Forráskód Böngészése

LibJS: Add support for do..while statements

Andreas Kling 5 éve
szülő
commit
f8393b80e3

+ 24 - 0
Libraries/LibJS/AST.cpp

@@ -177,6 +177,20 @@ Value WhileStatement::execute(Interpreter& interpreter) const
     return last_value;
     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
 Value ForStatement::execute(Interpreter& interpreter) const
 {
 {
     RefPtr<BlockStatement> wrapper;
     RefPtr<BlockStatement> wrapper;
@@ -568,6 +582,16 @@ void WhileStatement::dump(int indent) const
     body().dump(indent + 1);
     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
 void ForStatement::dump(int indent) const
 {
 {
     ASTNode::dump(indent);
     ASTNode::dump(indent);

+ 21 - 0
Libraries/LibJS/AST.h

@@ -257,6 +257,27 @@ private:
     NonnullRefPtr<ScopeNode> m_body;
     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 {
 class ForStatement : public Statement {
 public:
 public:
     ForStatement(RefPtr<ASTNode> init, RefPtr<Expression> test, RefPtr<Expression> update, NonnullRefPtr<ScopeNode> body)
     ForStatement(RefPtr<ASTNode> init, RefPtr<Expression> test, RefPtr<Expression> update, NonnullRefPtr<ScopeNode> body)

+ 11 - 0
Libraries/LibJS/Parser.cpp

@@ -210,6 +210,8 @@ NonnullRefPtr<Statement> Parser::parse_statement()
         return parse_break_statement();
         return parse_break_statement();
     case TokenType::Switch:
     case TokenType::Switch:
         return parse_switch_statement();
         return parse_switch_statement();
+    case TokenType::Do:
+        return parse_do_while_statement();
     default:
     default:
         if (match_expression())
         if (match_expression())
             return adopt(*new ExpressionStatement(parse_expression(0)));
             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));
     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()
 NonnullRefPtr<SwitchStatement> Parser::parse_switch_statement()
 {
 {
     consume(TokenType::Switch);
     consume(TokenType::Switch);

+ 1 - 0
Libraries/LibJS/Parser.h

@@ -58,6 +58,7 @@ public:
     NonnullRefPtr<SwitchStatement> parse_switch_statement();
     NonnullRefPtr<SwitchStatement> parse_switch_statement();
     NonnullRefPtr<SwitchCase> parse_switch_case();
     NonnullRefPtr<SwitchCase> parse_switch_case();
     NonnullRefPtr<BreakStatement> parse_break_statement();
     NonnullRefPtr<BreakStatement> parse_break_statement();
+    NonnullRefPtr<DoWhileStatement> parse_do_while_statement();
     NonnullRefPtr<ConditionalExpression> parse_conditional_expression(NonnullRefPtr<Expression> test);
     NonnullRefPtr<ConditionalExpression> parse_conditional_expression(NonnullRefPtr<Expression> test);
 
 
     NonnullRefPtr<Expression> parse_expression(int min_precedence, Associativity associate = Associativity::Right);
     NonnullRefPtr<Expression> parse_expression(int min_precedence, Associativity associate = Associativity::Right);

+ 17 - 0
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);
+}