/* Icinga 2 | (c) 2012 Icinga GmbH | GPLv2+ */ #include "config/expression.hpp" #include "config/configitem.hpp" #include "config/configcompiler.hpp" #include "config/vmops.hpp" #include "base/array.hpp" #include "base/json.hpp" #include "base/object.hpp" #include "base/logger.hpp" #include "base/exception.hpp" #include "base/scriptglobal.hpp" #include "base/loader.hpp" #include "base/reference.hpp" #include "base/namespace.hpp" #include "base/defer.hpp" #include #include using namespace icinga; boost::signals2::signal Expression::OnBreakpoint; boost::thread_specific_ptr l_InBreakpointHandler; Expression::~Expression() { } void Expression::ScriptBreakpoint(ScriptFrame& frame, ScriptError *ex, const DebugInfo& di) { bool *inHandler = l_InBreakpointHandler.get(); if (!inHandler || !*inHandler) { inHandler = new bool(true); l_InBreakpointHandler.reset(inHandler); OnBreakpoint(frame, ex, di); *inHandler = false; } } ExpressionResult Expression::Evaluate(ScriptFrame& frame, DebugHint *dhint) const { try { #ifdef I2_DEBUG /* std::ostringstream msgbuf; ShowCodeLocation(msgbuf, GetDebugInfo(), false); Log(LogDebug, "Expression") << "Executing:\n" << msgbuf.str();*/ #endif /* I2_DEBUG */ frame.IncreaseStackDepth(); Defer decreaseStackDepth([&frame]{ frame.DecreaseStackDepth(); }); ExpressionResult result = DoEvaluate(frame, dhint); return result; } catch (ScriptError& ex) { ScriptBreakpoint(frame, &ex, GetDebugInfo()); throw; } catch (const std::exception& ex) { BOOST_THROW_EXCEPTION(ScriptError("Error while evaluating expression: " + String(ex.what()), GetDebugInfo()) << boost::errinfo_nested_exception(boost::current_exception())); } } bool Expression::GetReference(ScriptFrame& frame, bool init_dict, Value *parent, String *index, DebugHint **dhint) const { return false; } const DebugInfo& Expression::GetDebugInfo() const { static DebugInfo debugInfo; return debugInfo; } std::unique_ptr icinga::MakeIndexer(ScopeSpecifier scopeSpec, const String& index) { std::unique_ptr scope{new GetScopeExpression(scopeSpec)}; return std::unique_ptr(new IndexerExpression(std::move(scope), MakeLiteral(index))); } void DictExpression::MakeInline() { m_Inline = true; } LiteralExpression::LiteralExpression(Value value) : m_Value(std::move(value)) { } ExpressionResult LiteralExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const { return m_Value; } const DebugInfo& DebuggableExpression::GetDebugInfo() const { return m_DebugInfo; } VariableExpression::VariableExpression(String variable, std::vector imports, const DebugInfo& debugInfo) : DebuggableExpression(debugInfo), m_Variable(std::move(variable)), m_Imports(std::move(imports)) { m_Imports.push_back(MakeIndexer(ScopeGlobal, "System").release()); m_Imports.push_back(new IndexerExpression(MakeIndexer(ScopeGlobal, "System"), MakeLiteral("Configuration"))); m_Imports.push_back(MakeIndexer(ScopeGlobal, "Types").release()); m_Imports.push_back(MakeIndexer(ScopeGlobal, "Icinga").release()); } ExpressionResult VariableExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const { Value value; if (frame.Locals && frame.Locals->Get(m_Variable, &value)) return value; else if (frame.Self.IsObject() && frame.Locals != frame.Self.Get() && frame.Self.Get()->GetOwnField(m_Variable, &value)) return value; else if (VMOps::FindVarImport(frame, m_Imports, m_Variable, &value, m_DebugInfo)) return value; else return ScriptGlobal::Get(m_Variable); } bool VariableExpression::GetReference(ScriptFrame& frame, bool init_dict, Value *parent, String *index, DebugHint **dhint) const { *index = m_Variable; if (frame.Locals && frame.Locals->Contains(m_Variable)) { *parent = frame.Locals; if (dhint) *dhint = nullptr; } else if (frame.Self.IsObject() && frame.Locals != frame.Self.Get() && frame.Self.Get()->HasOwnField(m_Variable)) { *parent = frame.Self; if (dhint && *dhint) *dhint = new DebugHint((*dhint)->GetChild(m_Variable)); } else if (VMOps::FindVarImportRef(frame, m_Imports, m_Variable, parent, m_DebugInfo)) { return true; } else if (ScriptGlobal::Exists(m_Variable)) { *parent = ScriptGlobal::GetGlobals(); if (dhint) *dhint = nullptr; } else *parent = frame.Self; return true; } ExpressionResult RefExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const { Value parent; String index; if (!m_Operand->GetReference(frame, false, &parent, &index, &dhint)) BOOST_THROW_EXCEPTION(ScriptError("Cannot obtain reference for expression.", m_DebugInfo)); if (!parent.IsObject()) BOOST_THROW_EXCEPTION(ScriptError("Cannot obtain reference for expression because parent is not an object.", m_DebugInfo)); return new Reference(parent, index); } ExpressionResult DerefExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const { ExpressionResult operand = m_Operand->Evaluate(frame); CHECK_RESULT(operand); Object::Ptr obj = operand.GetValue(); Reference::Ptr ref = dynamic_pointer_cast(obj); if (!ref) BOOST_THROW_EXCEPTION(ScriptError("Invalid reference specified.", GetDebugInfo())); return ref->Get(); } bool DerefExpression::GetReference(ScriptFrame& frame, bool init_dict, Value *parent, String *index, DebugHint **dhint) const { ExpressionResult operand = m_Operand->Evaluate(frame); if (operand.GetCode() != ResultOK) return false; Reference::Ptr ref = operand.GetValue(); *parent = ref->GetParent(); *index = ref->GetIndex(); return true; } ExpressionResult NegateExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const { ExpressionResult operand = m_Operand->Evaluate(frame); CHECK_RESULT(operand); return ~(long)operand.GetValue(); } ExpressionResult LogicalNegateExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const { ExpressionResult operand = m_Operand->Evaluate(frame); CHECK_RESULT(operand); return !operand.GetValue().ToBool(); } ExpressionResult AddExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const { ExpressionResult operand1 = m_Operand1->Evaluate(frame); CHECK_RESULT(operand1); ExpressionResult operand2 = m_Operand2->Evaluate(frame); CHECK_RESULT(operand2); return operand1.GetValue() + operand2.GetValue(); } ExpressionResult SubtractExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const { ExpressionResult operand1 = m_Operand1->Evaluate(frame); CHECK_RESULT(operand1); ExpressionResult operand2 = m_Operand2->Evaluate(frame); CHECK_RESULT(operand2); return operand1.GetValue() - operand2.GetValue(); } ExpressionResult MultiplyExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const { ExpressionResult operand1 = m_Operand1->Evaluate(frame); CHECK_RESULT(operand1); ExpressionResult operand2 = m_Operand2->Evaluate(frame); CHECK_RESULT(operand2); return operand1.GetValue() * operand2.GetValue(); } ExpressionResult DivideExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const { ExpressionResult operand1 = m_Operand1->Evaluate(frame); CHECK_RESULT(operand1); ExpressionResult operand2 = m_Operand2->Evaluate(frame); CHECK_RESULT(operand2); return operand1.GetValue() / operand2.GetValue(); } ExpressionResult ModuloExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const { ExpressionResult operand1 = m_Operand1->Evaluate(frame); CHECK_RESULT(operand1); ExpressionResult operand2 = m_Operand2->Evaluate(frame); CHECK_RESULT(operand2); return operand1.GetValue() % operand2.GetValue(); } ExpressionResult XorExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const { ExpressionResult operand1 = m_Operand1->Evaluate(frame); CHECK_RESULT(operand1); ExpressionResult operand2 = m_Operand2->Evaluate(frame); CHECK_RESULT(operand2); return operand1.GetValue() ^ operand2.GetValue(); } ExpressionResult BinaryAndExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const { ExpressionResult operand1 = m_Operand1->Evaluate(frame); CHECK_RESULT(operand1); ExpressionResult operand2 = m_Operand2->Evaluate(frame); CHECK_RESULT(operand2); return operand1.GetValue() & operand2.GetValue(); } ExpressionResult BinaryOrExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const { ExpressionResult operand1 = m_Operand1->Evaluate(frame); CHECK_RESULT(operand1); ExpressionResult operand2 = m_Operand2->Evaluate(frame); CHECK_RESULT(operand2); return operand1.GetValue() | operand2.GetValue(); } ExpressionResult ShiftLeftExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const { ExpressionResult operand1 = m_Operand1->Evaluate(frame); CHECK_RESULT(operand1); ExpressionResult operand2 = m_Operand2->Evaluate(frame); CHECK_RESULT(operand2); return operand1.GetValue() << operand2.GetValue(); } ExpressionResult ShiftRightExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const { ExpressionResult operand1 = m_Operand1->Evaluate(frame); CHECK_RESULT(operand1); ExpressionResult operand2 = m_Operand2->Evaluate(frame); CHECK_RESULT(operand2); return operand1.GetValue() >> operand2.GetValue(); } ExpressionResult EqualExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const { ExpressionResult operand1 = m_Operand1->Evaluate(frame); CHECK_RESULT(operand1); ExpressionResult operand2 = m_Operand2->Evaluate(frame); CHECK_RESULT(operand2); return operand1.GetValue() == operand2.GetValue(); } ExpressionResult NotEqualExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const { ExpressionResult operand1 = m_Operand1->Evaluate(frame); CHECK_RESULT(operand1); ExpressionResult operand2 = m_Operand2->Evaluate(frame); CHECK_RESULT(operand2); return operand1.GetValue() != operand2.GetValue(); } ExpressionResult LessThanExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const { ExpressionResult operand1 = m_Operand1->Evaluate(frame); CHECK_RESULT(operand1); ExpressionResult operand2 = m_Operand2->Evaluate(frame); CHECK_RESULT(operand2); return operand1.GetValue() < operand2.GetValue(); } ExpressionResult GreaterThanExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const { ExpressionResult operand1 = m_Operand1->Evaluate(frame); CHECK_RESULT(operand1); ExpressionResult operand2 = m_Operand2->Evaluate(frame); CHECK_RESULT(operand2); return operand1.GetValue() > operand2.GetValue(); } ExpressionResult LessThanOrEqualExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const { ExpressionResult operand1 = m_Operand1->Evaluate(frame); CHECK_RESULT(operand1); ExpressionResult operand2 = m_Operand2->Evaluate(frame); CHECK_RESULT(operand2); return operand1.GetValue() <= operand2.GetValue(); } ExpressionResult GreaterThanOrEqualExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const { ExpressionResult operand1 = m_Operand1->Evaluate(frame); CHECK_RESULT(operand1); ExpressionResult operand2 = m_Operand2->Evaluate(frame); CHECK_RESULT(operand2); return operand1.GetValue() >= operand2.GetValue(); } ExpressionResult InExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const { ExpressionResult operand2 = m_Operand2->Evaluate(frame); CHECK_RESULT(operand2); if (operand2.GetValue().IsEmpty()) return false; else if (!operand2.GetValue().IsObjectType()) BOOST_THROW_EXCEPTION(ScriptError("Invalid right side argument for 'in' operator: " + JsonEncode(operand2.GetValue()), m_DebugInfo)); ExpressionResult operand1 = m_Operand1->Evaluate(frame); CHECK_RESULT(operand1) Array::Ptr arr = operand2.GetValue(); return arr->Contains(operand1.GetValue()); } ExpressionResult NotInExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const { ExpressionResult operand2 = m_Operand2->Evaluate(frame); CHECK_RESULT(operand2); if (operand2.GetValue().IsEmpty()) return true; else if (!operand2.GetValue().IsObjectType()) BOOST_THROW_EXCEPTION(ScriptError("Invalid right side argument for 'in' operator: " + JsonEncode(operand2.GetValue()), m_DebugInfo)); ExpressionResult operand1 = m_Operand1->Evaluate(frame); CHECK_RESULT(operand1); Array::Ptr arr = operand2.GetValue(); return !arr->Contains(operand1.GetValue()); } ExpressionResult LogicalAndExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const { ExpressionResult operand1 = m_Operand1->Evaluate(frame); CHECK_RESULT(operand1); if (!operand1.GetValue().ToBool()) return operand1; else { ExpressionResult operand2 = m_Operand2->Evaluate(frame); CHECK_RESULT(operand2); return operand2.GetValue(); } } ExpressionResult LogicalOrExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const { ExpressionResult operand1 = m_Operand1->Evaluate(frame); CHECK_RESULT(operand1); if (operand1.GetValue().ToBool()) return operand1; else { ExpressionResult operand2 = m_Operand2->Evaluate(frame); CHECK_RESULT(operand2); return operand2.GetValue(); } } ExpressionResult FunctionCallExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const { Value self, vfunc; String index; if (m_FName->GetReference(frame, false, &self, &index)) vfunc = VMOps::GetField(self, index, frame.Sandboxed, m_DebugInfo); else { ExpressionResult vfuncres = m_FName->Evaluate(frame); CHECK_RESULT(vfuncres); vfunc = vfuncres.GetValue(); } if (vfunc.IsObjectType()) { std::vector arguments; arguments.reserve(m_Args.size()); for (const auto& arg : m_Args) { ExpressionResult argres = arg->Evaluate(frame); CHECK_RESULT(argres); arguments.push_back(argres.GetValue()); } return VMOps::ConstructorCall(vfunc, arguments, m_DebugInfo); } if (!vfunc.IsObjectType()) BOOST_THROW_EXCEPTION(ScriptError("Argument is not a callable object.", m_DebugInfo)); Function::Ptr func = vfunc; if (!func->IsSideEffectFree() && frame.Sandboxed) BOOST_THROW_EXCEPTION(ScriptError("Function is not marked as safe for sandbox mode.", m_DebugInfo)); std::vector arguments; arguments.reserve(m_Args.size()); for (const auto& arg : m_Args) { ExpressionResult argres = arg->Evaluate(frame); CHECK_RESULT(argres); arguments.push_back(argres.GetValue()); } return VMOps::FunctionCall(frame, self, func, arguments); } ExpressionResult ArrayExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const { ArrayData result; result.reserve(m_Expressions.size()); for (const auto& aexpr : m_Expressions) { ExpressionResult element = aexpr->Evaluate(frame); CHECK_RESULT(element); result.push_back(element.GetValue()); } return new Array(std::move(result)); } ExpressionResult DictExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const { Value self; if (!m_Inline) { self = frame.Self; frame.Self = new Dictionary(); } Value result; try { for (const auto& aexpr : m_Expressions) { ExpressionResult element = aexpr->Evaluate(frame, m_Inline ? dhint : nullptr); CHECK_RESULT(element); result = element.GetValue(); } } catch (...) { if (!m_Inline) std::swap(self, frame.Self); throw; } if (m_Inline) return result; else { std::swap(self, frame.Self); return self; } } ExpressionResult GetScopeExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const { if (m_ScopeSpec == ScopeLocal) return frame.Locals; else if (m_ScopeSpec == ScopeThis) return frame.Self; else if (m_ScopeSpec == ScopeGlobal) return ScriptGlobal::GetGlobals(); else VERIFY(!"Invalid scope."); } static inline void WarnOnImplicitlySetGlobalVar(const std::unique_ptr& setLhs, const Value& setLhsParent, CombinedSetOp setOp, const DebugInfo& debug) { auto var (dynamic_cast(setLhs.get())); if (var && setLhsParent.IsObject()) { auto ns (dynamic_pointer_cast(setLhsParent.Get())); if (ns && ns == ScriptGlobal::GetGlobals() && debug.Path.GetLength()) { const char *opStr = nullptr; switch (setOp) { case OpSetLiteral: opStr = "="; break; case OpSetAdd: opStr = "+="; break; case OpSetSubtract: opStr = "-="; break; case OpSetMultiply: opStr = "*="; break; case OpSetDivide: opStr = "/="; break; case OpSetModulo: opStr = "%="; break; case OpSetXor: opStr = "^="; break; case OpSetBinaryAnd: opStr = "&="; break; case OpSetBinaryOr: opStr = "|="; break; default: VERIFY(!"Invalid opcode."); } auto varName (var->GetVariable()); Log(LogWarning, "config") << "Global variable '" << varName << "' has been set implicitly via '" << varName << ' ' << opStr << " ...' " << debug << "." " Please set it explicitly via 'globals." << varName << ' ' << opStr << " ...' instead."; } } } ExpressionResult SetExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const { if (frame.Sandboxed) BOOST_THROW_EXCEPTION(ScriptError("Assignments are not allowed in sandbox mode.", m_DebugInfo)); DebugHint *psdhint = dhint; Value parent; String index; if (!m_Operand1->GetReference(frame, true, &parent, &index, &psdhint)) BOOST_THROW_EXCEPTION(ScriptError("Expression cannot be assigned to.", m_DebugInfo)); ExpressionResult operand2 = m_Operand2->Evaluate(frame, dhint); CHECK_RESULT(operand2); if (m_Op != OpSetLiteral) { Value object = VMOps::GetField(parent, index, frame.Sandboxed, m_DebugInfo); switch (m_Op) { case OpSetAdd: operand2 = object + operand2; break; case OpSetSubtract: operand2 = object - operand2; break; case OpSetMultiply: operand2 = object * operand2; break; case OpSetDivide: operand2 = object / operand2; break; case OpSetModulo: operand2 = object % operand2; break; case OpSetXor: operand2 = object ^ operand2; break; case OpSetBinaryAnd: operand2 = object & operand2; break; case OpSetBinaryOr: operand2 = object | operand2; break; default: VERIFY(!"Invalid opcode."); } } VMOps::SetField(parent, index, operand2.GetValue(), m_OverrideFrozen, m_DebugInfo); if (psdhint) { psdhint->AddMessage("=", m_DebugInfo); if (psdhint != dhint) delete psdhint; } WarnOnImplicitlySetGlobalVar(m_Operand1, parent, m_Op, m_DebugInfo); return Empty; } void SetExpression::SetOverrideFrozen() { m_OverrideFrozen = true; } ExpressionResult SetConstExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const { auto globals = ScriptGlobal::GetGlobals(); ExpressionResult operandres = m_Operand->Evaluate(frame); CHECK_RESULT(operandres); Value operand = operandres.GetValue(); globals->Set(m_Name, operand, true); return Empty; } ExpressionResult ConditionalExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const { ExpressionResult condition = m_Condition->Evaluate(frame, dhint); CHECK_RESULT(condition); if (condition.GetValue().ToBool()) return m_TrueBranch->Evaluate(frame, dhint); else if (m_FalseBranch) return m_FalseBranch->Evaluate(frame, dhint); return Empty; } ExpressionResult WhileExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const { if (frame.Sandboxed) BOOST_THROW_EXCEPTION(ScriptError("While loops are not allowed in sandbox mode.", m_DebugInfo)); for (;;) { ExpressionResult condition = m_Condition->Evaluate(frame, dhint); CHECK_RESULT(condition); if (!condition.GetValue().ToBool()) break; ExpressionResult loop_body = m_LoopBody->Evaluate(frame, dhint); CHECK_RESULT_LOOP(loop_body); } return Empty; } ExpressionResult ReturnExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const { ExpressionResult operand = m_Operand->Evaluate(frame); CHECK_RESULT(operand); return ExpressionResult(operand.GetValue(), ResultReturn); } ExpressionResult BreakExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const { return ExpressionResult(Empty, ResultBreak); } ExpressionResult ContinueExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const { return ExpressionResult(Empty, ResultContinue); } ExpressionResult IndexerExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const { ExpressionResult operand1 = m_Operand1->Evaluate(frame, dhint); CHECK_RESULT(operand1); ExpressionResult operand2 = m_Operand2->Evaluate(frame, dhint); CHECK_RESULT(operand2); return VMOps::GetField(operand1.GetValue(), operand2.GetValue(), frame.Sandboxed, m_DebugInfo); } bool IndexerExpression::GetReference(ScriptFrame& frame, bool init_dict, Value *parent, String *index, DebugHint **dhint) const { Value vparent; String vindex; DebugHint *psdhint = nullptr; bool free_psd = false; if (dhint) psdhint = *dhint; if (frame.Sandboxed) init_dict = false; if (m_Operand1->GetReference(frame, init_dict, &vparent, &vindex, &psdhint)) { if (init_dict) { Value old_value; bool has_field = true; if (vparent.IsObject()) { Object::Ptr oparent = vparent; has_field = oparent->HasOwnField(vindex); } if (has_field) old_value = VMOps::GetField(vparent, vindex, frame.Sandboxed, m_Operand1->GetDebugInfo()); if (old_value.IsEmpty() && !old_value.IsString()) VMOps::SetField(vparent, vindex, new Dictionary(), m_OverrideFrozen, m_Operand1->GetDebugInfo()); } *parent = VMOps::GetField(vparent, vindex, frame.Sandboxed, m_DebugInfo); free_psd = true; } else { ExpressionResult operand1 = m_Operand1->Evaluate(frame); *parent = operand1.GetValue(); } ExpressionResult operand2 = m_Operand2->Evaluate(frame); *index = operand2.GetValue(); if (dhint) { if (psdhint) *dhint = new DebugHint(psdhint->GetChild(*index)); else *dhint = nullptr; } if (free_psd) delete psdhint; return true; } void IndexerExpression::SetOverrideFrozen() { m_OverrideFrozen = true; } void icinga::BindToScope(std::unique_ptr& expr, ScopeSpecifier scopeSpec) { auto *dexpr = dynamic_cast(expr.get()); if (dexpr) { for (auto& expr : dexpr->m_Expressions) BindToScope(expr, scopeSpec); return; } auto *aexpr = dynamic_cast(expr.get()); if (aexpr) { BindToScope(aexpr->m_Operand1, scopeSpec); return; } auto *iexpr = dynamic_cast(expr.get()); if (iexpr) { BindToScope(iexpr->m_Operand1, scopeSpec); return; } auto *lexpr = dynamic_cast(expr.get()); if (lexpr && lexpr->GetValue().IsString()) { std::unique_ptr scope{new GetScopeExpression(scopeSpec)}; expr.reset(new IndexerExpression(std::move(scope), std::move(expr), lexpr->GetDebugInfo())); } auto *vexpr = dynamic_cast(expr.get()); if (vexpr) { std::unique_ptr scope{new GetScopeExpression(scopeSpec)}; expr.reset(new IndexerExpression(std::move(scope), MakeLiteral(vexpr->GetVariable()), vexpr->GetDebugInfo())); } } ExpressionResult ThrowExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const { ExpressionResult messageres = m_Message->Evaluate(frame); CHECK_RESULT(messageres); Value message = messageres.GetValue(); BOOST_THROW_EXCEPTION(ScriptError(message, m_DebugInfo, m_IncompleteExpr)); } ExpressionResult ImportExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const { if (frame.Sandboxed) BOOST_THROW_EXCEPTION(ScriptError("Imports are not allowed in sandbox mode.", m_DebugInfo)); String type = VMOps::GetField(frame.Self, "type", frame.Sandboxed, m_DebugInfo); ExpressionResult nameres = m_Name->Evaluate(frame); CHECK_RESULT(nameres); Value name = nameres.GetValue(); if (!name.IsString()) BOOST_THROW_EXCEPTION(ScriptError("Template/object name must be a string", m_DebugInfo)); ConfigItem::Ptr item = ConfigItem::GetByTypeAndName(Type::GetByName(type), name); if (!item) BOOST_THROW_EXCEPTION(ScriptError("Import references unknown template: '" + name + "'", m_DebugInfo)); Dictionary::Ptr scope = item->GetScope(); if (scope) scope->CopyTo(frame.Locals); ExpressionResult result = item->GetExpression()->Evaluate(frame, dhint); CHECK_RESULT(result); return Empty; } ExpressionResult ImportDefaultTemplatesExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const { if (frame.Sandboxed) BOOST_THROW_EXCEPTION(ScriptError("Imports are not allowed in sandbox mode.", m_DebugInfo)); String type = VMOps::GetField(frame.Self, "type", frame.Sandboxed, m_DebugInfo); Type::Ptr ptype = Type::GetByName(type); for (const ConfigItem::Ptr& item : ConfigItem::GetDefaultTemplates(ptype)) { Dictionary::Ptr scope = item->GetScope(); if (scope) scope->CopyTo(frame.Locals); ExpressionResult result = item->GetExpression()->Evaluate(frame, dhint); CHECK_RESULT(result); } return Empty; } ExpressionResult FunctionExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const { return VMOps::NewFunction(frame, m_Name, m_Args, m_ClosedVars, m_Expression); } ExpressionResult ApplyExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const { if (frame.Sandboxed) BOOST_THROW_EXCEPTION(ScriptError("Apply rules are not allowed in sandbox mode.", m_DebugInfo)); ExpressionResult nameres = m_Name->Evaluate(frame); CHECK_RESULT(nameres); return VMOps::NewApply(frame, m_Type, m_Target, nameres.GetValue(), m_Filter, m_Package, m_FKVar, m_FVVar, m_FTerm, m_ClosedVars, m_IgnoreOnError, m_Expression, m_DebugInfo); } ExpressionResult NamespaceExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const { Namespace::Ptr ns = new Namespace(true); ScriptFrame innerFrame(true, ns); ExpressionResult result = m_Expression->Evaluate(innerFrame); CHECK_RESULT(result); return ns; } ExpressionResult ObjectExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const { if (frame.Sandboxed) BOOST_THROW_EXCEPTION(ScriptError("Object definitions are not allowed in sandbox mode.", m_DebugInfo)); ExpressionResult typeres = m_Type->Evaluate(frame, dhint); CHECK_RESULT(typeres); Type::Ptr type = typeres.GetValue(); String name; if (m_Name) { ExpressionResult nameres = m_Name->Evaluate(frame, dhint); CHECK_RESULT(nameres); name = nameres.GetValue(); } return VMOps::NewObject(frame, m_Abstract, type, name, m_Filter, m_Zone, m_Package, m_DefaultTmpl, m_IgnoreOnError, m_ClosedVars, m_Expression, m_DebugInfo); } ExpressionResult ForExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const { if (frame.Sandboxed) BOOST_THROW_EXCEPTION(ScriptError("For loops are not allowed in sandbox mode.", m_DebugInfo)); ExpressionResult valueres = m_Value->Evaluate(frame, dhint); CHECK_RESULT(valueres); return VMOps::For(frame, m_FKVar, m_FVVar, valueres.GetValue(), m_Expression, m_DebugInfo); } ExpressionResult LibraryExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const { if (frame.Sandboxed) BOOST_THROW_EXCEPTION(ScriptError("Loading libraries is not allowed in sandbox mode.", m_DebugInfo)); ExpressionResult libres = m_Operand->Evaluate(frame, dhint); CHECK_RESULT(libres); Log(LogNotice, "config") << "Ignoring explicit load request for library \"" << libres << "\"."; return Empty; } ExpressionResult IncludeExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const { if (frame.Sandboxed) BOOST_THROW_EXCEPTION(ScriptError("Includes are not allowed in sandbox mode.", m_DebugInfo)); std::unique_ptr expr; String name, path, pattern; switch (m_Type) { case IncludeRegular: { ExpressionResult pathres = m_Path->Evaluate(frame, dhint); CHECK_RESULT(pathres); path = pathres.GetValue(); } expr = ConfigCompiler::HandleInclude(m_RelativeBase, path, m_SearchIncludes, m_Zone, m_Package, m_DebugInfo); break; case IncludeRecursive: { ExpressionResult pathres = m_Path->Evaluate(frame, dhint); CHECK_RESULT(pathres); path = pathres.GetValue(); } { ExpressionResult patternres = m_Pattern->Evaluate(frame, dhint); CHECK_RESULT(patternres); pattern = patternres.GetValue(); } expr = ConfigCompiler::HandleIncludeRecursive(m_RelativeBase, path, pattern, m_Zone, m_Package, m_DebugInfo); break; case IncludeZones: { ExpressionResult nameres = m_Name->Evaluate(frame, dhint); CHECK_RESULT(nameres); name = nameres.GetValue(); } { ExpressionResult pathres = m_Path->Evaluate(frame, dhint); CHECK_RESULT(pathres); path = pathres.GetValue(); } { ExpressionResult patternres = m_Pattern->Evaluate(frame, dhint); CHECK_RESULT(patternres); pattern = patternres.GetValue(); } expr = ConfigCompiler::HandleIncludeZones(m_RelativeBase, name, path, pattern, m_Package, m_DebugInfo); break; } ExpressionResult res(Empty); try { res = expr->Evaluate(frame, dhint); } catch (const std::exception&) { throw; } return res; } ExpressionResult BreakpointExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const { ScriptBreakpoint(frame, nullptr, GetDebugInfo()); return Empty; } ExpressionResult TryExceptExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const { try { ExpressionResult tryResult = m_TryBody->Evaluate(frame, dhint); CHECK_RESULT(tryResult); } catch (const std::exception&) { ExpressionResult exceptResult = m_ExceptBody->Evaluate(frame, dhint); CHECK_RESULT(exceptResult); } return Empty; }