diff --git a/doc/15-language-reference.md b/doc/15-language-reference.md index 76c73d8b0..71bfff057 100644 --- a/doc/15-language-reference.md +++ b/doc/15-language-reference.md @@ -668,6 +668,20 @@ This example prints the log message "Taking the 'true' branch" and the `a` varia The value of an if/else construct is null if the condition evaluates to false and no else branch is given. +## While Loops + +The `while` statement checks a condition and executes the loop body when the condition evaluates to `true`. +This is repeated until the condition is no longer true. + +Example: + + var num = 5 + + while (num > 5) { + log("Test") + num -= 1 + } + ## For Loops The `for` statement can be used to iterate over arrays and dictionaries. diff --git a/lib/config/config_lexer.ll b/lib/config/config_lexer.ll index a48555d2f..bfa7a9851 100644 --- a/lib/config/config_lexer.ll +++ b/lib/config/config_lexer.ll @@ -204,6 +204,7 @@ return return T_RETURN; for return T_FOR; if return T_IF; else return T_ELSE; +while return T_WHILE; =\> return T_FOLLOWS; \<\< return T_SHIFT_LEFT; \>\> return T_SHIFT_RIGHT; diff --git a/lib/config/config_parser.yy b/lib/config/config_parser.yy index 798717bf1..6c3b683a3 100644 --- a/lib/config/config_parser.yy +++ b/lib/config/config_parser.yy @@ -174,6 +174,7 @@ static void MakeRBinaryOp(Expression** result, Expression *left, Expression *rig %token T_FOR "for (T_FOR)" %token T_IF "if (T_IF)" %token T_ELSE "else (T_ELSE)" +%token T_WHILE "while (T_WHILE)" %token T_FOLLOWS "=> (T_FOLLOWS)" %type identifier @@ -644,6 +645,13 @@ lterm: type BindToScope(expr, ScopeLocal); $$ = new SetExpression(expr, $3, $4, @$); } + | T_WHILE '(' rterm ')' rterm_scope + { + DictExpression *aloop = dynamic_cast($5); + aloop->MakeInline(); + + $$ = new WhileExpression($3, aloop, @$); + } | rterm_side_effect ; diff --git a/lib/config/expression.cpp b/lib/config/expression.cpp index d254281b8..2fbcfea5e 100644 --- a/lib/config/expression.cpp +++ b/lib/config/expression.cpp @@ -400,6 +400,14 @@ Value ConditionalExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) co return Empty; } +Value WhileExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const +{ + while (m_Condition->Evaluate(frame, dhint).ToBool()) + m_LoopBody->Evaluate(frame, dhint); + + return Empty; +} + Value ReturnExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const { BOOST_THROW_EXCEPTION(InterruptExecutionError(m_Operand->Evaluate(frame))); diff --git a/lib/config/expression.hpp b/lib/config/expression.hpp index b729f6261..72780c880 100644 --- a/lib/config/expression.hpp +++ b/lib/config/expression.hpp @@ -632,6 +632,28 @@ private: Expression *m_FalseBranch; }; +class I2_CONFIG_API WhileExpression : public DebuggableExpression +{ +public: + WhileExpression(Expression *condition, Expression *loop_body, const DebugInfo& debugInfo = DebugInfo()) + : DebuggableExpression(debugInfo), m_Condition(condition), m_LoopBody(loop_body) + { } + + ~WhileExpression(void) + { + delete m_Condition; + delete m_LoopBody; + } + +protected: + virtual Value DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const; + +private: + Expression *m_Condition; + Expression *m_LoopBody; +}; + + class I2_CONFIG_API ReturnExpression : public UnaryExpression { public: