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