]> granicus.if.org Git - icinga2/blob - lib/config/expression.cpp
Merge branch 'support/2.5'
[icinga2] / lib / config / expression.cpp
1 /******************************************************************************
2  * Icinga 2                                                                   *
3  * Copyright (C) 2012-2016 Icinga Development Team (https://www.icinga.org/)  *
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 Expression *icinga::MakeIndexer(ScopeSpecifier scopeSpec, const String& index)
94 {
95         Expression *scope = new GetScopeExpression(scopeSpec);
96         return new IndexerExpression(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 != static_cast<Object::Ptr>(frame.Self) && static_cast<Object::Ptr>(frame.Self)->HasOwnField(m_Variable))
125                 return VMOps::GetField(frame.Self, m_Variable, frame.Sandboxed, m_DebugInfo);
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 = NULL;
141         } else if (frame.Self.IsObject() && frame.Locals != static_cast<Object::Ptr>(frame.Self) && static_cast<Object::Ptr>(frame.Self)->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 = NULL;
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                 for (Expression *arg : m_Args) {
432                         ExpressionResult argres = arg->Evaluate(frame);
433                         CHECK_RESULT(argres);
434
435                         arguments.push_back(argres.GetValue());
436                 }
437
438                 return VMOps::ConstructorCall(vfunc, arguments, m_DebugInfo);
439         }
440
441         if (!vfunc.IsObjectType<Function>())
442                 BOOST_THROW_EXCEPTION(ScriptError("Argument is not a callable object.", m_DebugInfo));
443
444         Function::Ptr func = vfunc;
445
446         if (!func->IsSideEffectFree() && frame.Sandboxed)
447                 BOOST_THROW_EXCEPTION(ScriptError("Function is not marked as safe for sandbox mode.", m_DebugInfo));
448
449         std::vector<Value> arguments;
450         for (Expression *arg : m_Args) {
451                 ExpressionResult argres = arg->Evaluate(frame);
452                 CHECK_RESULT(argres);
453
454                 arguments.push_back(argres.GetValue());
455         }
456
457         return VMOps::FunctionCall(frame, self, func, arguments);
458 }
459
460 ExpressionResult ArrayExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const
461 {
462         Array::Ptr result = new Array();
463         result->Reserve(m_Expressions.size());
464
465         for (Expression *aexpr : m_Expressions) {
466                 ExpressionResult element = aexpr->Evaluate(frame);
467                 CHECK_RESULT(element);
468
469                 result->Add(element.GetValue());
470         }
471
472         return result;
473 }
474
475 ExpressionResult DictExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const
476 {
477         Value self;
478
479         if (!m_Inline) {
480                 self = frame.Self;
481                 frame.Self = new Dictionary();
482         }
483
484         Value result;
485
486         try {
487                 for (Expression *aexpr : m_Expressions) {
488                         ExpressionResult element = aexpr->Evaluate(frame, m_Inline ? dhint : NULL);
489                         CHECK_RESULT(element);
490                         result = element.GetValue();
491                 }
492         } catch (...) {
493                 if (!m_Inline)
494                         std::swap(self, frame.Self);
495                 throw;
496         }
497
498         if (m_Inline)
499                 return result;
500         else {
501                 std::swap(self, frame.Self);
502                 return self;
503         }
504 }
505
506 ExpressionResult GetScopeExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const
507 {
508         if (m_ScopeSpec == ScopeLocal)
509                 return frame.Locals;
510         else if (m_ScopeSpec == ScopeThis)
511                 return frame.Self;
512         else if (m_ScopeSpec == ScopeGlobal)
513                 return ScriptGlobal::GetGlobals();
514         else
515                 VERIFY(!"Invalid scope.");
516 }
517
518 ExpressionResult SetExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const
519 {
520         if (frame.Sandboxed)
521                 BOOST_THROW_EXCEPTION(ScriptError("Assignments are not allowed in sandbox mode.", m_DebugInfo));
522
523         DebugHint *psdhint = dhint;
524
525         Value parent;
526         String index;
527
528         if (!m_Operand1->GetReference(frame, true, &parent, &index, &psdhint))
529                 BOOST_THROW_EXCEPTION(ScriptError("Expression cannot be assigned to.", m_DebugInfo));
530
531         ExpressionResult operand2 = m_Operand2->Evaluate(frame, dhint);
532         CHECK_RESULT(operand2);
533
534         if (m_Op != OpSetLiteral) {
535                 Value object = VMOps::GetField(parent, index, frame.Sandboxed, m_DebugInfo);
536
537                 switch (m_Op) {
538                         case OpSetAdd:
539                                 operand2 = object + operand2;
540                                 break;
541                         case OpSetSubtract:
542                                 operand2 = object - operand2;
543                                 break;
544                         case OpSetMultiply:
545                                 operand2 = object * operand2;
546                                 break;
547                         case OpSetDivide:
548                                 operand2 = object / operand2;
549                                 break;
550                         case OpSetModulo:
551                                 operand2 = object % operand2;
552                                 break;
553                         case OpSetXor:
554                                 operand2 = object ^ operand2;
555                                 break;
556                         case OpSetBinaryAnd:
557                                 operand2 = object & operand2;
558                                 break;
559                         case OpSetBinaryOr:
560                                 operand2 = object | operand2;
561                                 break;
562                         default:
563                                 VERIFY(!"Invalid opcode.");
564                 }
565         }
566
567         VMOps::SetField(parent, index, operand2.GetValue(), m_DebugInfo);
568
569         if (psdhint) {
570                 psdhint->AddMessage("=", m_DebugInfo);
571
572                 if (psdhint != dhint)
573                         delete psdhint;
574         }
575
576         return Empty;
577 }
578
579 ExpressionResult ConditionalExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const
580 {
581         ExpressionResult condition = m_Condition->Evaluate(frame, dhint);
582         CHECK_RESULT(condition);
583
584         if (condition.GetValue().ToBool())
585                 return m_TrueBranch->Evaluate(frame, dhint);
586         else if (m_FalseBranch)
587                 return m_FalseBranch->Evaluate(frame, dhint);
588
589         return Empty;
590 }
591
592 ExpressionResult WhileExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const
593 {
594         if (frame.Sandboxed)
595                 BOOST_THROW_EXCEPTION(ScriptError("While loops are not allowed in sandbox mode.", m_DebugInfo));
596
597         for (;;) {
598                 ExpressionResult condition = m_Condition->Evaluate(frame, dhint);
599                 CHECK_RESULT(condition);
600
601                 if (!condition.GetValue().ToBool())
602                         break;
603
604                 ExpressionResult loop_body = m_LoopBody->Evaluate(frame, dhint);
605                 CHECK_RESULT_LOOP(loop_body);
606         }
607
608         return Empty;
609 }
610
611 ExpressionResult ReturnExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const
612 {
613         ExpressionResult operand = m_Operand->Evaluate(frame);
614         CHECK_RESULT(operand);
615
616         return ExpressionResult(operand.GetValue(), ResultReturn);
617 }
618
619 ExpressionResult BreakExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const
620 {
621         return ExpressionResult(Empty, ResultBreak);
622 }
623
624 ExpressionResult ContinueExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const
625 {
626         return ExpressionResult(Empty, ResultContinue);
627 }
628
629 ExpressionResult IndexerExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const
630 {
631         ExpressionResult operand1 = m_Operand1->Evaluate(frame, dhint);
632         CHECK_RESULT(operand1);
633
634         ExpressionResult operand2 = m_Operand2->Evaluate(frame, dhint);
635         CHECK_RESULT(operand2);
636
637         return VMOps::GetField(operand1.GetValue(), operand2.GetValue(), frame.Sandboxed, m_DebugInfo);
638 }
639
640 bool IndexerExpression::GetReference(ScriptFrame& frame, bool init_dict, Value *parent, String *index, DebugHint **dhint) const
641 {
642         Value vparent;
643         String vindex;
644         DebugHint *psdhint = NULL;
645         bool free_psd = false;
646
647         if (dhint)
648                 psdhint = *dhint;
649
650         if (frame.Sandboxed)
651                 init_dict = false;
652
653         if (m_Operand1->GetReference(frame, init_dict, &vparent, &vindex, &psdhint)) {
654                 if (init_dict) {
655                         Value old_value =  VMOps::GetField(vparent, vindex, frame.Sandboxed, m_Operand1->GetDebugInfo());
656
657                         if (old_value.IsEmpty() && !old_value.IsString())
658                                 VMOps::SetField(vparent, vindex, new Dictionary(), m_Operand1->GetDebugInfo());
659                 }
660
661                 *parent = VMOps::GetField(vparent, vindex, frame.Sandboxed, m_DebugInfo);
662                 free_psd = true;
663         } else {
664                 ExpressionResult operand1 = m_Operand1->Evaluate(frame);
665                 *parent = operand1.GetValue();
666         }
667
668         ExpressionResult operand2 = m_Operand2->Evaluate(frame);
669         *index = operand2.GetValue();
670
671         if (dhint) {
672                 if (psdhint)
673                         *dhint = new DebugHint(psdhint->GetChild(*index));
674                 else
675                         *dhint = NULL;
676         }
677
678         if (free_psd)
679                 delete psdhint;
680
681         return true;
682 }
683
684 void icinga::BindToScope(Expression *& expr, ScopeSpecifier scopeSpec)
685 {
686         DictExpression *dexpr = dynamic_cast<DictExpression *>(expr);
687
688         if (dexpr) {
689                 for (Expression *& expr : dexpr->m_Expressions)
690                         BindToScope(expr, scopeSpec);
691
692                 return;
693         }
694
695         SetExpression *aexpr = dynamic_cast<SetExpression *>(expr);
696
697         if (aexpr) {
698                 BindToScope(aexpr->m_Operand1, scopeSpec);
699
700                 return;
701         }
702
703         IndexerExpression *iexpr = dynamic_cast<IndexerExpression *>(expr);
704
705         if (iexpr) {
706                 BindToScope(iexpr->m_Operand1, scopeSpec);
707                 return;
708         }
709
710         LiteralExpression *lexpr = dynamic_cast<LiteralExpression *>(expr);
711
712         if (lexpr && lexpr->GetValue().IsString()) {
713                 Expression *scope = new GetScopeExpression(scopeSpec);
714                 expr = new IndexerExpression(scope, lexpr, lexpr->GetDebugInfo());
715         }
716
717         VariableExpression *vexpr = dynamic_cast<VariableExpression *>(expr);
718
719         if (vexpr) {
720                 Expression *scope = new GetScopeExpression(scopeSpec);
721                 Expression *new_expr = new IndexerExpression(scope, MakeLiteral(vexpr->GetVariable()), vexpr->GetDebugInfo());
722                 delete expr;
723                 expr = new_expr;
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, 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
771         for (const ConfigItem::Ptr& item : ConfigItem::GetDefaultTemplates(type)) {
772                 Dictionary::Ptr scope = item->GetScope();
773
774                 if (scope)
775                         scope->CopyTo(frame.Locals);
776
777                 ExpressionResult result = item->GetExpression()->Evaluate(frame, dhint);
778                 CHECK_RESULT(result);
779         }
780
781         return Empty;
782 }
783
784 ExpressionResult FunctionExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const
785 {
786         return VMOps::NewFunction(frame, m_Name, m_Args, m_ClosedVars, m_Expression);
787 }
788
789 ExpressionResult ApplyExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const
790 {
791         if (frame.Sandboxed)
792                 BOOST_THROW_EXCEPTION(ScriptError("Apply rules are not allowed in sandbox mode.", m_DebugInfo));
793
794         ExpressionResult nameres = m_Name->Evaluate(frame);
795         CHECK_RESULT(nameres);
796
797         return VMOps::NewApply(frame, m_Type, m_Target, nameres.GetValue(), m_Filter,
798             m_Package, m_FKVar, m_FVVar, m_FTerm, m_ClosedVars, m_IgnoreOnError, m_Expression, m_DebugInfo);
799 }
800
801 ExpressionResult ObjectExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const
802 {
803         if (frame.Sandboxed)
804                 BOOST_THROW_EXCEPTION(ScriptError("Object definitions are not allowed in sandbox mode.", m_DebugInfo));
805
806         String name;
807
808         if (m_Name) {
809                 ExpressionResult nameres = m_Name->Evaluate(frame, dhint);
810                 CHECK_RESULT(nameres);
811
812                 name = nameres.GetValue();
813         }
814
815         return VMOps::NewObject(frame, m_Abstract, m_Type, name, m_Filter, m_Zone,
816             m_Package, m_DefaultTmpl, m_IgnoreOnError, m_ClosedVars, m_Expression, m_DebugInfo);
817 }
818
819 ExpressionResult ForExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const
820 {
821         if (frame.Sandboxed)
822                 BOOST_THROW_EXCEPTION(ScriptError("For loops are not allowed in sandbox mode.", m_DebugInfo));
823
824         ExpressionResult valueres = m_Value->Evaluate(frame, dhint);
825         CHECK_RESULT(valueres);
826
827         return VMOps::For(frame, m_FKVar, m_FVVar, valueres.GetValue(), m_Expression, m_DebugInfo);
828 }
829
830 ExpressionResult LibraryExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const
831 {
832         if (frame.Sandboxed)
833                 BOOST_THROW_EXCEPTION(ScriptError("Loading libraries is not allowed in sandbox mode.", m_DebugInfo));
834
835         ExpressionResult libres = m_Operand->Evaluate(frame, dhint);
836         CHECK_RESULT(libres);
837
838         Loader::LoadExtensionLibrary(libres.GetValue());
839
840         return Empty;
841 }
842
843 ExpressionResult IncludeExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const
844 {
845         if (frame.Sandboxed)
846                 BOOST_THROW_EXCEPTION(ScriptError("Includes are not allowed in sandbox mode.", m_DebugInfo));
847
848         Expression *expr;
849         String name, path, pattern;
850
851         switch (m_Type) {
852                 case IncludeRegular:
853                         {
854                                 ExpressionResult pathres = m_Path->Evaluate(frame, dhint);
855                                 CHECK_RESULT(pathres);
856                                 path = pathres.GetValue();
857                         }
858
859                         expr = ConfigCompiler::HandleInclude(m_RelativeBase, path, m_SearchIncludes, m_Zone, m_Package, m_DebugInfo);
860                         break;
861
862                 case IncludeRecursive:
863                         {
864                                 ExpressionResult pathres = m_Path->Evaluate(frame, dhint);
865                                 CHECK_RESULT(pathres);
866                                 path = pathres.GetValue();
867                         }
868
869                         {
870                                 ExpressionResult patternres = m_Pattern->Evaluate(frame, dhint);
871                                 CHECK_RESULT(patternres);
872                                 pattern = patternres.GetValue();
873                         }
874
875                         expr = ConfigCompiler::HandleIncludeRecursive(m_RelativeBase, path, pattern, m_Zone, m_Package, m_DebugInfo);
876                         break;
877
878                 case IncludeZones:
879                         {
880                                 ExpressionResult nameres = m_Name->Evaluate(frame, dhint);
881                                 CHECK_RESULT(nameres);
882                                 name = nameres.GetValue();
883                         }
884
885                         {
886                                 ExpressionResult pathres = m_Path->Evaluate(frame, dhint);
887                                 CHECK_RESULT(pathres);
888                                 path = pathres.GetValue();
889                         }
890
891                         {
892                                 ExpressionResult patternres = m_Pattern->Evaluate(frame, dhint);
893                                 CHECK_RESULT(patternres);
894                                 pattern = patternres.GetValue();
895                         }
896
897                         expr = ConfigCompiler::HandleIncludeZones(m_RelativeBase, name, path, pattern, m_Package, m_DebugInfo);
898                         break;
899         }
900
901         ExpressionResult res(Empty);
902
903         try {
904                 res = expr->Evaluate(frame, dhint);
905         } catch (const std::exception&) {
906                 delete expr;
907                 throw;
908         }
909
910         delete expr;
911
912         return res;
913 }
914
915 ExpressionResult BreakpointExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const
916 {
917         ScriptBreakpoint(frame, NULL, GetDebugInfo());
918
919         return Empty;
920 }
921
922 ExpressionResult UsingExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const
923 {
924         if (frame.Sandboxed)
925                 BOOST_THROW_EXCEPTION(ScriptError("Using directives are not allowed in sandbox mode.", m_DebugInfo));
926
927         ExpressionResult importres = m_Name->Evaluate(frame);
928         CHECK_RESULT(importres);
929         Value import = importres.GetValue();
930
931         if (!import.IsObjectType<Dictionary>())
932                 BOOST_THROW_EXCEPTION(ScriptError("The parameter must resolve to an object of type 'Dictionary'", m_DebugInfo));
933
934         ScriptFrame::AddImport(import);
935
936         return Empty;
937 }
938