diff options
author | Andreas Kling <kling@serenityos.org> | 2020-03-23 16:46:41 +0100 |
---|---|---|
committer | Andreas Kling <kling@serenityos.org> | 2020-03-23 16:52:58 +0100 |
commit | fbb9e1b71507acefec54f8fbee68fa6b6d8a4512 (patch) | |
tree | a8cfda6e367a0f913d8817fe0e76bea8444b075f | |
parent | b2f005125debe74051bf74d773c15efa39bbb949 (diff) | |
download | serenity-fbb9e1b71507acefec54f8fbee68fa6b6d8a4512.zip |
LibJS: Implement "else" parsing
We can now handle scripts with if/else in LibJS. Most of the changes
are about fixing IfStatement to store the consequent and alternate node
as Statements.
Interpreter now also runs Statements, rather than running ScopeNodes.
-rw-r--r-- | Libraries/LibJS/AST.h | 14 | ||||
-rw-r--r-- | Libraries/LibJS/Forward.h | 1 | ||||
-rw-r--r-- | Libraries/LibJS/Interpreter.cpp | 12 | ||||
-rw-r--r-- | Libraries/LibJS/Interpreter.h | 2 | ||||
-rw-r--r-- | Libraries/LibJS/Parser.cpp | 18 |
5 files changed, 31 insertions, 16 deletions
diff --git a/Libraries/LibJS/AST.h b/Libraries/LibJS/AST.h index 3d58f0b395..3f5e58bec5 100644 --- a/Libraries/LibJS/AST.h +++ b/Libraries/LibJS/AST.h @@ -26,11 +26,11 @@ #pragma once +#include <AK/FlyString.h> #include <AK/HashMap.h> #include <AK/NonnullRefPtrVector.h> #include <AK/RefPtr.h> #include <AK/String.h> -#include <AK/FlyString.h> #include <AK/Vector.h> #include <LibJS/Forward.h> #include <LibJS/Runtime/Value.h> @@ -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<Statement> m_children; }; @@ -212,7 +214,7 @@ private: class IfStatement : public Statement { public: - IfStatement(NonnullRefPtr<Expression> predicate, NonnullRefPtr<ScopeNode> consequent, RefPtr<ScopeNode> alternate) + IfStatement(NonnullRefPtr<Expression> predicate, NonnullRefPtr<Statement> consequent, RefPtr<Statement> 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<Expression> m_predicate; - NonnullRefPtr<ScopeNode> m_consequent; - RefPtr<ScopeNode> m_alternate; + NonnullRefPtr<Statement> m_consequent; + RefPtr<Statement> m_alternate; }; class WhileStatement : public Statement { diff --git a/Libraries/LibJS/Forward.h b/Libraries/LibJS/Forward.h index 8e1febcfcd..359d6f6ab4 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 47a63646d1..ac80f688b0 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<Argument> arguments, ScopeType scope_type) +Value Interpreter::run(const Statement& statement, Vector<Argument> 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<const BlockStatement&>(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 4c749fcd0e..1aa7b87f05 100644 --- a/Libraries/LibJS/Interpreter.h +++ b/Libraries/LibJS/Interpreter.h @@ -67,7 +67,7 @@ public: Interpreter(); ~Interpreter(); - Value run(const ScopeNode&, Vector<Argument> = {}, ScopeType = ScopeType::Block); + Value run(const Statement&, Vector<Argument> = {}, 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 6b5a09cb18..a6532fb775 100644 --- a/Libraries/LibJS/Parser.cpp +++ b/Libraries/LibJS/Parser.cpp @@ -197,8 +197,12 @@ NonnullRefPtr<Statement> 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<IfStatement> 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<IfStatement>(move(predicate), move(consequent), nullptr); + auto consequent = parse_statement(); + RefPtr<Statement> alternate; + if (match(TokenType::Else)) { + consume(TokenType::Else); + alternate = parse_statement(); + } + return create_ast_node<IfStatement>(move(predicate), move(consequent), move(alternate)); } NonnullRefPtr<ForStatement> Parser::parse_for_statement() |