LibJS: Implement for statement

This commit is contained in:
Conrad Pankoff 2020-03-12 23:12:12 +11:00 committed by Andreas Kling
parent e88f2f15ee
commit 097e1af4e8
Notes: sideshowbarker 2024-07-19 08:44:52 +09:00
6 changed files with 119 additions and 0 deletions

View file

@ -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());

View file

@ -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,

View file

@ -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);

View file

@ -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;

View file

@ -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();

View file

@ -58,6 +58,7 @@ enum class TokenType {
ExclamationMarkEquals,
ExclamationMarkEqualsEquals,
Finally,
For,
Function,
GreaterThan,
GreaterThanEquals,