summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorConrad Pankoff <deoxxa@fknsrs.biz>2020-03-12 23:12:12 +1100
committerAndreas Kling <kling@serenityos.org>2020-03-12 13:42:23 +0100
commit097e1af4e878dce6eed13126ca3684df15643483 (patch)
treebf79928aa88a8ed0a02cd26e0f11463e99be8665
parente88f2f15ee829590dbc0a53e03d8a3acfba97db1 (diff)
downloadserenity-097e1af4e878dce6eed13126ca3684df15643483.zip
LibJS: Implement for statement
-rw-r--r--Libraries/LibJS/AST.cpp39
-rw-r--r--Libraries/LibJS/AST.h27
-rw-r--r--Libraries/LibJS/Lexer.cpp1
-rw-r--r--Libraries/LibJS/Parser.cpp50
-rw-r--r--Libraries/LibJS/Parser.h1
-rw-r--r--Libraries/LibJS/Token.h1
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,