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