diff --git a/Libraries/LibJS/AST.h b/Libraries/LibJS/AST.h index 3d58f0b395d..3f5e58bec59 100644 --- a/Libraries/LibJS/AST.h +++ b/Libraries/LibJS/AST.h @@ -26,11 +26,11 @@ #pragma once +#include #include #include #include #include -#include #include #include #include @@ -52,6 +52,7 @@ public: virtual void dump(int indent) const; virtual bool is_identifier() const { return false; } virtual bool is_member_expression() const { return false; } + virtual bool is_scope_node() const { return false; } protected: ASTNode() {} @@ -107,6 +108,7 @@ protected: ScopeNode() {} private: + virtual bool is_scope_node() const final { return true; } NonnullRefPtrVector m_children; }; @@ -212,7 +214,7 @@ private: class IfStatement : public Statement { public: - IfStatement(NonnullRefPtr predicate, NonnullRefPtr consequent, RefPtr alternate) + IfStatement(NonnullRefPtr predicate, NonnullRefPtr consequent, RefPtr alternate) : m_predicate(move(predicate)) , m_consequent(move(consequent)) , m_alternate(move(alternate)) @@ -220,8 +222,8 @@ public: } const Expression& predicate() const { return *m_predicate; } - const ScopeNode& consequent() const { return *m_consequent; } - const ScopeNode* alternate() const { return m_alternate; } + const Statement& consequent() const { return *m_consequent; } + const Statement* alternate() const { return m_alternate; } virtual Value execute(Interpreter&) const override; virtual void dump(int indent) const override; @@ -230,8 +232,8 @@ private: virtual const char* class_name() const override { return "IfStatement"; } NonnullRefPtr m_predicate; - NonnullRefPtr m_consequent; - RefPtr m_alternate; + NonnullRefPtr m_consequent; + RefPtr m_alternate; }; class WhileStatement : public Statement { diff --git a/Libraries/LibJS/Forward.h b/Libraries/LibJS/Forward.h index 8e1febcfcd8..359d6f6ab4d 100644 --- a/Libraries/LibJS/Forward.h +++ b/Libraries/LibJS/Forward.h @@ -40,6 +40,7 @@ class Interpreter; class Object; class PrimitiveString; class ScopeNode; +class Statement; class Value; enum class DeclarationType; diff --git a/Libraries/LibJS/Interpreter.cpp b/Libraries/LibJS/Interpreter.cpp index 47a63646d1b..ac80f688b07 100644 --- a/Libraries/LibJS/Interpreter.cpp +++ b/Libraries/LibJS/Interpreter.cpp @@ -50,16 +50,20 @@ Interpreter::~Interpreter() { } -Value Interpreter::run(const ScopeNode& scope_node, Vector arguments, ScopeType scope_type) +Value Interpreter::run(const Statement& statement, Vector arguments, ScopeType scope_type) { - enter_scope(scope_node, move(arguments), scope_type); + if (!statement.is_scope_node()) + return statement.execute(*this); + + auto& block = static_cast(statement); + enter_scope(block, move(arguments), scope_type); Value last_value = js_undefined(); - for (auto& node : scope_node.children()) { + for (auto& node : block.children()) { last_value = node.execute(*this); } - exit_scope(scope_node); + exit_scope(block); return last_value; } diff --git a/Libraries/LibJS/Interpreter.h b/Libraries/LibJS/Interpreter.h index 4c749fcd0eb..1aa7b87f05a 100644 --- a/Libraries/LibJS/Interpreter.h +++ b/Libraries/LibJS/Interpreter.h @@ -67,7 +67,7 @@ public: Interpreter(); ~Interpreter(); - Value run(const ScopeNode&, Vector = {}, ScopeType = ScopeType::Block); + Value run(const Statement&, Vector = {}, ScopeType = ScopeType::Block); Object& global_object() { return *m_global_object; } const Object& global_object() const { return *m_global_object; } diff --git a/Libraries/LibJS/Parser.cpp b/Libraries/LibJS/Parser.cpp index 6b5a09cb18d..a6532fb7752 100644 --- a/Libraries/LibJS/Parser.cpp +++ b/Libraries/LibJS/Parser.cpp @@ -197,8 +197,12 @@ NonnullRefPtr Parser::parse_statement() case TokenType::If: return parse_if_statement(); default: - if (match_expression()) - return adopt(*new ExpressionStatement(parse_expression(0))); + if (match_expression()) { + auto statement = adopt(*new ExpressionStatement(parse_expression(0))); + if (match(TokenType::Semicolon)) + consume(); + return statement; + } m_has_errors = true; expected("statement (missing switch case)"); consume(); @@ -520,9 +524,13 @@ NonnullRefPtr Parser::parse_if_statement() consume(TokenType::ParenOpen); auto predicate = parse_expression(0); consume(TokenType::ParenClose); - auto consequent = parse_block_statement(); - // FIXME: Parse "else" - return create_ast_node(move(predicate), move(consequent), nullptr); + auto consequent = parse_statement(); + RefPtr alternate; + if (match(TokenType::Else)) { + consume(TokenType::Else); + alternate = parse_statement(); + } + return create_ast_node(move(predicate), move(consequent), move(alternate)); } NonnullRefPtr Parser::parse_for_statement()