]> granicus.if.org Git - icinga2/blob - lib/config/expression.cpp
Merge branch 'support/2.10'
[icinga2] / lib / config / expression.cpp
1 /* Icinga 2 | (c) 2012 Icinga GmbH | GPLv2+ */
2
3 #include "config/expression.hpp"
4 #include "config/configitem.hpp"
5 #include "config/configcompiler.hpp"
6 #include "config/vmops.hpp"
7 #include "base/array.hpp"
8 #include "base/json.hpp"
9 #include "base/object.hpp"
10 #include "base/logger.hpp"
11 #include "base/exception.hpp"
12 #include "base/scriptglobal.hpp"
13 #include "base/loader.hpp"
14 #include "base/reference.hpp"
15 #include "base/namespace.hpp"
16 #include <boost/exception_ptr.hpp>
17 #include <boost/exception/errinfo_nested_exception.hpp>
18
19 using namespace icinga;
20
21 boost::signals2::signal<void (ScriptFrame&, ScriptError *ex, const DebugInfo&)> Expression::OnBreakpoint;
22 boost::thread_specific_ptr<bool> l_InBreakpointHandler;
23
24 Expression::~Expression()
25 { }
26
27 void Expression::ScriptBreakpoint(ScriptFrame& frame, ScriptError *ex, const DebugInfo& di)
28 {
29         bool *inHandler = l_InBreakpointHandler.get();
30         if (!inHandler || !*inHandler) {
31                 inHandler = new bool(true);
32                 l_InBreakpointHandler.reset(inHandler);
33                 OnBreakpoint(frame, ex, di);
34                 *inHandler = false;
35         }
36 }
37
38 ExpressionResult Expression::Evaluate(ScriptFrame& frame, DebugHint *dhint) const
39 {
40         try {
41 #ifdef I2_DEBUG
42 /*              std::ostringstream msgbuf;
43                 ShowCodeLocation(msgbuf, GetDebugInfo(), false);
44                 Log(LogDebug, "Expression")
45                         << "Executing:\n" << msgbuf.str();*/
46 #endif /* I2_DEBUG */
47
48                 frame.IncreaseStackDepth();
49                 ExpressionResult result = DoEvaluate(frame, dhint);
50                 frame.DecreaseStackDepth();
51                 return result;
52         } catch (ScriptError& ex) {
53                 frame.DecreaseStackDepth();
54
55                 ScriptBreakpoint(frame, &ex, GetDebugInfo());
56                 throw;
57         } catch (const std::exception& ex) {
58                 frame.DecreaseStackDepth();
59
60                 BOOST_THROW_EXCEPTION(ScriptError("Error while evaluating expression: " + String(ex.what()), GetDebugInfo())
61                         << boost::errinfo_nested_exception(boost::current_exception()));
62         }
63
64         frame.DecreaseStackDepth();
65 }
66
67 bool Expression::GetReference(ScriptFrame& frame, bool init_dict, Value *parent, String *index, DebugHint **dhint) const
68 {
69         return false;
70 }
71
72 const DebugInfo& Expression::GetDebugInfo() const
73 {
74         static DebugInfo debugInfo;
75         return debugInfo;
76 }
77
78 std::unique_ptr<Expression> icinga::MakeIndexer(ScopeSpecifier scopeSpec, const String& index)
79 {
80         std::unique_ptr<Expression> scope{new GetScopeExpression(scopeSpec)};
81         return std::unique_ptr<Expression>(new IndexerExpression(std::move(scope), MakeLiteral(index)));
82 }
83
84 void DictExpression::MakeInline()
85 {
86         m_Inline = true;
87 }
88
89 LiteralExpression::LiteralExpression(Value value)
90         : m_Value(std::move(value))
91 { }
92
93 ExpressionResult LiteralExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const
94 {
95         return m_Value;
96 }
97
98 const DebugInfo& DebuggableExpression::GetDebugInfo() const
99 {
100         return m_DebugInfo;
101 }
102
103 VariableExpression::VariableExpression(String variable, std::vector<std::shared_ptr<Expression> > imports, const DebugInfo& debugInfo)
104         : DebuggableExpression(debugInfo), m_Variable(std::move(variable)), m_Imports(std::move(imports))
105 {
106         m_Imports.push_back(MakeIndexer(ScopeGlobal, "System"));
107         m_Imports.push_back(std::unique_ptr<Expression>(new IndexerExpression(MakeIndexer(ScopeGlobal, "System"), MakeLiteral("Configuration"))));
108         m_Imports.push_back(MakeIndexer(ScopeGlobal, "Types"));
109         m_Imports.push_back(MakeIndexer(ScopeGlobal, "Icinga"));
110 }
111
112 ExpressionResult VariableExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const
113 {
114         Value value;
115
116         if (frame.Locals && frame.Locals->Get(m_Variable, &value))
117                 return value;
118         else if (frame.Self.IsObject() && frame.Locals != frame.Self.Get<Object::Ptr>() && frame.Self.Get<Object::Ptr>()->GetOwnField(m_Variable, &value))
119                 return value;
120         else if (VMOps::FindVarImport(frame, m_Imports, m_Variable, &value, m_DebugInfo))
121                 return value;
122         else
123                 return ScriptGlobal::Get(m_Variable);
124 }
125
126 bool VariableExpression::GetReference(ScriptFrame& frame, bool init_dict, Value *parent, String *index, DebugHint **dhint) const
127 {
128         *index = m_Variable;
129
130         if (frame.Locals && frame.Locals->Contains(m_Variable)) {
131                 *parent = frame.Locals;
132
133                 if (dhint)
134                         *dhint = nullptr;
135         } else if (frame.Self.IsObject() && frame.Locals != frame.Self.Get<Object::Ptr>() && frame.Self.Get<Object::Ptr>()->HasOwnField(m_Variable)) {
136                 *parent = frame.Self;
137
138                 if (dhint && *dhint)
139                         *dhint = new DebugHint((*dhint)->GetChild(m_Variable));
140         } else if (VMOps::FindVarImportRef(frame, m_Imports, m_Variable, parent, m_DebugInfo)) {
141                 return true;
142         } else if (ScriptGlobal::Exists(m_Variable)) {
143                 *parent = ScriptGlobal::GetGlobals();
144
145                 if (dhint)
146                         *dhint = nullptr;
147         } else
148                 *parent = frame.Self;
149
150         return true;
151 }
152
153 ExpressionResult RefExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const
154 {
155         Value parent;
156         String index;
157
158         if (!m_Operand->GetReference(frame, false, &parent, &index, &dhint))
159                 BOOST_THROW_EXCEPTION(ScriptError("Cannot obtain reference for expression.", m_DebugInfo));
160
161         if (!parent.IsObject())
162                 BOOST_THROW_EXCEPTION(ScriptError("Cannot obtain reference for expression because parent is not an object.", m_DebugInfo));
163
164         return new Reference(parent, index);
165 }
166
167 ExpressionResult DerefExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const
168 {
169         ExpressionResult operand = m_Operand->Evaluate(frame);
170         CHECK_RESULT(operand);
171
172         Object::Ptr obj = operand.GetValue();
173         Reference::Ptr ref = dynamic_pointer_cast<Reference>(obj);
174
175         if (!ref)
176                 BOOST_THROW_EXCEPTION(ScriptError("Invalid reference specified.", GetDebugInfo()));
177
178         return ref->Get();
179 }
180
181 bool DerefExpression::GetReference(ScriptFrame& frame, bool init_dict, Value *parent, String *index, DebugHint **dhint) const
182 {
183         ExpressionResult operand = m_Operand->Evaluate(frame);
184         if (operand.GetCode() != ResultOK)
185                 return false;
186
187         Reference::Ptr ref = operand.GetValue();
188
189         *parent = ref->GetParent();
190         *index = ref->GetIndex();
191         return true;
192 }
193
194 ExpressionResult NegateExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const
195 {
196         ExpressionResult operand = m_Operand->Evaluate(frame);
197         CHECK_RESULT(operand);
198
199         return ~(long)operand.GetValue();
200 }
201
202 ExpressionResult LogicalNegateExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const
203 {
204         ExpressionResult operand = m_Operand->Evaluate(frame);
205         CHECK_RESULT(operand);
206
207         return !operand.GetValue().ToBool();
208 }
209
210 ExpressionResult AddExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const
211 {
212         ExpressionResult operand1 = m_Operand1->Evaluate(frame);
213         CHECK_RESULT(operand1);
214
215         ExpressionResult operand2 = m_Operand2->Evaluate(frame);
216         CHECK_RESULT(operand2);
217
218         return operand1.GetValue() + operand2.GetValue();
219 }
220
221 ExpressionResult SubtractExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const
222 {
223         ExpressionResult operand1 = m_Operand1->Evaluate(frame);
224         CHECK_RESULT(operand1);
225
226         ExpressionResult operand2 = m_Operand2->Evaluate(frame);
227         CHECK_RESULT(operand2);
228
229         return operand1.GetValue() - operand2.GetValue();
230 }
231
232 ExpressionResult MultiplyExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const
233 {
234         ExpressionResult operand1 = m_Operand1->Evaluate(frame);
235         CHECK_RESULT(operand1);
236
237         ExpressionResult operand2 = m_Operand2->Evaluate(frame);
238         CHECK_RESULT(operand2);
239
240         return operand1.GetValue() * operand2.GetValue();
241 }
242
243 ExpressionResult DivideExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const
244 {
245         ExpressionResult operand1 = m_Operand1->Evaluate(frame);
246         CHECK_RESULT(operand1);
247
248         ExpressionResult operand2 = m_Operand2->Evaluate(frame);
249         CHECK_RESULT(operand2);
250
251         return operand1.GetValue() / operand2.GetValue();
252 }
253
254 ExpressionResult ModuloExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const
255 {
256         ExpressionResult operand1 = m_Operand1->Evaluate(frame);
257         CHECK_RESULT(operand1);
258
259         ExpressionResult operand2 = m_Operand2->Evaluate(frame);
260         CHECK_RESULT(operand2);
261
262         return operand1.GetValue() % operand2.GetValue();
263 }
264
265 ExpressionResult XorExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const
266 {
267         ExpressionResult operand1 = m_Operand1->Evaluate(frame);
268         CHECK_RESULT(operand1);
269
270         ExpressionResult operand2 = m_Operand2->Evaluate(frame);
271         CHECK_RESULT(operand2);
272
273         return operand1.GetValue() ^ operand2.GetValue();
274 }
275
276 ExpressionResult BinaryAndExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const
277 {
278         ExpressionResult operand1 = m_Operand1->Evaluate(frame);
279         CHECK_RESULT(operand1);
280
281         ExpressionResult operand2 = m_Operand2->Evaluate(frame);
282         CHECK_RESULT(operand2);
283
284         return operand1.GetValue() & operand2.GetValue();
285 }
286
287 ExpressionResult BinaryOrExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const
288 {
289         ExpressionResult operand1 = m_Operand1->Evaluate(frame);
290         CHECK_RESULT(operand1);
291
292         ExpressionResult operand2 = m_Operand2->Evaluate(frame);
293         CHECK_RESULT(operand2);
294
295         return operand1.GetValue() | operand2.GetValue();
296 }
297
298 ExpressionResult ShiftLeftExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const
299 {
300         ExpressionResult operand1 = m_Operand1->Evaluate(frame);
301         CHECK_RESULT(operand1);
302
303         ExpressionResult operand2 = m_Operand2->Evaluate(frame);
304         CHECK_RESULT(operand2);
305
306         return operand1.GetValue() << operand2.GetValue();
307 }
308
309 ExpressionResult ShiftRightExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const
310 {
311         ExpressionResult operand1 = m_Operand1->Evaluate(frame);
312         CHECK_RESULT(operand1);
313
314         ExpressionResult operand2 = m_Operand2->Evaluate(frame);
315         CHECK_RESULT(operand2);
316
317         return operand1.GetValue() >> operand2.GetValue();
318 }
319
320 ExpressionResult EqualExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const
321 {
322         ExpressionResult operand1 = m_Operand1->Evaluate(frame);
323         CHECK_RESULT(operand1);
324
325         ExpressionResult operand2 = m_Operand2->Evaluate(frame);
326         CHECK_RESULT(operand2);
327
328         return operand1.GetValue() == operand2.GetValue();
329 }
330
331 ExpressionResult NotEqualExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const
332 {
333         ExpressionResult operand1 = m_Operand1->Evaluate(frame);
334         CHECK_RESULT(operand1);
335
336         ExpressionResult operand2 = m_Operand2->Evaluate(frame);
337         CHECK_RESULT(operand2);
338
339         return operand1.GetValue() != operand2.GetValue();
340 }
341
342 ExpressionResult LessThanExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const
343 {
344         ExpressionResult operand1 = m_Operand1->Evaluate(frame);
345         CHECK_RESULT(operand1);
346
347         ExpressionResult operand2 = m_Operand2->Evaluate(frame);
348         CHECK_RESULT(operand2);
349
350         return operand1.GetValue() < operand2.GetValue();
351 }
352
353 ExpressionResult GreaterThanExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const
354 {
355         ExpressionResult operand1 = m_Operand1->Evaluate(frame);
356         CHECK_RESULT(operand1);
357
358         ExpressionResult operand2 = m_Operand2->Evaluate(frame);
359         CHECK_RESULT(operand2);
360
361         return operand1.GetValue() > operand2.GetValue();
362 }
363
364 ExpressionResult LessThanOrEqualExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const
365 {
366         ExpressionResult operand1 = m_Operand1->Evaluate(frame);
367         CHECK_RESULT(operand1);
368
369         ExpressionResult operand2 = m_Operand2->Evaluate(frame);
370         CHECK_RESULT(operand2);
371
372         return operand1.GetValue() <= operand2.GetValue();
373 }
374
375 ExpressionResult GreaterThanOrEqualExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const
376 {
377         ExpressionResult operand1 = m_Operand1->Evaluate(frame);
378         CHECK_RESULT(operand1);
379
380         ExpressionResult operand2 = m_Operand2->Evaluate(frame);
381         CHECK_RESULT(operand2);
382
383         return operand1.GetValue() >= operand2.GetValue();
384 }
385
386 ExpressionResult InExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const
387 {
388         ExpressionResult operand2 = m_Operand2->Evaluate(frame);
389         CHECK_RESULT(operand2);
390
391         if (operand2.GetValue().IsEmpty())
392                 return false;
393         else if (!operand2.GetValue().IsObjectType<Array>())
394                 BOOST_THROW_EXCEPTION(ScriptError("Invalid right side argument for 'in' operator: " + JsonEncode(operand2.GetValue()), m_DebugInfo));
395
396         ExpressionResult operand1 = m_Operand1->Evaluate(frame);
397         CHECK_RESULT(operand1)
398
399         Array::Ptr arr = operand2.GetValue();
400         return arr->Contains(operand1.GetValue());
401 }
402
403 ExpressionResult NotInExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const
404 {
405         ExpressionResult operand2 = m_Operand2->Evaluate(frame);
406         CHECK_RESULT(operand2);
407
408         if (operand2.GetValue().IsEmpty())
409                 return true;
410         else if (!operand2.GetValue().IsObjectType<Array>())
411                 BOOST_THROW_EXCEPTION(ScriptError("Invalid right side argument for 'in' operator: " + JsonEncode(operand2.GetValue()), m_DebugInfo));
412
413         ExpressionResult operand1 = m_Operand1->Evaluate(frame);
414         CHECK_RESULT(operand1);
415
416         Array::Ptr arr = operand2.GetValue();
417         return !arr->Contains(operand1.GetValue());
418 }
419
420 ExpressionResult LogicalAndExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const
421 {
422         ExpressionResult operand1 = m_Operand1->Evaluate(frame);
423         CHECK_RESULT(operand1);
424
425         if (!operand1.GetValue().ToBool())
426                 return operand1;
427         else {
428                 ExpressionResult operand2 = m_Operand2->Evaluate(frame);
429                 CHECK_RESULT(operand2);
430
431                 return operand2.GetValue();
432         }
433 }
434
435 ExpressionResult LogicalOrExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const
436 {
437         ExpressionResult operand1 = m_Operand1->Evaluate(frame);
438         CHECK_RESULT(operand1);
439
440         if (operand1.GetValue().ToBool())
441                 return operand1;
442         else {
443                 ExpressionResult operand2 = m_Operand2->Evaluate(frame);
444                 CHECK_RESULT(operand2);
445
446                 return operand2.GetValue();
447         }
448 }
449
450 ExpressionResult FunctionCallExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const
451 {
452         Value self, vfunc;
453         String index;
454
455         if (m_FName->GetReference(frame, false, &self, &index))
456                 vfunc = VMOps::GetField(self, index, frame.Sandboxed, m_DebugInfo);
457         else {
458                 ExpressionResult vfuncres = m_FName->Evaluate(frame);
459                 CHECK_RESULT(vfuncres);
460
461                 vfunc = vfuncres.GetValue();
462         }
463
464         if (vfunc.IsObjectType<Type>()) {
465                 std::vector<Value> arguments;
466                 arguments.reserve(m_Args.size());
467                 for (const auto& arg : m_Args) {
468                         ExpressionResult argres = arg->Evaluate(frame);
469                         CHECK_RESULT(argres);
470
471                         arguments.push_back(argres.GetValue());
472                 }
473
474                 return VMOps::ConstructorCall(vfunc, arguments, m_DebugInfo);
475         }
476
477         if (!vfunc.IsObjectType<Function>())
478                 BOOST_THROW_EXCEPTION(ScriptError("Argument is not a callable object.", m_DebugInfo));
479
480         Function::Ptr func = vfunc;
481
482         if (!func->IsSideEffectFree() && frame.Sandboxed)
483                 BOOST_THROW_EXCEPTION(ScriptError("Function is not marked as safe for sandbox mode.", m_DebugInfo));
484
485         std::vector<Value> arguments;
486         arguments.reserve(m_Args.size());
487         for (const auto& arg : m_Args) {
488                 ExpressionResult argres = arg->Evaluate(frame);
489                 CHECK_RESULT(argres);
490
491                 arguments.push_back(argres.GetValue());
492         }
493
494         return VMOps::FunctionCall(frame, self, func, arguments);
495 }
496
497 ExpressionResult ArrayExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const
498 {
499         ArrayData result;
500         result.reserve(m_Expressions.size());
501
502         for (const auto& aexpr : m_Expressions) {
503                 ExpressionResult element = aexpr->Evaluate(frame);
504                 CHECK_RESULT(element);
505
506                 result.push_back(element.GetValue());
507         }
508
509         return new Array(std::move(result));
510 }
511
512 ExpressionResult DictExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const
513 {
514         Value self;
515
516         if (!m_Inline) {
517                 self = frame.Self;
518                 frame.Self = new Dictionary();
519         }
520
521         Value result;
522
523         try {
524                 for (const auto& aexpr : m_Expressions) {
525                         ExpressionResult element = aexpr->Evaluate(frame, m_Inline ? dhint : nullptr);
526                         CHECK_RESULT(element);
527                         result = element.GetValue();
528                 }
529         } catch (...) {
530                 if (!m_Inline)
531                         std::swap(self, frame.Self);
532                 throw;
533         }
534
535         if (m_Inline)
536                 return result;
537         else {
538                 std::swap(self, frame.Self);
539                 return self;
540         }
541 }
542
543 ExpressionResult GetScopeExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const
544 {
545         if (m_ScopeSpec == ScopeLocal)
546                 return frame.Locals;
547         else if (m_ScopeSpec == ScopeThis)
548                 return frame.Self;
549         else if (m_ScopeSpec == ScopeGlobal)
550                 return ScriptGlobal::GetGlobals();
551         else
552                 VERIFY(!"Invalid scope.");
553 }
554
555 ExpressionResult SetExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const
556 {
557         if (frame.Sandboxed)
558                 BOOST_THROW_EXCEPTION(ScriptError("Assignments are not allowed in sandbox mode.", m_DebugInfo));
559
560         DebugHint *psdhint = dhint;
561
562         Value parent;
563         String index;
564
565         if (!m_Operand1->GetReference(frame, true, &parent, &index, &psdhint))
566                 BOOST_THROW_EXCEPTION(ScriptError("Expression cannot be assigned to.", m_DebugInfo));
567
568         ExpressionResult operand2 = m_Operand2->Evaluate(frame, dhint);
569         CHECK_RESULT(operand2);
570
571         if (m_Op != OpSetLiteral) {
572                 Value object = VMOps::GetField(parent, index, frame.Sandboxed, m_DebugInfo);
573
574                 switch (m_Op) {
575                         case OpSetAdd:
576                                 operand2 = object + operand2;
577                                 break;
578                         case OpSetSubtract:
579                                 operand2 = object - operand2;
580                                 break;
581                         case OpSetMultiply:
582                                 operand2 = object * operand2;
583                                 break;
584                         case OpSetDivide:
585                                 operand2 = object / operand2;
586                                 break;
587                         case OpSetModulo:
588                                 operand2 = object % operand2;
589                                 break;
590                         case OpSetXor:
591                                 operand2 = object ^ operand2;
592                                 break;
593                         case OpSetBinaryAnd:
594                                 operand2 = object & operand2;
595                                 break;
596                         case OpSetBinaryOr:
597                                 operand2 = object | operand2;
598                                 break;
599                         default:
600                                 VERIFY(!"Invalid opcode.");
601                 }
602         }
603
604         VMOps::SetField(parent, index, operand2.GetValue(), m_OverrideFrozen, m_DebugInfo);
605
606         if (psdhint) {
607                 psdhint->AddMessage("=", m_DebugInfo);
608
609                 if (psdhint != dhint)
610                         delete psdhint;
611         }
612
613         return Empty;
614 }
615
616 void SetExpression::SetOverrideFrozen()
617 {
618         m_OverrideFrozen = true;
619 }
620
621 ExpressionResult SetConstExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const
622 {
623         auto globals = ScriptGlobal::GetGlobals();
624
625         auto attr = globals->GetAttribute(m_Name);
626
627         if (dynamic_pointer_cast<ConstEmbeddedNamespaceValue>(attr)) {
628                 std::ostringstream msgbuf;
629                 msgbuf << "Value for constant '" << m_Name << "' was modified. This behaviour is deprecated.\n";
630                 ShowCodeLocation(msgbuf, GetDebugInfo(), false);
631                 Log(LogWarning, msgbuf.str());
632         }
633
634         ExpressionResult operandres = m_Operand->Evaluate(frame);
635         CHECK_RESULT(operandres);
636         Value operand = operandres.GetValue();
637
638         globals->SetAttribute(m_Name, std::make_shared<ConstEmbeddedNamespaceValue>(operand));
639
640         return Empty;
641 }
642
643 ExpressionResult ConditionalExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const
644 {
645         ExpressionResult condition = m_Condition->Evaluate(frame, dhint);
646         CHECK_RESULT(condition);
647
648         if (condition.GetValue().ToBool())
649                 return m_TrueBranch->Evaluate(frame, dhint);
650         else if (m_FalseBranch)
651                 return m_FalseBranch->Evaluate(frame, dhint);
652
653         return Empty;
654 }
655
656 ExpressionResult WhileExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const
657 {
658         if (frame.Sandboxed)
659                 BOOST_THROW_EXCEPTION(ScriptError("While loops are not allowed in sandbox mode.", m_DebugInfo));
660
661         for (;;) {
662                 ExpressionResult condition = m_Condition->Evaluate(frame, dhint);
663                 CHECK_RESULT(condition);
664
665                 if (!condition.GetValue().ToBool())
666                         break;
667
668                 ExpressionResult loop_body = m_LoopBody->Evaluate(frame, dhint);
669                 CHECK_RESULT_LOOP(loop_body);
670         }
671
672         return Empty;
673 }
674
675 ExpressionResult ReturnExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const
676 {
677         ExpressionResult operand = m_Operand->Evaluate(frame);
678         CHECK_RESULT(operand);
679
680         return ExpressionResult(operand.GetValue(), ResultReturn);
681 }
682
683 ExpressionResult BreakExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const
684 {
685         return ExpressionResult(Empty, ResultBreak);
686 }
687
688 ExpressionResult ContinueExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const
689 {
690         return ExpressionResult(Empty, ResultContinue);
691 }
692
693 ExpressionResult IndexerExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const
694 {
695         ExpressionResult operand1 = m_Operand1->Evaluate(frame, dhint);
696         CHECK_RESULT(operand1);
697
698         ExpressionResult operand2 = m_Operand2->Evaluate(frame, dhint);
699         CHECK_RESULT(operand2);
700
701         return VMOps::GetField(operand1.GetValue(), operand2.GetValue(), frame.Sandboxed, m_DebugInfo);
702 }
703
704 bool IndexerExpression::GetReference(ScriptFrame& frame, bool init_dict, Value *parent, String *index, DebugHint **dhint) const
705 {
706         Value vparent;
707         String vindex;
708         DebugHint *psdhint = nullptr;
709         bool free_psd = false;
710
711         if (dhint)
712                 psdhint = *dhint;
713
714         if (frame.Sandboxed)
715                 init_dict = false;
716
717         if (m_Operand1->GetReference(frame, init_dict, &vparent, &vindex, &psdhint)) {
718                 if (init_dict) {
719                         Value old_value;
720                         bool has_field = true;
721
722                         if (vparent.IsObject()) {
723                                 Object::Ptr oparent = vparent;
724                                 has_field = oparent->HasOwnField(vindex);
725                         }
726
727                         if (has_field)
728                                 old_value = VMOps::GetField(vparent, vindex, frame.Sandboxed, m_Operand1->GetDebugInfo());
729
730                         if (old_value.IsEmpty() && !old_value.IsString())
731                                 VMOps::SetField(vparent, vindex, new Dictionary(), m_OverrideFrozen, m_Operand1->GetDebugInfo());
732                 }
733
734                 *parent = VMOps::GetField(vparent, vindex, frame.Sandboxed, m_DebugInfo);
735                 free_psd = true;
736         } else {
737                 ExpressionResult operand1 = m_Operand1->Evaluate(frame);
738                 *parent = operand1.GetValue();
739         }
740
741         ExpressionResult operand2 = m_Operand2->Evaluate(frame);
742         *index = operand2.GetValue();
743
744         if (dhint) {
745                 if (psdhint)
746                         *dhint = new DebugHint(psdhint->GetChild(*index));
747                 else
748                         *dhint = nullptr;
749         }
750
751         if (free_psd)
752                 delete psdhint;
753
754         return true;
755 }
756
757 void IndexerExpression::SetOverrideFrozen()
758 {
759         m_OverrideFrozen = true;
760 }
761
762 void icinga::BindToScope(std::unique_ptr<Expression>& expr, ScopeSpecifier scopeSpec)
763 {
764         auto *dexpr = dynamic_cast<DictExpression *>(expr.get());
765
766         if (dexpr) {
767                 for (auto& expr : dexpr->m_Expressions)
768                         BindToScope(expr, scopeSpec);
769
770                 return;
771         }
772
773         auto *aexpr = dynamic_cast<SetExpression *>(expr.get());
774
775         if (aexpr) {
776                 BindToScope(aexpr->m_Operand1, scopeSpec);
777
778                 return;
779         }
780
781         auto *iexpr = dynamic_cast<IndexerExpression *>(expr.get());
782
783         if (iexpr) {
784                 BindToScope(iexpr->m_Operand1, scopeSpec);
785                 return;
786         }
787
788         auto *lexpr = dynamic_cast<LiteralExpression *>(expr.get());
789
790         if (lexpr && lexpr->GetValue().IsString()) {
791                 std::unique_ptr<Expression> scope{new GetScopeExpression(scopeSpec)};
792                 expr.reset(new IndexerExpression(std::move(scope), std::move(expr), lexpr->GetDebugInfo()));
793         }
794
795         auto *vexpr = dynamic_cast<VariableExpression *>(expr.get());
796
797         if (vexpr) {
798                 std::unique_ptr<Expression> scope{new GetScopeExpression(scopeSpec)};
799                 expr.reset(new IndexerExpression(std::move(scope), MakeLiteral(vexpr->GetVariable()), vexpr->GetDebugInfo()));
800         }
801 }
802
803 ExpressionResult ThrowExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const
804 {
805         ExpressionResult messageres = m_Message->Evaluate(frame);
806         CHECK_RESULT(messageres);
807         Value message = messageres.GetValue();
808         BOOST_THROW_EXCEPTION(ScriptError(message, m_DebugInfo, m_IncompleteExpr));
809 }
810
811 ExpressionResult ImportExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const
812 {
813         if (frame.Sandboxed)
814                 BOOST_THROW_EXCEPTION(ScriptError("Imports are not allowed in sandbox mode.", m_DebugInfo));
815
816         String type = VMOps::GetField(frame.Self, "type", frame.Sandboxed, m_DebugInfo);
817         ExpressionResult nameres = m_Name->Evaluate(frame);
818         CHECK_RESULT(nameres);
819         Value name = nameres.GetValue();
820
821         if (!name.IsString())
822                 BOOST_THROW_EXCEPTION(ScriptError("Template/object name must be a string", m_DebugInfo));
823
824         ConfigItem::Ptr item = ConfigItem::GetByTypeAndName(Type::GetByName(type), name);
825
826         if (!item)
827                 BOOST_THROW_EXCEPTION(ScriptError("Import references unknown template: '" + name + "'", m_DebugInfo));
828
829         Dictionary::Ptr scope = item->GetScope();
830
831         if (scope)
832                 scope->CopyTo(frame.Locals);
833
834         ExpressionResult result = item->GetExpression()->Evaluate(frame, dhint);
835         CHECK_RESULT(result);
836
837         return Empty;
838 }
839
840 ExpressionResult ImportDefaultTemplatesExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const
841 {
842         if (frame.Sandboxed)
843                 BOOST_THROW_EXCEPTION(ScriptError("Imports are not allowed in sandbox mode.", m_DebugInfo));
844
845         String type = VMOps::GetField(frame.Self, "type", frame.Sandboxed, m_DebugInfo);
846         Type::Ptr ptype = Type::GetByName(type);
847
848         for (const ConfigItem::Ptr& item : ConfigItem::GetDefaultTemplates(ptype)) {
849                 Dictionary::Ptr scope = item->GetScope();
850
851                 if (scope)
852                         scope->CopyTo(frame.Locals);
853
854                 ExpressionResult result = item->GetExpression()->Evaluate(frame, dhint);
855                 CHECK_RESULT(result);
856         }
857
858         return Empty;
859 }
860
861 ExpressionResult FunctionExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const
862 {
863         return VMOps::NewFunction(frame, m_Name, m_Args, m_ClosedVars, m_Expression);
864 }
865
866 ExpressionResult ApplyExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const
867 {
868         if (frame.Sandboxed)
869                 BOOST_THROW_EXCEPTION(ScriptError("Apply rules are not allowed in sandbox mode.", m_DebugInfo));
870
871         ExpressionResult nameres = m_Name->Evaluate(frame);
872         CHECK_RESULT(nameres);
873
874         return VMOps::NewApply(frame, m_Type, m_Target, nameres.GetValue(), m_Filter,
875                 m_Package, m_FKVar, m_FVVar, m_FTerm, m_ClosedVars, m_IgnoreOnError, m_Expression, m_DebugInfo);
876 }
877
878 ExpressionResult NamespaceExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const
879 {
880         Namespace::Ptr ns = new Namespace(new ConstNamespaceBehavior());
881
882         ScriptFrame innerFrame(true, ns);
883         ExpressionResult result = m_Expression->Evaluate(innerFrame);
884         CHECK_RESULT(result);
885
886         return ns;
887 }
888
889 ExpressionResult ObjectExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const
890 {
891         if (frame.Sandboxed)
892                 BOOST_THROW_EXCEPTION(ScriptError("Object definitions are not allowed in sandbox mode.", m_DebugInfo));
893
894         ExpressionResult typeres = m_Type->Evaluate(frame, dhint);
895         CHECK_RESULT(typeres);
896         Type::Ptr type = typeres.GetValue();
897
898         String name;
899
900         if (m_Name) {
901                 ExpressionResult nameres = m_Name->Evaluate(frame, dhint);
902                 CHECK_RESULT(nameres);
903
904                 name = nameres.GetValue();
905         }
906
907         return VMOps::NewObject(frame, m_Abstract, type, name, m_Filter, m_Zone,
908                 m_Package, m_DefaultTmpl, m_IgnoreOnError, m_ClosedVars, m_Expression, m_DebugInfo);
909 }
910
911 ExpressionResult ForExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const
912 {
913         if (frame.Sandboxed)
914                 BOOST_THROW_EXCEPTION(ScriptError("For loops are not allowed in sandbox mode.", m_DebugInfo));
915
916         ExpressionResult valueres = m_Value->Evaluate(frame, dhint);
917         CHECK_RESULT(valueres);
918
919         return VMOps::For(frame, m_FKVar, m_FVVar, valueres.GetValue(), m_Expression, m_DebugInfo);
920 }
921
922 ExpressionResult LibraryExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const
923 {
924         if (frame.Sandboxed)
925                 BOOST_THROW_EXCEPTION(ScriptError("Loading libraries is not allowed in sandbox mode.", m_DebugInfo));
926
927         ExpressionResult libres = m_Operand->Evaluate(frame, dhint);
928         CHECK_RESULT(libres);
929
930         Log(LogNotice, "config")
931                 << "Ignoring explicit load request for library \"" << libres << "\".";
932
933         return Empty;
934 }
935
936 ExpressionResult IncludeExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const
937 {
938         if (frame.Sandboxed)
939                 BOOST_THROW_EXCEPTION(ScriptError("Includes are not allowed in sandbox mode.", m_DebugInfo));
940
941         std::unique_ptr<Expression> expr;
942         String name, path, pattern;
943
944         switch (m_Type) {
945                 case IncludeRegular:
946                         {
947                                 ExpressionResult pathres = m_Path->Evaluate(frame, dhint);
948                                 CHECK_RESULT(pathres);
949                                 path = pathres.GetValue();
950                         }
951
952                         expr = ConfigCompiler::HandleInclude(m_RelativeBase, path, m_SearchIncludes, m_Zone, m_Package, m_DebugInfo);
953                         break;
954
955                 case IncludeRecursive:
956                         {
957                                 ExpressionResult pathres = m_Path->Evaluate(frame, dhint);
958                                 CHECK_RESULT(pathres);
959                                 path = pathres.GetValue();
960                         }
961
962                         {
963                                 ExpressionResult patternres = m_Pattern->Evaluate(frame, dhint);
964                                 CHECK_RESULT(patternres);
965                                 pattern = patternres.GetValue();
966                         }
967
968                         expr = ConfigCompiler::HandleIncludeRecursive(m_RelativeBase, path, pattern, m_Zone, m_Package, m_DebugInfo);
969                         break;
970
971                 case IncludeZones:
972                         {
973                                 ExpressionResult nameres = m_Name->Evaluate(frame, dhint);
974                                 CHECK_RESULT(nameres);
975                                 name = nameres.GetValue();
976                         }
977
978                         {
979                                 ExpressionResult pathres = m_Path->Evaluate(frame, dhint);
980                                 CHECK_RESULT(pathres);
981                                 path = pathres.GetValue();
982                         }
983
984                         {
985                                 ExpressionResult patternres = m_Pattern->Evaluate(frame, dhint);
986                                 CHECK_RESULT(patternres);
987                                 pattern = patternres.GetValue();
988                         }
989
990                         expr = ConfigCompiler::HandleIncludeZones(m_RelativeBase, name, path, pattern, m_Package, m_DebugInfo);
991                         break;
992         }
993
994         ExpressionResult res(Empty);
995
996         try {
997                 res = expr->Evaluate(frame, dhint);
998         } catch (const std::exception&) {
999                 throw;
1000         }
1001
1002         return res;
1003 }
1004
1005 ExpressionResult BreakpointExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const
1006 {
1007         ScriptBreakpoint(frame, nullptr, GetDebugInfo());
1008
1009         return Empty;
1010 }
1011
1012 ExpressionResult TryExceptExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const
1013 {
1014         try {
1015                 ExpressionResult tryResult = m_TryBody->Evaluate(frame, dhint);
1016                 CHECK_RESULT(tryResult);
1017         } catch (const std::exception&) {
1018                 ExpressionResult exceptResult = m_ExceptBody->Evaluate(frame, dhint);
1019                 CHECK_RESULT(exceptResult);
1020         }
1021
1022         return Empty;
1023 }
1024