diff options
author | Andreas Kling <kling@serenityos.org> | 2020-04-04 21:29:23 +0200 |
---|---|---|
committer | Andreas Kling <kling@serenityos.org> | 2020-04-04 21:29:23 +0200 |
commit | f8393b80e302b80b20198ea53b3c29342faf4003 (patch) | |
tree | 9966d41098a022f64001756f4dc33bd42048c406 | |
parent | da0715aba96b85a6df23854960ebb3382fa0cf1f (diff) | |
download | serenity-f8393b80e302b80b20198ea53b3c29342faf4003.zip |
LibJS: Add support for do..while statements
-rw-r--r-- | Libraries/LibJS/AST.cpp | 24 | ||||
-rw-r--r-- | Libraries/LibJS/AST.h | 21 | ||||
-rw-r--r-- | Libraries/LibJS/Parser.cpp | 11 | ||||
-rw-r--r-- | Libraries/LibJS/Parser.h | 1 | ||||
-rw-r--r-- | Libraries/LibJS/Tests/do-while-basic.js | 17 |
5 files changed, 74 insertions, 0 deletions
diff --git a/Libraries/LibJS/AST.cpp b/Libraries/LibJS/AST.cpp index 1b4cd0d76b..978ede3922 100644 --- a/Libraries/LibJS/AST.cpp +++ b/Libraries/LibJS/AST.cpp @@ -177,6 +177,20 @@ Value WhileStatement::execute(Interpreter& interpreter) const return last_value; } +Value DoWhileStatement::execute(Interpreter& interpreter) const +{ + Value last_value = js_undefined(); + do { + if (interpreter.exception()) + return {}; + last_value = interpreter.run(*m_body); + if (interpreter.exception()) + return {}; + } while (m_test->execute(interpreter).to_boolean()); + + return last_value; +} + Value ForStatement::execute(Interpreter& interpreter) const { RefPtr<BlockStatement> wrapper; @@ -568,6 +582,16 @@ void WhileStatement::dump(int indent) const body().dump(indent + 1); } +void DoWhileStatement::dump(int indent) const +{ + ASTNode::dump(indent); + + print_indent(indent); + printf("DoWhile\n"); + test().dump(indent + 1); + body().dump(indent + 1); +} + void ForStatement::dump(int indent) const { ASTNode::dump(indent); diff --git a/Libraries/LibJS/AST.h b/Libraries/LibJS/AST.h index 2b7e3aeb1d..6f6d7eec59 100644 --- a/Libraries/LibJS/AST.h +++ b/Libraries/LibJS/AST.h @@ -257,6 +257,27 @@ private: NonnullRefPtr<ScopeNode> m_body; }; +class DoWhileStatement : public Statement { +public: + DoWhileStatement(NonnullRefPtr<Expression> test, NonnullRefPtr<ScopeNode> body) + : m_test(move(test)) + , m_body(move(body)) + { + } + + const Expression& test() const { return *m_test; } + const ScopeNode& body() const { return *m_body; } + + virtual Value execute(Interpreter&) const override; + virtual void dump(int indent) const override; + +private: + virtual const char* class_name() const override { return "DoWhileStatement"; } + + NonnullRefPtr<Expression> m_test; + NonnullRefPtr<ScopeNode> m_body; +}; + class ForStatement : public Statement { public: ForStatement(RefPtr<ASTNode> init, RefPtr<Expression> test, RefPtr<Expression> update, NonnullRefPtr<ScopeNode> body) diff --git a/Libraries/LibJS/Parser.cpp b/Libraries/LibJS/Parser.cpp index 5468432f76..50617f9e2c 100644 --- a/Libraries/LibJS/Parser.cpp +++ b/Libraries/LibJS/Parser.cpp @@ -210,6 +210,8 @@ NonnullRefPtr<Statement> Parser::parse_statement() return parse_break_statement(); case TokenType::Switch: return parse_switch_statement(); + case TokenType::Do: + return parse_do_while_statement(); default: if (match_expression()) return adopt(*new ExpressionStatement(parse_expression(0))); @@ -702,6 +704,15 @@ NonnullRefPtr<TryStatement> Parser::parse_try_statement() return create_ast_node<TryStatement>(move(block), move(handler), move(finalizer)); } +NonnullRefPtr<DoWhileStatement> Parser::parse_do_while_statement() +{ + consume(TokenType::Do); + auto body = parse_statement(); + consume(TokenType::While); + auto test = parse_expression(0); + return create_ast_node<DoWhileStatement>(move(test), move(body)); +} + NonnullRefPtr<SwitchStatement> Parser::parse_switch_statement() { consume(TokenType::Switch); diff --git a/Libraries/LibJS/Parser.h b/Libraries/LibJS/Parser.h index f4e759d4f5..04bfcc85c9 100644 --- a/Libraries/LibJS/Parser.h +++ b/Libraries/LibJS/Parser.h @@ -58,6 +58,7 @@ public: NonnullRefPtr<SwitchStatement> parse_switch_statement(); NonnullRefPtr<SwitchCase> parse_switch_case(); NonnullRefPtr<BreakStatement> parse_break_statement(); + NonnullRefPtr<DoWhileStatement> parse_do_while_statement(); NonnullRefPtr<ConditionalExpression> parse_conditional_expression(NonnullRefPtr<Expression> test); NonnullRefPtr<Expression> parse_expression(int min_precedence, Associativity associate = Associativity::Right); diff --git a/Libraries/LibJS/Tests/do-while-basic.js b/Libraries/LibJS/Tests/do-while-basic.js new file mode 100644 index 0000000000..f0ca39136f --- /dev/null +++ b/Libraries/LibJS/Tests/do-while-basic.js @@ -0,0 +1,17 @@ +function assert(x) { if (!x) throw 1; } + +try { + var number = 0; + do { + number++; + } while (number < 9); + assert(number === 9); + + number = 0; + do number++; while(number < 3); + assert(number === 3); + + console.log("PASS"); +} catch (e) { + console.log("FAIL: " + e); +} |