From a76f81662397f60242b5556e59708717277e8da2 Mon Sep 17 00:00:00 2001 From: Gunnar Beutner Date: Thu, 19 Feb 2015 12:57:52 +0100 Subject: [PATCH] Implement the 'continue' and 'break' keywords fixes #8394 --- doc/16-language-reference.md | 8 + lib/config/applyrule.cpp | 2 +- lib/config/config_lexer.ll | 2 + lib/config/config_parser.yy | 12 +- lib/config/expression.cpp | 411 +++++++++++++++++++++++++---------- lib/config/expression.hpp | 163 +++++++++----- lib/config/vmops.hpp | 15 +- lib/icinga/hostgroup.cpp | 2 +- lib/icinga/servicegroup.cpp | 2 +- lib/icinga/usergroup.cpp | 2 +- test/config-ops.cpp | 142 ++++++------ 11 files changed, 506 insertions(+), 255 deletions(-) diff --git a/doc/16-language-reference.md b/doc/16-language-reference.md index 3b465fb27..393a004a8 100644 --- a/doc/16-language-reference.md +++ b/doc/16-language-reference.md @@ -703,6 +703,10 @@ Example: num -= 1 } +The `continue` and `break` keywords can be used to control how the loop is executed: The `continue` keyword +skips over the remaining expressions for the loop body and begins the next loop evaluation. The `break` keyword +breaks out of the loop. + ## For Loops The `for` statement can be used to iterate over arrays and dictionaries. @@ -726,6 +730,10 @@ Iterating over dictionaries can be accomplished in a similar manner: log("Key: " + key + ", Value: " + value) } +The `continue` and `break` keywords can be used to control how the loop is executed: The `continue` keyword +skips over the remaining expressions for the loop body and begins the next loop evaluation. The `break` keyword +breaks out of the loop. + ## Types All values have a static type. The `typeof` function can be used to determine the type of a value: diff --git a/lib/config/applyrule.cpp b/lib/config/applyrule.cpp index 58328b0da..9909791f6 100644 --- a/lib/config/applyrule.cpp +++ b/lib/config/applyrule.cpp @@ -88,7 +88,7 @@ void ApplyRule::AddRule(const String& sourceType, const String& targetType, cons bool ApplyRule::EvaluateFilter(ScriptFrame& frame) const { - return m_Filter->Evaluate(frame).ToBool(); + return Convert::ToBool(m_Filter->Evaluate(frame)); } void ApplyRule::RegisterType(const String& sourceType, const std::vector& targetTypes) diff --git a/lib/config/config_lexer.ll b/lib/config/config_lexer.ll index 5885e3de1..e12f2b2c8 100644 --- a/lib/config/config_lexer.ll +++ b/lib/config/config_lexer.ll @@ -202,6 +202,8 @@ assign return T_ASSIGN; ignore return T_IGNORE; function return T_FUNCTION; return return T_RETURN; +break return T_BREAK; +continue return T_CONTINUE; for return T_FOR; if return T_IF; else return T_ELSE; diff --git a/lib/config/config_parser.yy b/lib/config/config_parser.yy index f4113eb14..23a1803dc 100644 --- a/lib/config/config_parser.yy +++ b/lib/config/config_parser.yy @@ -172,6 +172,8 @@ static void MakeRBinaryOp(Expression** result, Expression *left, Expression *rig %token T_IGNORE "ignore (T_IGNORE)" %token T_FUNCTION "function (T_FUNCTION)" %token T_RETURN "return (T_RETURN)" +%token T_BREAK "break (T_BREAK)" +%token T_CONTINUE "continue (T_CONTINUE)" %token T_FOR "for (T_FOR)" %token T_IF "if (T_IF)" %token T_ELSE "else (T_ELSE)" @@ -213,7 +215,7 @@ static void MakeRBinaryOp(Expression** result, Expression *left, Expression *rig %left T_SET T_SET_ADD T_SET_SUBTRACT T_SET_MULTIPLY T_SET_DIVIDE T_SET_MODULO T_SET_XOR T_SET_BINARY_AND T_SET_BINARY_OR %left T_LOGICAL_OR %left T_LOGICAL_AND -%left T_RETURN +%left T_RETURN T_BREAK T_CONTINUE %left T_IDENTIFIER %left T_BINARY_OR %left T_XOR @@ -605,6 +607,14 @@ lterm: type { $$ = new ReturnExpression($2, @$); } + | T_BREAK + { + $$ = new BreakExpression(@$); + } + | T_CONTINUE + { + $$ = new ContinueExpression(@$); + } | apply | object | T_FOR '(' identifier T_FOLLOWS identifier T_IN rterm ')' rterm_scope_require_side_effect diff --git a/lib/config/expression.cpp b/lib/config/expression.cpp index e48ff0214..af2c53de8 100644 --- a/lib/config/expression.cpp +++ b/lib/config/expression.cpp @@ -35,7 +35,7 @@ using namespace icinga; Expression::~Expression(void) { } -Value Expression::Evaluate(ScriptFrame& frame, DebugHint *dhint) const +ExpressionResult Expression::Evaluate(ScriptFrame& frame, DebugHint *dhint) const { try { #ifdef I2_DEBUG @@ -46,8 +46,6 @@ Value Expression::Evaluate(ScriptFrame& frame, DebugHint *dhint) const #endif /* I2_DEBUG */ return DoEvaluate(frame, dhint); - } catch (const InterruptExecutionError&) { - throw; } catch (const ScriptError& ex) { throw; } catch (const std::exception& ex) { @@ -82,7 +80,7 @@ LiteralExpression::LiteralExpression(const Value& value) : m_Value(value) { } -Value LiteralExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const +ExpressionResult LiteralExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const { return m_Value; } @@ -92,7 +90,7 @@ const DebugInfo& DebuggableExpression::GetDebugInfo(void) const return m_DebugInfo; } -Value VariableExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const +ExpressionResult VariableExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const { if (frame.Locals && frame.Locals->Contains(m_Variable)) return frame.Locals->Get(m_Variable); @@ -127,155 +125,275 @@ bool VariableExpression::GetReference(ScriptFrame& frame, bool init_dict, Value return true; } -Value NegateExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const +ExpressionResult NegateExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const { - return ~(long)m_Operand->Evaluate(frame); + ExpressionResult operand = m_Operand->Evaluate(frame); + CHECK_RESULT(operand); + + return ~(long)operand.GetValue(); } -Value LogicalNegateExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const +ExpressionResult LogicalNegateExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const { - return !m_Operand->Evaluate(frame).ToBool(); + ExpressionResult operand = m_Operand->Evaluate(frame); + CHECK_RESULT(operand); + + return !operand.GetValue().ToBool(); } -Value AddExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const +ExpressionResult AddExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const { - return m_Operand1->Evaluate(frame) + m_Operand2->Evaluate(frame); + ExpressionResult operand1 = m_Operand1->Evaluate(frame); + CHECK_RESULT(operand1); + + ExpressionResult operand2 = m_Operand2->Evaluate(frame); + CHECK_RESULT(operand2); + + return operand1.GetValue() + operand2.GetValue(); } -Value SubtractExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const +ExpressionResult SubtractExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const { - return m_Operand1->Evaluate(frame) - m_Operand2->Evaluate(frame); + ExpressionResult operand1 = m_Operand1->Evaluate(frame); + CHECK_RESULT(operand1); + + ExpressionResult operand2 = m_Operand2->Evaluate(frame); + CHECK_RESULT(operand2); + + return operand1.GetValue() - operand2.GetValue(); } -Value MultiplyExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const +ExpressionResult MultiplyExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const { - return m_Operand1->Evaluate(frame) * m_Operand2->Evaluate(frame); + ExpressionResult operand1 = m_Operand1->Evaluate(frame); + CHECK_RESULT(operand1); + + ExpressionResult operand2 = m_Operand2->Evaluate(frame); + CHECK_RESULT(operand2); + + return operand1.GetValue() * operand2.GetValue(); } -Value DivideExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const +ExpressionResult DivideExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const { - return m_Operand1->Evaluate(frame) / m_Operand2->Evaluate(frame); + ExpressionResult operand1 = m_Operand1->Evaluate(frame); + CHECK_RESULT(operand1); + + ExpressionResult operand2 = m_Operand2->Evaluate(frame); + CHECK_RESULT(operand2); + + return operand1.GetValue() / operand2.GetValue(); } -Value ModuloExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const +ExpressionResult ModuloExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const { - return m_Operand1->Evaluate(frame) % m_Operand2->Evaluate(frame); + ExpressionResult operand1 = m_Operand1->Evaluate(frame); + CHECK_RESULT(operand1); + + ExpressionResult operand2 = m_Operand2->Evaluate(frame); + CHECK_RESULT(operand2); + + return operand1.GetValue() % operand2.GetValue(); } -Value XorExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const +ExpressionResult XorExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const { - return m_Operand1->Evaluate(frame) ^ m_Operand2->Evaluate(frame); + ExpressionResult operand1 = m_Operand1->Evaluate(frame); + CHECK_RESULT(operand1); + + ExpressionResult operand2 = m_Operand2->Evaluate(frame); + CHECK_RESULT(operand2); + + return operand1.GetValue() ^ operand2.GetValue(); } -Value BinaryAndExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const +ExpressionResult BinaryAndExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const { - return m_Operand1->Evaluate(frame) & m_Operand2->Evaluate(frame); + ExpressionResult operand1 = m_Operand1->Evaluate(frame); + CHECK_RESULT(operand1); + + ExpressionResult operand2 = m_Operand2->Evaluate(frame); + CHECK_RESULT(operand2); + + return operand1.GetValue() & operand2.GetValue(); } -Value BinaryOrExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const +ExpressionResult BinaryOrExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const { - return m_Operand1->Evaluate(frame) | m_Operand2->Evaluate(frame); + ExpressionResult operand1 = m_Operand1->Evaluate(frame); + CHECK_RESULT(operand1); + + ExpressionResult operand2 = m_Operand2->Evaluate(frame); + CHECK_RESULT(operand2); + + return operand1.GetValue() | operand2.GetValue(); } -Value ShiftLeftExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const +ExpressionResult ShiftLeftExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const { - return m_Operand1->Evaluate(frame) << m_Operand2->Evaluate(frame); + ExpressionResult operand1 = m_Operand1->Evaluate(frame); + CHECK_RESULT(operand1); + + ExpressionResult operand2 = m_Operand2->Evaluate(frame); + CHECK_RESULT(operand2); + + return operand1.GetValue() << operand2.GetValue(); } -Value ShiftRightExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const +ExpressionResult ShiftRightExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const { - return m_Operand1->Evaluate(frame) >> m_Operand2->Evaluate(frame); + ExpressionResult operand1 = m_Operand1->Evaluate(frame); + CHECK_RESULT(operand1); + + ExpressionResult operand2 = m_Operand2->Evaluate(frame); + CHECK_RESULT(operand2); + + return operand1.GetValue() >> operand2.GetValue(); } -Value EqualExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const +ExpressionResult EqualExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const { - return m_Operand1->Evaluate(frame) == m_Operand2->Evaluate(frame); + ExpressionResult operand1 = m_Operand1->Evaluate(frame); + CHECK_RESULT(operand1); + + ExpressionResult operand2 = m_Operand2->Evaluate(frame); + CHECK_RESULT(operand2); + + return operand1.GetValue() == operand2.GetValue(); } -Value NotEqualExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const +ExpressionResult NotEqualExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const { - return m_Operand1->Evaluate(frame) != m_Operand2->Evaluate(frame); + ExpressionResult operand1 = m_Operand1->Evaluate(frame); + CHECK_RESULT(operand1); + + ExpressionResult operand2 = m_Operand2->Evaluate(frame); + CHECK_RESULT(operand2); + + return operand1.GetValue() != operand2.GetValue(); } -Value LessThanExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const +ExpressionResult LessThanExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const { - return m_Operand1->Evaluate(frame) < m_Operand2->Evaluate(frame); + ExpressionResult operand1 = m_Operand1->Evaluate(frame); + CHECK_RESULT(operand1); + + ExpressionResult operand2 = m_Operand2->Evaluate(frame); + CHECK_RESULT(operand2); + + return operand1.GetValue() < operand2.GetValue(); } -Value GreaterThanExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const +ExpressionResult GreaterThanExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const { - return m_Operand1->Evaluate(frame) > m_Operand2->Evaluate(frame); + ExpressionResult operand1 = m_Operand1->Evaluate(frame); + CHECK_RESULT(operand1); + + ExpressionResult operand2 = m_Operand2->Evaluate(frame); + CHECK_RESULT(operand2); + + return operand1.GetValue() > operand2.GetValue(); } -Value LessThanOrEqualExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const +ExpressionResult LessThanOrEqualExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const { - return m_Operand1->Evaluate(frame) <= m_Operand2->Evaluate(frame); + ExpressionResult operand1 = m_Operand1->Evaluate(frame); + CHECK_RESULT(operand1); + + ExpressionResult operand2 = m_Operand2->Evaluate(frame); + CHECK_RESULT(operand2); + + return operand1.GetValue() <= operand2.GetValue(); } -Value GreaterThanOrEqualExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const +ExpressionResult GreaterThanOrEqualExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const { - return m_Operand1->Evaluate(frame) >= m_Operand2->Evaluate(frame); + ExpressionResult operand1 = m_Operand1->Evaluate(frame); + CHECK_RESULT(operand1); + + ExpressionResult operand2 = m_Operand2->Evaluate(frame); + CHECK_RESULT(operand2); + + return operand1.GetValue() >= operand2.GetValue(); } -Value InExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const +ExpressionResult InExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const { - Value right = m_Operand2->Evaluate(frame); + ExpressionResult operand2 = m_Operand2->Evaluate(frame); + CHECK_RESULT(operand2); - if (right.IsEmpty()) + if (operand2.GetValue().IsEmpty()) return false; - else if (!right.IsObjectType()) - BOOST_THROW_EXCEPTION(ScriptError("Invalid right side argument for 'in' operator: " + JsonEncode(right), m_DebugInfo)); + else if (!operand2.GetValue().IsObjectType()) + BOOST_THROW_EXCEPTION(ScriptError("Invalid right side argument for 'in' operator: " + JsonEncode(operand2.GetValue()), m_DebugInfo)); - Value left = m_Operand1->Evaluate(frame); + ExpressionResult operand1 = m_Operand1->Evaluate(frame); + CHECK_RESULT(operand1) - Array::Ptr arr = right; - return arr->Contains(left); + Array::Ptr arr = operand2.GetValue(); + return arr->Contains(operand1.GetValue()); } -Value NotInExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const +ExpressionResult NotInExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const { - Value right = m_Operand2->Evaluate(frame); + ExpressionResult operand2 = m_Operand2->Evaluate(frame); + CHECK_RESULT(operand2); - if (right.IsEmpty()) + if (operand2.GetValue().IsEmpty()) return true; - else if (!right.IsObjectType()) - BOOST_THROW_EXCEPTION(ScriptError("Invalid right side argument for 'in' operator: " + JsonEncode(right), m_DebugInfo)); + else if (!operand2.GetValue().IsObjectType()) + BOOST_THROW_EXCEPTION(ScriptError("Invalid right side argument for 'in' operator: " + JsonEncode(operand2.GetValue()), m_DebugInfo)); - Value left = m_Operand1->Evaluate(frame); + ExpressionResult operand1 = m_Operand1->Evaluate(frame); + CHECK_RESULT(operand1); - Array::Ptr arr = right; - return !arr->Contains(left); + Array::Ptr arr = operand2.GetValue(); + return !arr->Contains(operand1.GetValue()); } -Value LogicalAndExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const +ExpressionResult LogicalAndExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const { - Value left = m_Operand1->Evaluate(frame); + ExpressionResult operand1 = m_Operand1->Evaluate(frame); + CHECK_RESULT(operand1); - if (!left.ToBool()) - return left; - else - return m_Operand2->Evaluate(frame); + if (!operand1.GetValue().ToBool()) + return operand1; + else { + ExpressionResult operand2 = m_Operand2->Evaluate(frame); + CHECK_RESULT(operand2); + + return operand2.GetValue(); + } } -Value LogicalOrExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const +ExpressionResult LogicalOrExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const { - Value left = m_Operand1->Evaluate(frame); + ExpressionResult operand1 = m_Operand1->Evaluate(frame); + CHECK_RESULT(operand1); - if (left.ToBool()) - return left; - else - return m_Operand2->Evaluate(frame); + if (operand1.GetValue().ToBool()) + return operand1; + else { + ExpressionResult operand2 = m_Operand2->Evaluate(frame); + CHECK_RESULT(operand2); + + return operand2.GetValue(); + } } -Value FunctionCallExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const +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, m_DebugInfo); - else - vfunc = m_FName->Evaluate(frame); + else { + ExpressionResult vfuncres = m_FName->Evaluate(frame); + CHECK_RESULT(vfuncres); + + vfunc = vfuncres.GetValue(); + } if (!vfunc.IsObjectType()) BOOST_THROW_EXCEPTION(ScriptError("Argument is not a callable object.", m_DebugInfo)); @@ -284,24 +402,30 @@ Value FunctionCallExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) c std::vector arguments; BOOST_FOREACH(Expression *arg, m_Args) { - arguments.push_back(arg->Evaluate(frame)); + ExpressionResult argres = arg->Evaluate(frame); + CHECK_RESULT(argres); + + arguments.push_back(argres.GetValue()); } return VMOps::FunctionCall(frame, self, func, arguments); } -Value ArrayExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const +ExpressionResult ArrayExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const { Array::Ptr result = new Array(); BOOST_FOREACH(Expression *aexpr, m_Expressions) { - result->Add(aexpr->Evaluate(frame)); + ExpressionResult element = aexpr->Evaluate(frame); + CHECK_RESULT(element); + + result->Add(element.GetValue()); } return result; } -Value DictExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const +ExpressionResult DictExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const { ScriptFrame *dframe; ScriptFrame rframe; @@ -317,7 +441,9 @@ Value DictExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const Value result; BOOST_FOREACH(Expression *aexpr, m_Expressions) { - result = aexpr->Evaluate(*dframe, dhint); + ExpressionResult element = aexpr->Evaluate(*dframe, dhint); + CHECK_RESULT(element); + result = element.GetValue(); } if (m_Inline) @@ -326,7 +452,7 @@ Value DictExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const return dframe->Self; } -Value GetScopeExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const +ExpressionResult GetScopeExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const { if (m_ScopeSpec == ScopeLocal) return frame.Locals; @@ -340,7 +466,7 @@ Value GetScopeExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const ASSERT(!"Invalid scope."); } -Value SetExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const +ExpressionResult SetExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const { DebugHint *psdhint = dhint; @@ -350,45 +476,54 @@ Value SetExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const if (!m_Operand1->GetReference(frame, true, &parent, &index, &psdhint)) BOOST_THROW_EXCEPTION(ScriptError("Expression cannot be assigned to.", m_DebugInfo)); - Value right = m_Operand2->Evaluate(frame, dhint); + ExpressionResult operand2 = m_Operand2->Evaluate(frame, dhint); + CHECK_RESULT(operand2); if (m_Op != OpSetLiteral) { Value object = VMOps::GetField(parent, index, m_DebugInfo); Expression *lhs = MakeLiteral(object); - Expression *rhs = MakeLiteral(right); + Expression *rhs = MakeLiteral(operand2); switch (m_Op) { case OpSetAdd: - right = AddExpression(lhs, rhs, m_DebugInfo).Evaluate(frame, dhint); + operand2 = AddExpression(lhs, rhs, m_DebugInfo).Evaluate(frame, dhint); + CHECK_RESULT(operand2); break; case OpSetSubtract: - right = SubtractExpression(lhs, rhs, m_DebugInfo).Evaluate(frame, dhint); + operand2 = SubtractExpression(lhs, rhs, m_DebugInfo).Evaluate(frame, dhint); + CHECK_RESULT(operand2); break; case OpSetMultiply: - right = MultiplyExpression(lhs, rhs, m_DebugInfo).Evaluate(frame, dhint); + operand2 = MultiplyExpression(lhs, rhs, m_DebugInfo).Evaluate(frame, dhint); + CHECK_RESULT(operand2); break; case OpSetDivide: - right = DivideExpression(lhs, rhs, m_DebugInfo).Evaluate(frame, dhint); + operand2 = DivideExpression(lhs, rhs, m_DebugInfo).Evaluate(frame, dhint); + CHECK_RESULT(operand2); break; case OpSetModulo: - right = ModuloExpression(lhs, rhs, m_DebugInfo).Evaluate(frame, dhint); + operand2 = ModuloExpression(lhs, rhs, m_DebugInfo).Evaluate(frame, dhint); + CHECK_RESULT(operand2); break; case OpSetXor: - right = XorExpression(lhs, rhs, m_DebugInfo).Evaluate(frame, dhint); + operand2 = XorExpression(lhs, rhs, m_DebugInfo).Evaluate(frame, dhint); + CHECK_RESULT(operand2); break; case OpSetBinaryAnd: - right = BinaryAndExpression(lhs, rhs, m_DebugInfo).Evaluate(frame, dhint); + operand2 = BinaryAndExpression(lhs, rhs, m_DebugInfo).Evaluate(frame, dhint); + CHECK_RESULT(operand2); break; case OpSetBinaryOr: - right = BinaryOrExpression(lhs, rhs, m_DebugInfo).Evaluate(frame, dhint); + operand2 = BinaryOrExpression(lhs, rhs, m_DebugInfo).Evaluate(frame, dhint); + CHECK_RESULT(operand2); break; default: VERIFY(!"Invalid opcode."); } } - VMOps::SetField(parent, index, right, m_DebugInfo); + VMOps::SetField(parent, index, operand2.GetValue(), m_DebugInfo); if (psdhint) { psdhint->AddMessage("=", m_DebugInfo); @@ -400,9 +535,12 @@ Value SetExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const return Empty; } -Value ConditionalExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const +ExpressionResult ConditionalExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const { - if (m_Condition->Evaluate(frame, dhint).ToBool()) + 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); @@ -410,24 +548,49 @@ Value ConditionalExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) co return Empty; } -Value WhileExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const +ExpressionResult WhileExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const { - while (m_Condition->Evaluate(frame, dhint).ToBool()) - m_LoopBody->Evaluate(frame, dhint); + 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; } -Value ReturnExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const +ExpressionResult ReturnExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const { - BOOST_THROW_EXCEPTION(InterruptExecutionError(m_Operand->Evaluate(frame))); + ExpressionResult operand = m_Operand->Evaluate(frame); + CHECK_RESULT(operand); + + return ExpressionResult(operand.GetValue(), ResultReturn); } -Value IndexerExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const +ExpressionResult BreakExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const { - Value object = m_Operand1->Evaluate(frame, dhint); - String index = m_Operand2->Evaluate(frame, dhint); - return VMOps::GetField(object, index, m_DebugInfo); + 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(), m_DebugInfo); } bool IndexerExpression::GetReference(ScriptFrame& frame, bool init_dict, Value *parent, String *index, DebugHint **dhint) const @@ -440,10 +603,13 @@ bool IndexerExpression::GetReference(ScriptFrame& frame, bool init_dict, Value * VMOps::SetField(vparent, vindex, new Dictionary(), m_Operand1->GetDebugInfo()); *parent = VMOps::GetField(vparent, vindex, m_DebugInfo); - } else - *parent = m_Operand1->Evaluate(frame); + } else { + ExpressionResult operand1 = m_Operand1->Evaluate(frame); + *parent = operand1.GetValue(); + } - *index = m_Operand2->Evaluate(frame); + ExpressionResult operand2 = m_Operand2->Evaluate(frame); + *index = operand2.GetValue(); if (dhint && *dhint) *dhint = new DebugHint((*dhint)->GetChild(*index)); @@ -480,7 +646,7 @@ void icinga::BindToScope(Expression *& expr, ScopeSpecifier scopeSpec) LiteralExpression *lexpr = dynamic_cast(expr); ScriptFrame frame; - if (lexpr && lexpr->Evaluate(frame).IsString()) { + if (lexpr && lexpr->Evaluate(frame).GetValue().IsString()) { Expression *scope = new GetScopeExpression(scopeSpec); expr = new IndexerExpression(scope, lexpr, lexpr->GetDebugInfo()); } @@ -495,10 +661,12 @@ void icinga::BindToScope(Expression *& expr, ScopeSpecifier scopeSpec) } } -Value ImportExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const +ExpressionResult ImportExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const { String type = VMOps::GetField(frame.Self, "type", m_DebugInfo); - Value name = m_Name->Evaluate(frame); + 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)); @@ -508,37 +676,46 @@ Value ImportExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const if (!item) BOOST_THROW_EXCEPTION(ScriptError("Import references unknown template: '" + name + "'", m_DebugInfo)); - item->GetExpression()->Evaluate(frame, dhint); + ExpressionResult result = item->GetExpression()->Evaluate(frame, dhint); + CHECK_RESULT(result); return Empty; } -Value FunctionExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const +ExpressionResult FunctionExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const { return VMOps::NewFunction(frame, m_Args, m_ClosedVars, m_Expression); } -Value ApplyExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const +ExpressionResult ApplyExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const { - return VMOps::NewApply(frame, m_Type, m_Target, m_Name->Evaluate(frame), m_Filter, + ExpressionResult nameres = m_Name->Evaluate(frame); + CHECK_RESULT(nameres); + + return VMOps::NewApply(frame, m_Type, m_Target, nameres.GetValue(), m_Filter, m_FKVar, m_FVVar, m_FTerm, m_ClosedVars, m_Expression, m_DebugInfo); } -Value ObjectExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const +ExpressionResult ObjectExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const { String name; - if (m_Name) - name = m_Name->Evaluate(frame, dhint); + if (m_Name) { + ExpressionResult nameres = m_Name->Evaluate(frame, dhint); + CHECK_RESULT(nameres); + + name = nameres.GetValue(); + } return VMOps::NewObject(frame, m_Abstract, m_Type, name, m_Filter, m_Zone, m_ClosedVars, m_Expression, m_DebugInfo); } -Value ForExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const +ExpressionResult ForExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const { - Value value = m_Value->Evaluate(frame, dhint); + ExpressionResult valueres = m_Value->Evaluate(frame, dhint); + CHECK_RESULT(valueres); - return VMOps::For(frame, m_FKVar, m_FVVar, m_Value->Evaluate(frame), m_Expression, m_DebugInfo); + return VMOps::For(frame, m_FKVar, m_FVVar, valueres.GetValue(), m_Expression, m_DebugInfo); } diff --git a/lib/config/expression.hpp b/lib/config/expression.hpp index 72780c880..0180c2be9 100644 --- a/lib/config/expression.hpp +++ b/lib/config/expression.hpp @@ -114,26 +114,63 @@ enum ScopeSpecifier ScopeGlobal }; -class InterruptExecutionError : virtual public std::exception, virtual public boost::exception +typedef std::map DefinitionMap; + +/** + * @ingroup config + */ +enum ExpressionResultCode +{ + ResultOK, + ResultReturn, + ResultContinue, + ResultBreak +}; + +/** + * @ingroup config + */ +struct ExpressionResult { public: - InterruptExecutionError(const Value& result) - : m_Result(result) + template + ExpressionResult(const T& value, ExpressionResultCode code = ResultOK) + : m_Value(value), m_Code(code) { } - ~InterruptExecutionError(void) throw() - { } - - Value GetResult(void) const + operator Value(void) const { - return m_Result; + return m_Value; + } + + Value GetValue(void) const + { + return m_Value; + } + + ExpressionResultCode GetCode(void) const + { + return m_Code; } private: - Value m_Result; + Value m_Value; + ExpressionResultCode m_Code; }; -typedef std::map DefinitionMap; +#define CHECK_RESULT(res) \ + do { \ + if (res.GetCode() != ResultOK) \ + return res; \ + } while (0); + +#define CHECK_RESULT_LOOP(res) \ + if (res.GetCode() == ResultReturn) \ + return res; \ + if (res.GetCode() == ResultContinue) \ + continue; \ + if (res.GetCode() == ResultBreak) \ + break; \ /** * @ingroup config @@ -143,11 +180,11 @@ class I2_CONFIG_API Expression public: virtual ~Expression(void); - Value Evaluate(ScriptFrame& frame, DebugHint *dhint = NULL) const; + ExpressionResult Evaluate(ScriptFrame& frame, DebugHint *dhint = NULL) const; virtual bool GetReference(ScriptFrame& frame, bool init_dict, Value *parent, String *index, DebugHint **dhint = NULL) const; virtual const DebugInfo& GetDebugInfo(void) const; - virtual Value DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const = 0; + virtual ExpressionResult DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const = 0; }; I2_CONFIG_API Expression *MakeIndexer(ScopeSpecifier scopeSpec, const String& index); @@ -160,7 +197,7 @@ public: { } protected: - virtual Value DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const + virtual ExpressionResult DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const { return m_Expression->DoEvaluate(frame, dhint); } @@ -182,7 +219,7 @@ public: { } protected: - virtual Value DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const + virtual ExpressionResult DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const { return m_Future.get()->DoEvaluate(frame, dhint); } @@ -202,7 +239,7 @@ public: LiteralExpression(const Value& value = Value()); protected: - virtual Value DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const; + virtual ExpressionResult DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const; private: Value m_Value; @@ -274,7 +311,7 @@ public: } protected: - virtual Value DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const; + virtual ExpressionResult DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const; virtual bool GetReference(ScriptFrame& frame, bool init_dict, Value *parent, String *index, DebugHint **dhint) const; private: @@ -291,7 +328,7 @@ public: { } protected: - virtual Value DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const; + virtual ExpressionResult DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const; }; class I2_CONFIG_API LogicalNegateExpression : public UnaryExpression @@ -302,7 +339,7 @@ public: { } protected: - virtual Value DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const; + virtual ExpressionResult DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const; }; class I2_CONFIG_API AddExpression : public BinaryExpression @@ -313,7 +350,7 @@ public: { } protected: - virtual Value DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const; + virtual ExpressionResult DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const; }; class I2_CONFIG_API SubtractExpression : public BinaryExpression @@ -324,7 +361,7 @@ public: { } protected: - virtual Value DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const; + virtual ExpressionResult DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const; }; class I2_CONFIG_API MultiplyExpression : public BinaryExpression @@ -335,7 +372,7 @@ public: { } protected: - virtual Value DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const; + virtual ExpressionResult DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const; }; class I2_CONFIG_API DivideExpression : public BinaryExpression @@ -346,7 +383,7 @@ public: { } protected: - virtual Value DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const; + virtual ExpressionResult DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const; }; class I2_CONFIG_API ModuloExpression : public BinaryExpression @@ -357,7 +394,7 @@ public: { } protected: - virtual Value DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const; + virtual ExpressionResult DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const; }; class I2_CONFIG_API XorExpression : public BinaryExpression @@ -368,7 +405,7 @@ public: { } protected: - virtual Value DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const; + virtual ExpressionResult DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const; }; class I2_CONFIG_API BinaryAndExpression : public BinaryExpression @@ -379,7 +416,7 @@ public: { } protected: - virtual Value DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const; + virtual ExpressionResult DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const; }; class I2_CONFIG_API BinaryOrExpression : public BinaryExpression @@ -390,7 +427,7 @@ public: { } protected: - virtual Value DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const; + virtual ExpressionResult DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const; }; class I2_CONFIG_API ShiftLeftExpression : public BinaryExpression @@ -401,7 +438,7 @@ public: { } protected: - virtual Value DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const; + virtual ExpressionResult DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const; }; class I2_CONFIG_API ShiftRightExpression : public BinaryExpression @@ -412,7 +449,7 @@ public: { } protected: - virtual Value DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const; + virtual ExpressionResult DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const; }; class I2_CONFIG_API EqualExpression : public BinaryExpression @@ -423,7 +460,7 @@ public: { } protected: - virtual Value DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const; + virtual ExpressionResult DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const; }; class I2_CONFIG_API NotEqualExpression : public BinaryExpression @@ -434,7 +471,7 @@ public: { } protected: - virtual Value DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const; + virtual ExpressionResult DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const; }; class I2_CONFIG_API LessThanExpression : public BinaryExpression @@ -445,7 +482,7 @@ public: { } protected: - virtual Value DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const; + virtual ExpressionResult DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const; }; class I2_CONFIG_API GreaterThanExpression : public BinaryExpression @@ -456,7 +493,7 @@ public: { } protected: - virtual Value DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const; + virtual ExpressionResult DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const; }; class I2_CONFIG_API LessThanOrEqualExpression : public BinaryExpression @@ -467,7 +504,7 @@ public: { } protected: - virtual Value DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const; + virtual ExpressionResult DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const; }; class I2_CONFIG_API GreaterThanOrEqualExpression : public BinaryExpression @@ -478,7 +515,7 @@ public: { } protected: - virtual Value DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const; + virtual ExpressionResult DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const; }; class I2_CONFIG_API InExpression : public BinaryExpression @@ -489,7 +526,7 @@ public: { } protected: - virtual Value DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const; + virtual ExpressionResult DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const; }; class I2_CONFIG_API NotInExpression : public BinaryExpression @@ -500,7 +537,7 @@ public: { } protected: - virtual Value DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const; + virtual ExpressionResult DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const; }; class I2_CONFIG_API LogicalAndExpression : public BinaryExpression @@ -511,7 +548,7 @@ public: { } protected: - virtual Value DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const; + virtual ExpressionResult DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const; }; class I2_CONFIG_API LogicalOrExpression : public BinaryExpression @@ -522,7 +559,7 @@ public: { } protected: - virtual Value DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const; + virtual ExpressionResult DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const; }; class I2_CONFIG_API FunctionCallExpression : public DebuggableExpression @@ -541,7 +578,7 @@ public: } protected: - virtual Value DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const; + virtual ExpressionResult DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const; public: Expression *m_FName; @@ -562,7 +599,7 @@ public: } protected: - virtual Value DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const; + virtual ExpressionResult DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const; private: std::vector m_Expressions; @@ -584,7 +621,7 @@ public: void MakeInline(void); protected: - virtual Value DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const; + virtual ExpressionResult DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const; private: std::vector m_Expressions; @@ -601,7 +638,7 @@ public: { } protected: - virtual Value DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const; + virtual ExpressionResult DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const; private: CombinedSetOp m_Op; @@ -624,7 +661,7 @@ public: } protected: - virtual Value DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const; + virtual ExpressionResult DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const; private: Expression *m_Condition; @@ -646,7 +683,7 @@ public: } protected: - virtual Value DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const; + virtual ExpressionResult DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const; private: Expression *m_Condition; @@ -662,7 +699,29 @@ public: { } protected: - virtual Value DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const; + virtual ExpressionResult DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const; +}; + +class I2_CONFIG_API BreakExpression : public DebuggableExpression +{ +public: + BreakExpression(const DebugInfo& debugInfo = DebugInfo()) + : DebuggableExpression(debugInfo) + { } + +protected: + virtual ExpressionResult DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const; +}; + +class I2_CONFIG_API ContinueExpression : public DebuggableExpression +{ +public: + ContinueExpression(const DebugInfo& debugInfo = DebugInfo()) + : DebuggableExpression(debugInfo) + { } + +protected: + virtual ExpressionResult DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const; }; class I2_CONFIG_API GetScopeExpression : public Expression @@ -673,7 +732,7 @@ public: { } protected: - virtual Value DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const; + virtual ExpressionResult DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const; private: ScopeSpecifier m_ScopeSpec; @@ -687,7 +746,7 @@ public: { } protected: - virtual Value DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const; + virtual ExpressionResult DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const; virtual bool GetReference(ScriptFrame& frame, bool init_dict, Value *parent, String *index, DebugHint **dhint) const; friend I2_CONFIG_API void BindToScope(Expression *& expr, ScopeSpecifier scopeSpec); @@ -708,7 +767,7 @@ public: } protected: - virtual Value DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const; + virtual ExpressionResult DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const; private: Expression *m_Name; @@ -723,7 +782,7 @@ public: { } protected: - virtual Value DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const; + virtual ExpressionResult DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const; private: std::vector m_Args; @@ -749,7 +808,7 @@ public: } protected: - virtual Value DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const; + virtual ExpressionResult DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const; private: String m_Type; @@ -779,7 +838,7 @@ public: } protected: - virtual Value DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const; + virtual ExpressionResult DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const; private: bool m_Abstract; @@ -805,7 +864,7 @@ public: } protected: - virtual Value DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const; + virtual ExpressionResult DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const; private: String m_FKVar; diff --git a/lib/config/vmops.hpp b/lib/config/vmops.hpp index 36bd0dedc..5bb3cf451 100644 --- a/lib/config/vmops.hpp +++ b/lib/config/vmops.hpp @@ -139,7 +139,8 @@ public: for (Array::SizeType i = 0; i < arr->GetLength(); i++) { frame.Locals->Set(fkvar, arr->Get(i)); - expression->Evaluate(frame); + ExpressionResult res = expression->Evaluate(frame); + CHECK_RESULT_LOOP(res); } } else if (value.IsObjectType()) { if (fvvar.IsEmpty()) @@ -158,7 +159,8 @@ public: BOOST_FOREACH(const String& key, keys) { frame.Locals->Set(fkvar, key); frame.Locals->Set(fvvar, dict->Get(key)); - expression->Evaluate(frame); + ExpressionResult res = expression->Evaluate(frame); + CHECK_RESULT_LOOP(res); } } else BOOST_THROW_EXCEPTION(ScriptError("Invalid type in for expression: " + value.GetTypeName(), debugInfo)); @@ -304,14 +306,7 @@ private: for (std::vector::size_type i = 0; i < std::min(arguments.size(), funcargs.size()); i++) frame.Locals->Set(funcargs[i], arguments[i]); - Value result; - try { - result = expr->Evaluate(frame); - } catch (const InterruptExecutionError& iee) { - result = iee.GetResult(); - } - - return result; + return expr->Evaluate(frame); } static inline Dictionary::Ptr EvaluateClosedVars(ScriptFrame& frame, std::map *closedVars) diff --git a/lib/icinga/hostgroup.cpp b/lib/icinga/hostgroup.cpp index cec8d98a3..586ab6227 100644 --- a/lib/icinga/hostgroup.cpp +++ b/lib/icinga/hostgroup.cpp @@ -49,7 +49,7 @@ bool HostGroup::EvaluateObjectRule(const Host::Ptr& host, const ConfigItem::Ptr& group->GetScope()->CopyTo(frame.Locals); frame.Locals->Set("host", host); - if (!group->GetFilter()->Evaluate(frame).ToBool()) + if (!group->GetFilter()->Evaluate(frame).GetValue().ToBool()) return false; Log(LogDebug, "HostGroup") diff --git a/lib/icinga/servicegroup.cpp b/lib/icinga/servicegroup.cpp index 4e1898ab4..ee07360bd 100644 --- a/lib/icinga/servicegroup.cpp +++ b/lib/icinga/servicegroup.cpp @@ -52,7 +52,7 @@ bool ServiceGroup::EvaluateObjectRule(const Service::Ptr& service, const ConfigI frame.Locals->Set("host", host); frame.Locals->Set("service", service); - if (!group->GetFilter()->Evaluate(frame).ToBool()) + if (!group->GetFilter()->Evaluate(frame).GetValue().ToBool()) return false; Log(LogDebug, "ServiceGroup") diff --git a/lib/icinga/usergroup.cpp b/lib/icinga/usergroup.cpp index 2c54625c5..fbaa545f3 100644 --- a/lib/icinga/usergroup.cpp +++ b/lib/icinga/usergroup.cpp @@ -49,7 +49,7 @@ bool UserGroup::EvaluateObjectRule(const User::Ptr& user, const ConfigItem::Ptr& group->GetScope()->CopyTo(frame.Locals); frame.Locals->Set("user", user); - if (!group->GetFilter()->Evaluate(frame).ToBool()) + if (!group->GetFilter()->Evaluate(frame).GetValue().ToBool()) return false; Log(LogDebug, "UserGroup") diff --git a/test/config-ops.cpp b/test/config-ops.cpp index 4293b2497..6468e3177 100644 --- a/test/config-ops.cpp +++ b/test/config-ops.cpp @@ -31,177 +31,177 @@ BOOST_AUTO_TEST_CASE(simple) Dictionary::Ptr dict; expr = ConfigCompiler::CompileText("", ""); - BOOST_CHECK(expr->Evaluate(frame) == Empty); + BOOST_CHECK(expr->Evaluate(frame).GetValue() == Empty); delete expr; expr = ConfigCompiler::CompileText("", "\n3"); - BOOST_CHECK(expr->Evaluate(frame) == 3); + BOOST_CHECK(expr->Evaluate(frame).GetValue() == 3); delete expr; expr = ConfigCompiler::CompileText("", "{ 3\n\n5 }"); - BOOST_CHECK_THROW(expr->Evaluate(frame), ScriptError); + BOOST_CHECK_THROW(expr->Evaluate(frame).GetValue(), ScriptError); delete expr; expr = ConfigCompiler::CompileText("", "1 + 3"); - BOOST_CHECK(expr->Evaluate(frame) == 4); + BOOST_CHECK(expr->Evaluate(frame).GetValue() == 4); delete expr; expr = ConfigCompiler::CompileText("", "3 - 1"); - BOOST_CHECK(expr->Evaluate(frame) == 2); + BOOST_CHECK(expr->Evaluate(frame).GetValue() == 2); delete expr; expr = ConfigCompiler::CompileText("", "5m * 10"); - BOOST_CHECK(expr->Evaluate(frame) == 3000); + BOOST_CHECK(expr->Evaluate(frame).GetValue() == 3000); delete expr; expr = ConfigCompiler::CompileText("", "5m / 5"); - BOOST_CHECK(expr->Evaluate(frame) == 60); + BOOST_CHECK(expr->Evaluate(frame).GetValue() == 60); delete expr; expr = ConfigCompiler::CompileText("", "7 & 3"); - BOOST_CHECK(expr->Evaluate(frame) == 3); + BOOST_CHECK(expr->Evaluate(frame).GetValue() == 3); delete expr; expr = ConfigCompiler::CompileText("", "2 | 3"); - BOOST_CHECK(expr->Evaluate(frame) == 3); + BOOST_CHECK(expr->Evaluate(frame).GetValue() == 3); delete expr; expr = ConfigCompiler::CompileText("", "true && false"); - BOOST_CHECK(!expr->Evaluate(frame)); + BOOST_CHECK(!expr->Evaluate(frame).GetValue()); delete expr; expr = ConfigCompiler::CompileText("", "true || false"); - BOOST_CHECK(expr->Evaluate(frame)); + BOOST_CHECK(expr->Evaluate(frame).GetValue()); delete expr; expr = ConfigCompiler::CompileText("", "3 < 5"); - BOOST_CHECK(expr->Evaluate(frame)); + BOOST_CHECK(expr->Evaluate(frame).GetValue()); delete expr; expr = ConfigCompiler::CompileText("", "3 > 5"); - BOOST_CHECK(!expr->Evaluate(frame)); + BOOST_CHECK(!expr->Evaluate(frame).GetValue()); delete expr; expr = ConfigCompiler::CompileText("", "3 <= 3"); - BOOST_CHECK(expr->Evaluate(frame)); + BOOST_CHECK(expr->Evaluate(frame).GetValue()); delete expr; expr = ConfigCompiler::CompileText("", "3 >= 3"); - BOOST_CHECK(expr->Evaluate(frame)); + BOOST_CHECK(expr->Evaluate(frame).GetValue()); delete expr; expr = ConfigCompiler::CompileText("", "2 + 3 * 4"); - BOOST_CHECK(expr->Evaluate(frame) == 14); + BOOST_CHECK(expr->Evaluate(frame).GetValue() == 14); delete expr; expr = ConfigCompiler::CompileText("", "(2 + 3) * 4"); - BOOST_CHECK(expr->Evaluate(frame) == 20); + BOOST_CHECK(expr->Evaluate(frame).GetValue() == 20); delete expr; expr = ConfigCompiler::CompileText("", "2 * - 3"); - BOOST_CHECK(expr->Evaluate(frame) == -6); + BOOST_CHECK(expr->Evaluate(frame).GetValue() == -6); delete expr; expr = ConfigCompiler::CompileText("", "-(2 + 3)"); - BOOST_CHECK(expr->Evaluate(frame) == -5); + BOOST_CHECK(expr->Evaluate(frame).GetValue() == -5); delete expr; expr = ConfigCompiler::CompileText("", "- 2 * 2 - 2 * 3 - 4 * - 5"); - BOOST_CHECK(expr->Evaluate(frame) == 10); + BOOST_CHECK(expr->Evaluate(frame).GetValue() == 10); delete expr; expr = ConfigCompiler::CompileText("", "!0 == true"); - BOOST_CHECK(expr->Evaluate(frame)); + BOOST_CHECK(expr->Evaluate(frame).GetValue()); delete expr; expr = ConfigCompiler::CompileText("", "~0"); - BOOST_CHECK(expr->Evaluate(frame) == (double)~(long)0); + BOOST_CHECK(expr->Evaluate(frame).GetValue() == (double)~(long)0); delete expr; expr = ConfigCompiler::CompileText("", "4 << 8"); - BOOST_CHECK(expr->Evaluate(frame) == 1024); + BOOST_CHECK(expr->Evaluate(frame).GetValue() == 1024); delete expr; expr = ConfigCompiler::CompileText("", "1024 >> 4"); - BOOST_CHECK(expr->Evaluate(frame) == 64); + BOOST_CHECK(expr->Evaluate(frame).GetValue() == 64); delete expr; expr = ConfigCompiler::CompileText("", "2 << 3 << 4"); - BOOST_CHECK(expr->Evaluate(frame) == 256); + BOOST_CHECK(expr->Evaluate(frame).GetValue() == 256); delete expr; expr = ConfigCompiler::CompileText("", "256 >> 4 >> 3"); - BOOST_CHECK(expr->Evaluate(frame) == 2); + BOOST_CHECK(expr->Evaluate(frame).GetValue() == 2); delete expr; expr = ConfigCompiler::CompileText("", "\"hello\" == \"hello\""); - BOOST_CHECK(expr->Evaluate(frame)); + BOOST_CHECK(expr->Evaluate(frame).GetValue()); delete expr; expr = ConfigCompiler::CompileText("", "\"hello\" != \"hello\""); - BOOST_CHECK(!expr->Evaluate(frame)); + BOOST_CHECK(!expr->Evaluate(frame).GetValue()); delete expr; expr = ConfigCompiler::CompileText("", "\"foo\" in [ \"foo\", \"bar\" ]"); - BOOST_CHECK(expr->Evaluate(frame)); + BOOST_CHECK(expr->Evaluate(frame).GetValue()); delete expr; expr = ConfigCompiler::CompileText("", "\"foo\" in [ \"bar\", \"baz\" ]"); - BOOST_CHECK(!expr->Evaluate(frame)); + BOOST_CHECK(!expr->Evaluate(frame).GetValue()); delete expr; expr = ConfigCompiler::CompileText("", "\"foo\" in null"); - BOOST_CHECK(!expr->Evaluate(frame)); + BOOST_CHECK(!expr->Evaluate(frame).GetValue()); delete expr; expr = ConfigCompiler::CompileText("", "\"foo\" in \"bar\""); - BOOST_CHECK_THROW(expr->Evaluate(frame), ScriptError); + BOOST_CHECK_THROW(expr->Evaluate(frame).GetValue(), ScriptError); delete expr; expr = ConfigCompiler::CompileText("", "\"foo\" !in [ \"bar\", \"baz\" ]"); - BOOST_CHECK(expr->Evaluate(frame)); + BOOST_CHECK(expr->Evaluate(frame).GetValue()); delete expr; expr = ConfigCompiler::CompileText("", "\"foo\" !in [ \"foo\", \"bar\" ]"); - BOOST_CHECK(!expr->Evaluate(frame)); + BOOST_CHECK(!expr->Evaluate(frame).GetValue()); delete expr; expr = ConfigCompiler::CompileText("", "\"foo\" !in null"); - BOOST_CHECK(expr->Evaluate(frame)); + BOOST_CHECK(expr->Evaluate(frame).GetValue()); delete expr; expr = ConfigCompiler::CompileText("", "\"foo\" !in \"bar\""); - BOOST_CHECK_THROW(expr->Evaluate(frame), ScriptError); + BOOST_CHECK_THROW(expr->Evaluate(frame).GetValue(), ScriptError); delete expr; expr = ConfigCompiler::CompileText("", "{ a += 3 }"); - dict = expr->Evaluate(frame); + dict = expr->Evaluate(frame).GetValue(); delete expr; BOOST_CHECK(dict->GetLength() == 1); BOOST_CHECK(dict->Get("a") == 3); expr = ConfigCompiler::CompileText("", "test"); - BOOST_CHECK_THROW(expr->Evaluate(frame), ScriptError); + BOOST_CHECK_THROW(expr->Evaluate(frame).GetValue(), ScriptError); delete expr; expr = ConfigCompiler::CompileText("", "null + 3"); - BOOST_CHECK(expr->Evaluate(frame) == 3); + BOOST_CHECK(expr->Evaluate(frame).GetValue() == 3); delete expr; expr = ConfigCompiler::CompileText("", "3 + null"); - BOOST_CHECK(expr->Evaluate(frame) == 3); + BOOST_CHECK(expr->Evaluate(frame).GetValue() == 3); delete expr; expr = ConfigCompiler::CompileText("", "\"test\" + 3"); - BOOST_CHECK(expr->Evaluate(frame) == "test3"); + BOOST_CHECK(expr->Evaluate(frame).GetValue() == "test3"); delete expr; expr = ConfigCompiler::CompileText("", "\"\\\"te\\\\st\""); - BOOST_CHECK(expr->Evaluate(frame) == "\"te\\st"); + BOOST_CHECK(expr->Evaluate(frame).GetValue() == "\"te\\st"); delete expr; expr = ConfigCompiler::CompileText("", "\"\\'test\""); - BOOST_CHECK_THROW(expr->Evaluate(frame), ScriptError); + BOOST_CHECK_THROW(expr->Evaluate(frame).GetValue(), ScriptError); delete expr; } @@ -212,117 +212,117 @@ BOOST_AUTO_TEST_CASE(advanced) Function::Ptr func; expr = ConfigCompiler::CompileText("", "regex(\"^Hello\", \"Hello World\")"); - BOOST_CHECK(expr->Evaluate(frame)); + BOOST_CHECK(expr->Evaluate(frame).GetValue()); delete expr; expr = ConfigCompiler::CompileText("", "__boost_test()"); - BOOST_CHECK_THROW(expr->Evaluate(frame), ScriptError); + BOOST_CHECK_THROW(expr->Evaluate(frame).GetValue(), ScriptError); delete expr; Object::Ptr self = new Object(); ScriptFrame frame2(self); expr = ConfigCompiler::CompileText("", "this"); - BOOST_CHECK(expr->Evaluate(frame2) == Value(self)); + BOOST_CHECK(expr->Evaluate(frame2).GetValue() == Value(self)); delete expr; expr = ConfigCompiler::CompileText("", "var v = 7; v"); - BOOST_CHECK(expr->Evaluate(frame)); + BOOST_CHECK(expr->Evaluate(frame).GetValue()); delete expr; expr = ConfigCompiler::CompileText("", "{ a = 3 }.a"); - BOOST_CHECK(expr->Evaluate(frame) == 3); + BOOST_CHECK(expr->Evaluate(frame).GetValue() == 3); delete expr; expr = ConfigCompiler::CompileText("", "[ 2, 3 ][1]"); - BOOST_CHECK(expr->Evaluate(frame) == 3); + BOOST_CHECK(expr->Evaluate(frame).GetValue() == 3); delete expr; expr = ConfigCompiler::CompileText("", "var v = { a = 3}; v.a"); - BOOST_CHECK(expr->Evaluate(frame) == 3); + BOOST_CHECK(expr->Evaluate(frame).GetValue() == 3); delete expr; expr = ConfigCompiler::CompileText("", "a = 3 b = 3"); - BOOST_CHECK_THROW(expr->Evaluate(frame), ScriptError); + BOOST_CHECK_THROW(expr->Evaluate(frame).GetValue(), ScriptError); delete expr; expr = ConfigCompiler::CompileText("", "function() { 3 }()"); - BOOST_CHECK(expr->Evaluate(frame) == 3); + BOOST_CHECK(expr->Evaluate(frame).GetValue() == 3); delete expr; expr = ConfigCompiler::CompileText("", "function() { return 3, 5 }()"); - BOOST_CHECK(expr->Evaluate(frame) == 3); + BOOST_CHECK(expr->Evaluate(frame).GetValue() == 3); delete expr; expr = ConfigCompiler::CompileText("", "typeof([]) == Array"); - BOOST_CHECK(expr->Evaluate(frame)); + BOOST_CHECK(expr->Evaluate(frame).GetValue()); delete expr; expr = ConfigCompiler::CompileText("", "typeof({}) == Dictionary"); - BOOST_CHECK(expr->Evaluate(frame)); + BOOST_CHECK(expr->Evaluate(frame).GetValue()); delete expr; expr = ConfigCompiler::CompileText("", "typeof(3) == Number"); - BOOST_CHECK(expr->Evaluate(frame)); + BOOST_CHECK(expr->Evaluate(frame).GetValue()); delete expr; expr = ConfigCompiler::CompileText("", "typeof(\"test\") == String"); - BOOST_CHECK(expr->Evaluate(frame)); + BOOST_CHECK(expr->Evaluate(frame).GetValue()); delete expr; expr = ConfigCompiler::CompileText("", "(7 | 8) == 15"); - BOOST_CHECK(expr->Evaluate(frame)); + BOOST_CHECK(expr->Evaluate(frame).GetValue()); delete expr; expr = ConfigCompiler::CompileText("", "(7 ^ 8) == 15"); - BOOST_CHECK(expr->Evaluate(frame)); + BOOST_CHECK(expr->Evaluate(frame).GetValue()); delete expr; expr = ConfigCompiler::CompileText("", "(7 & 15) == 7"); - BOOST_CHECK(expr->Evaluate(frame)); + BOOST_CHECK(expr->Evaluate(frame).GetValue()); delete expr; expr = ConfigCompiler::CompileText("", "7 in [7] == true"); - BOOST_CHECK(expr->Evaluate(frame)); + BOOST_CHECK(expr->Evaluate(frame).GetValue()); delete expr; expr = ConfigCompiler::CompileText("", "7 !in [7] == false"); - BOOST_CHECK(expr->Evaluate(frame)); + BOOST_CHECK(expr->Evaluate(frame).GetValue()); delete expr; expr = ConfigCompiler::CompileText("", "(7 | 8) > 14"); - BOOST_CHECK(expr->Evaluate(frame)); + BOOST_CHECK(expr->Evaluate(frame).GetValue()); delete expr; expr = ConfigCompiler::CompileText("", "(7 ^ 8) > 14"); - BOOST_CHECK(expr->Evaluate(frame)); + BOOST_CHECK(expr->Evaluate(frame).GetValue()); delete expr; expr = ConfigCompiler::CompileText("", "(7 & 15) > 6"); - BOOST_CHECK(expr->Evaluate(frame)); + BOOST_CHECK(expr->Evaluate(frame).GetValue()); delete expr; expr = ConfigCompiler::CompileText("", "\"a\" = 3"); - BOOST_CHECK_THROW(expr->Evaluate(frame), ScriptError); + BOOST_CHECK_THROW(expr->Evaluate(frame).GetValue(), ScriptError); delete expr; expr = ConfigCompiler::CompileText("", "3 = 3"); - BOOST_CHECK_THROW(expr->Evaluate(frame), ScriptError); + BOOST_CHECK_THROW(expr->Evaluate(frame).GetValue(), ScriptError); delete expr; expr = ConfigCompiler::CompileText("", "var e; e"); - BOOST_CHECK(expr->Evaluate(frame).IsEmpty()); + BOOST_CHECK(expr->Evaluate(frame).GetValue().IsEmpty()); delete expr; expr = ConfigCompiler::CompileText("", "var e = 3; e"); - BOOST_CHECK(expr->Evaluate(frame) == 3); + BOOST_CHECK(expr->Evaluate(frame).GetValue() == 3); delete expr; expr = ConfigCompiler::CompileText("", "Array.x"); - BOOST_CHECK_THROW(expr->Evaluate(frame), ScriptError); + BOOST_CHECK_THROW(expr->Evaluate(frame).GetValue(), ScriptError); delete expr; expr = ConfigCompiler::CompileText("", "{{ 3 }}"); - func = expr->Evaluate(frame); + func = expr->Evaluate(frame).GetValue(); BOOST_CHECK(func->Invoke() == 3); delete expr; }