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