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