summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndreas Kling <kling@serenityos.org>2020-04-04 21:29:23 +0200
committerAndreas Kling <kling@serenityos.org>2020-04-04 21:29:23 +0200
commitf8393b80e302b80b20198ea53b3c29342faf4003 (patch)
tree9966d41098a022f64001756f4dc33bd42048c406
parentda0715aba96b85a6df23854960ebb3382fa0cf1f (diff)
downloadserenity-f8393b80e302b80b20198ea53b3c29342faf4003.zip
LibJS: Add support for do..while statements
-rw-r--r--Libraries/LibJS/AST.cpp24
-rw-r--r--Libraries/LibJS/AST.h21
-rw-r--r--Libraries/LibJS/Parser.cpp11
-rw-r--r--Libraries/LibJS/Parser.h1
-rw-r--r--Libraries/LibJS/Tests/do-while-basic.js17
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);
+}