diff options
author | Conrad Pankoff <deoxxa@fknsrs.biz> | 2020-03-12 23:12:12 +1100 |
---|---|---|
committer | Andreas Kling <kling@serenityos.org> | 2020-03-12 13:42:23 +0100 |
commit | 097e1af4e878dce6eed13126ca3684df15643483 (patch) | |
tree | bf79928aa88a8ed0a02cd26e0f11463e99be8665 | |
parent | e88f2f15ee829590dbc0a53e03d8a3acfba97db1 (diff) | |
download | serenity-097e1af4e878dce6eed13126ca3684df15643483.zip |
LibJS: Implement for statement
-rw-r--r-- | Libraries/LibJS/AST.cpp | 39 | ||||
-rw-r--r-- | Libraries/LibJS/AST.h | 27 | ||||
-rw-r--r-- | Libraries/LibJS/Lexer.cpp | 1 | ||||
-rw-r--r-- | Libraries/LibJS/Parser.cpp | 50 | ||||
-rw-r--r-- | Libraries/LibJS/Parser.h | 1 | ||||
-rw-r--r-- | Libraries/LibJS/Token.h | 1 |
6 files changed, 119 insertions, 0 deletions
diff --git a/Libraries/LibJS/AST.cpp b/Libraries/LibJS/AST.cpp index 436980ec55..1bb47b24f1 100644 --- a/Libraries/LibJS/AST.cpp +++ b/Libraries/LibJS/AST.cpp @@ -105,6 +105,30 @@ Value WhileStatement::execute(Interpreter& interpreter) const return last_value; } +Value ForStatement::execute(Interpreter& interpreter) const +{ + Value last_value = js_undefined(); + + if (m_init) + m_init->execute(interpreter); + + if (m_test) { + while (m_test->execute(interpreter).to_boolean()) { + last_value = interpreter.run(*m_body); + if (m_update) + m_update->execute(interpreter); + } + } else { + while (true) { + last_value = interpreter.run(*m_body); + if (m_update) + m_update->execute(interpreter); + } + } + + return last_value; +} + Value BinaryExpression::execute(Interpreter& interpreter) const { auto lhs_result = m_lhs->execute(interpreter); @@ -362,6 +386,21 @@ void WhileStatement::dump(int indent) const body().dump(indent + 1); } +void ForStatement::dump(int indent) const +{ + ASTNode::dump(indent); + + print_indent(indent); + printf("For\n"); + if (init()) + init()->dump(indent + 1); + if (test()) + test()->dump(indent + 1); + if (update()) + update()->dump(indent + 1); + body().dump(indent + 1); +} + Value Identifier::execute(Interpreter& interpreter) const { return interpreter.get_variable(string()); diff --git a/Libraries/LibJS/AST.h b/Libraries/LibJS/AST.h index 6c3f11b8f1..8821c5ceaf 100644 --- a/Libraries/LibJS/AST.h +++ b/Libraries/LibJS/AST.h @@ -211,6 +211,33 @@ private: NonnullOwnPtr<ScopeNode> m_body; }; +class ForStatement : public Statement { +public: + ForStatement(OwnPtr<Statement> init, OwnPtr<Expression> test, OwnPtr<Expression> update, NonnullOwnPtr<ScopeNode> body) + : m_init(move(init)) + , m_test(move(test)) + , m_update(move(update)) + , m_body(move(body)) + { + } + + const Statement* init() const { return m_init; } + const Expression* test() const { return m_test; } + const Expression* update() const { return m_update; } + 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 "ForStatement"; } + + OwnPtr<Statement> m_init; + OwnPtr<Expression> m_test; + OwnPtr<Expression> m_update; + NonnullOwnPtr<ScopeNode> m_body; +}; + enum class BinaryOp { Plus, Minus, diff --git a/Libraries/LibJS/Lexer.cpp b/Libraries/LibJS/Lexer.cpp index a3e95974e0..d928d17db2 100644 --- a/Libraries/LibJS/Lexer.cpp +++ b/Libraries/LibJS/Lexer.cpp @@ -51,6 +51,7 @@ Lexer::Lexer(StringView source) s_keywords.set("do", TokenType::Do); s_keywords.set("else", TokenType::Else); s_keywords.set("finally", TokenType::Finally); + s_keywords.set("for", TokenType::For); s_keywords.set("function", TokenType::Function); s_keywords.set("if", TokenType::If); s_keywords.set("interface", TokenType::Interface); diff --git a/Libraries/LibJS/Parser.cpp b/Libraries/LibJS/Parser.cpp index 8c79857606..f00c8c2efb 100644 --- a/Libraries/LibJS/Parser.cpp +++ b/Libraries/LibJS/Parser.cpp @@ -66,6 +66,8 @@ NonnullOwnPtr<Statement> Parser::parse_statement() return parse_return_statement(); case TokenType::Var: return parse_variable_declaration(); + case TokenType::For: + return parse_for_statement(); default: m_has_errors = true; expected("statement (missing switch case)"); @@ -251,6 +253,53 @@ NonnullOwnPtr<VariableDeclaration> Parser::parse_variable_declaration() return make<VariableDeclaration>(make<Identifier>(name), move(initializer), DeclarationType::Var); } +NonnullOwnPtr<ForStatement> Parser::parse_for_statement() +{ + consume(TokenType::For); + + consume(TokenType::ParenOpen); + + OwnPtr<Statement> init = nullptr; + switch (m_current_token.type()) { + case TokenType::Var: + init = parse_variable_declaration(); + break; + case TokenType::Semicolon: + break; + default: + init = parse_statement(); + break; + } + + consume(TokenType::Semicolon); + + OwnPtr<Expression> test = nullptr; + switch (m_current_token.type()) { + case TokenType::Semicolon: + break; + default: + test = parse_expression(); + break; + } + + consume(TokenType::Semicolon); + + OwnPtr<Expression> update = nullptr; + switch (m_current_token.type()) { + case TokenType::Semicolon: + break; + default: + update = parse_expression(); + break; + } + + consume(TokenType::ParenClose); + + auto body = parse_block_statement(); + + return make<ForStatement>(move(init), move(test), move(update), move(body)); +} + bool Parser::match(TokenType type) const { return m_current_token.type() == type; @@ -306,6 +355,7 @@ bool Parser::match_statement() const || type == TokenType::If || type == TokenType::Try || type == TokenType::While + || type == TokenType::For || type == TokenType::Const || type == TokenType::CurlyOpen || type == TokenType::Var; diff --git a/Libraries/LibJS/Parser.h b/Libraries/LibJS/Parser.h index 1800004c16..e979a1d7d9 100644 --- a/Libraries/LibJS/Parser.h +++ b/Libraries/LibJS/Parser.h @@ -42,6 +42,7 @@ public: NonnullOwnPtr<ReturnStatement> parse_return_statement(); NonnullOwnPtr<FunctionDeclaration> parse_function_declaration(); NonnullOwnPtr<VariableDeclaration> parse_variable_declaration(); + NonnullOwnPtr<ForStatement> parse_for_statement(); NonnullOwnPtr<Expression> parse_expression(); NonnullOwnPtr<Expression> parse_primary_expression(); diff --git a/Libraries/LibJS/Token.h b/Libraries/LibJS/Token.h index 02d901ee52..9a7463ce51 100644 --- a/Libraries/LibJS/Token.h +++ b/Libraries/LibJS/Token.h @@ -58,6 +58,7 @@ enum class TokenType { ExclamationMarkEquals, ExclamationMarkEqualsEquals, Finally, + For, Function, GreaterThan, GreaterThanEquals, |