diff --git a/lib/config/config_parser.yy b/lib/config/config_parser.yy index 30896fd97..67c3c4574 100644 --- a/lib/config/config_parser.yy +++ b/lib/config/config_parser.yy @@ -652,9 +652,7 @@ lterm: T_LOCAL indexer combined_set_op rterm } | T_RETURN rterm { - std::vector vname; - vname.push_back(MakeLiteral("__result")); - $$ = new SetExpression(vname, OpSetLiteral, $2, false, DebugInfoRange(@1, @2)); + $$ = new ReturnExpression($2, DebugInfoRange(@1, @2)); } | apply { diff --git a/lib/config/expression.cpp b/lib/config/expression.cpp index 85804a2b1..063b92255 100644 --- a/lib/config/expression.cpp +++ b/lib/config/expression.cpp @@ -45,6 +45,8 @@ Value Expression::Evaluate(VMFrame& frame, DebugHint *dhint) const #endif /* _DEBUG */ return DoEvaluate(frame, dhint); + } catch (const InterruptExecutionError&) { + throw; } catch (const std::exception& ex) { if (boost::get_error_info(ex)) throw; @@ -344,6 +346,11 @@ Value SetExpression::DoEvaluate(VMFrame& frame, DebugHint *dhint) const return right; } +Value ReturnExpression::DoEvaluate(VMFrame& frame, DebugHint *dhint) const +{ + BOOST_THROW_EXCEPTION(InterruptExecutionError(m_Operand->Evaluate(frame))); +} + Value IndexerExpression::DoEvaluate(VMFrame& frame, DebugHint *dhint) const { return VMOps::Indexer(frame, m_Indexer); diff --git a/lib/config/expression.hpp b/lib/config/expression.hpp index 84e5d8b57..d9d9ca556 100644 --- a/lib/config/expression.hpp +++ b/lib/config/expression.hpp @@ -101,6 +101,25 @@ enum CombinedSetOp OpSetDivide }; +class InterruptExecutionError : virtual public std::exception, virtual public boost::exception +{ +public: + InterruptExecutionError(const Value& result) + : m_Result(result) + { } + + ~InterruptExecutionError(void) throw() + { } + + Value GetResult(void) const + { + return m_Result; + } + +private: + Value m_Result; +}; + typedef std::map DefinitionMap; /** @@ -537,6 +556,17 @@ private: }; +class I2_CONFIG_API ReturnExpression : public UnaryExpression +{ +public: + ReturnExpression(Expression *expression, const DebugInfo& debugInfo = DebugInfo()) + : UnaryExpression(expression, debugInfo) + { } + +protected: + virtual Value DoEvaluate(VMFrame& frame, DebugHint *dhint) const; +}; + class I2_CONFIG_API IndexerExpression : public DebuggableExpression { public: diff --git a/lib/config/vmframe.hpp b/lib/config/vmframe.hpp index 833058d69..68ca2b76d 100644 --- a/lib/config/vmframe.hpp +++ b/lib/config/vmframe.hpp @@ -30,7 +30,6 @@ struct VMFrame { Dictionary::Ptr Locals; Object::Ptr Self; - Value Result; VMFrame(void) : Locals(new Dictionary()), Self(Locals) diff --git a/lib/config/vmops.hpp b/lib/config/vmops.hpp index a44ac019c..f2d2f5d44 100644 --- a/lib/config/vmops.hpp +++ b/lib/config/vmops.hpp @@ -295,8 +295,14 @@ private: for (std::vector::size_type i = 0; i < std::min(arguments.size(), funcargs.size()); i++) frame.Locals->Set(funcargs[i], arguments[i]); - expr->Evaluate(frame); - return frame.Result; + Value result; + try { + result = expr->Evaluate(frame); + } catch (const InterruptExecutionError& iee) { + result = iee.GetResult(); + } + + return result; } static inline void SlotWrapper(const Value& funcName, const std::vector& arguments) diff --git a/test/config-ops.cpp b/test/config-ops.cpp index cffdec550..db3d44806 100644 --- a/test/config-ops.cpp +++ b/test/config-ops.cpp @@ -226,6 +226,14 @@ BOOST_AUTO_TEST_CASE(advanced) expr = ConfigCompiler::CompileText("", "a = 3 b = 3"); BOOST_CHECK(expr == NULL); + + expr = ConfigCompiler::CompileText("", "__function() { 3 }()"); + BOOST_CHECK(expr->Evaluate(frame) == 3); + delete expr; + + expr = ConfigCompiler::CompileText("", "__function() { __return 3, 5 }()"); + BOOST_CHECK(expr->Evaluate(frame) == 3); + delete expr; } BOOST_AUTO_TEST_SUITE_END()