1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-05-31 03:48:13 +00:00

LibJS: Consume semicolon at the end of a statement

A bunch of code was relying on this not happenind, in particular the
parsing of "for" statements. Reorganized things so they work again.
This commit is contained in:
Andreas Kling 2020-03-23 19:08:32 +01:00
parent fbb9e1b715
commit df524203b2
3 changed files with 32 additions and 15 deletions

View file

@ -53,6 +53,7 @@ public:
virtual bool is_identifier() const { return false; } virtual bool is_identifier() const { return false; }
virtual bool is_member_expression() const { return false; } virtual bool is_member_expression() const { return false; }
virtual bool is_scope_node() const { return false; } virtual bool is_scope_node() const { return false; }
virtual bool is_variable_declaration() const { return false; }
protected: protected:
ASTNode() {} ASTNode() {}
@ -61,8 +62,6 @@ private:
}; };
class Statement : public ASTNode { class Statement : public ASTNode {
public:
virtual bool is_variable_declaration() const { return false; }
}; };
class ErrorStatement final : public Statement { class ErrorStatement final : public Statement {
@ -259,7 +258,7 @@ private:
class ForStatement : public Statement { class ForStatement : public Statement {
public: public:
ForStatement(RefPtr<Statement> init, RefPtr<Expression> test, RefPtr<Expression> update, NonnullRefPtr<ScopeNode> body) ForStatement(RefPtr<ASTNode> init, RefPtr<Expression> test, RefPtr<Expression> update, NonnullRefPtr<ScopeNode> body)
: m_init(move(init)) : m_init(move(init))
, m_test(move(test)) , m_test(move(test))
, m_update(move(update)) , m_update(move(update))
@ -267,7 +266,7 @@ public:
{ {
} }
const Statement* init() const { return m_init; } const ASTNode* init() const { return m_init; }
const Expression* test() const { return m_test; } const Expression* test() const { return m_test; }
const Expression* update() const { return m_update; } const Expression* update() const { return m_update; }
const ScopeNode& body() const { return *m_body; } const ScopeNode& body() const { return *m_body; }
@ -278,7 +277,7 @@ public:
private: private:
virtual const char* class_name() const override { return "ForStatement"; } virtual const char* class_name() const override { return "ForStatement"; }
RefPtr<Statement> m_init; RefPtr<ASTNode> m_init;
RefPtr<Expression> m_test; RefPtr<Expression> m_test;
RefPtr<Expression> m_update; RefPtr<Expression> m_update;
NonnullRefPtr<ScopeNode> m_body; NonnullRefPtr<ScopeNode> m_body;

View file

@ -181,6 +181,7 @@ NonnullRefPtr<Program> Parser::parse_program()
NonnullRefPtr<Statement> Parser::parse_statement() NonnullRefPtr<Statement> Parser::parse_statement()
{ {
auto statement = [this]() -> NonnullRefPtr<Statement> {
switch (m_current_token.type()) { switch (m_current_token.type()) {
case TokenType::Function: case TokenType::Function:
return parse_function_node<FunctionDeclaration>(); return parse_function_node<FunctionDeclaration>();
@ -197,17 +198,16 @@ NonnullRefPtr<Statement> Parser::parse_statement()
case TokenType::If: case TokenType::If:
return parse_if_statement(); return parse_if_statement();
default: default:
if (match_expression()) { if (match_expression())
auto statement = adopt(*new ExpressionStatement(parse_expression(0))); return adopt(*new ExpressionStatement(parse_expression(0)));
if (match(TokenType::Semicolon))
consume();
return statement;
}
m_has_errors = true; m_has_errors = true;
expected("statement (missing switch case)"); expected("statement (missing switch case)");
consume(); consume();
return create_ast_node<ErrorStatement>(); return create_ast_node<ErrorStatement>();
} } }();
if (match(TokenType::Semicolon))
consume();
return statement;
} }
NonnullRefPtr<Expression> Parser::parse_primary_expression() NonnullRefPtr<Expression> Parser::parse_primary_expression()
@ -394,7 +394,7 @@ NonnullRefPtr<Expression> Parser::parse_secondary_expression(NonnullRefPtr<Expre
return create_ast_node<MemberExpression>(move(lhs), parse_expression(min_precedence, associativity)); return create_ast_node<MemberExpression>(move(lhs), parse_expression(min_precedence, associativity));
case TokenType::BracketOpen: { case TokenType::BracketOpen: {
consume(TokenType::BracketOpen); consume(TokenType::BracketOpen);
auto expression = create_ast_node<MemberExpression>(move(lhs), parse_expression(min_precedence, associativity), true); auto expression = create_ast_node<MemberExpression>(move(lhs), parse_expression(0), true);
consume(TokenType::BracketClose); consume(TokenType::BracketClose);
return expression; return expression;
} }
@ -539,12 +539,17 @@ NonnullRefPtr<ForStatement> Parser::parse_for_statement()
consume(TokenType::ParenOpen); consume(TokenType::ParenOpen);
RefPtr<Statement> init; RefPtr<ASTNode> init;
switch (m_current_token.type()) { switch (m_current_token.type()) {
case TokenType::Semicolon: case TokenType::Semicolon:
break; break;
default: default:
init = parse_statement(); if (match_expression())
init = parse_expression(0);
else if (match_variable_declaration())
init = parse_variable_declaration();
else
ASSERT_NOT_REACHED();
break; break;
} }
@ -582,6 +587,18 @@ bool Parser::match(TokenType type) const
return m_current_token.type() == type; return m_current_token.type() == type;
} }
bool Parser::match_variable_declaration() const
{
switch (m_current_token.type()) {
case TokenType::Var:
case TokenType::Let:
case TokenType::Const:
return true;
default:
return false;
}
}
bool Parser::match_expression() const bool Parser::match_expression() const
{ {
auto type = m_current_token.type(); auto type = m_current_token.type();

View file

@ -70,6 +70,7 @@ private:
bool match_unary_prefixed_expression() const; bool match_unary_prefixed_expression() const;
bool match_secondary_expression() const; bool match_secondary_expression() const;
bool match_statement() const; bool match_statement() const;
bool match_variable_declaration() const;
bool match(TokenType type) const; bool match(TokenType type) const;
bool done() const; bool done() const;
void expected(const char* what); void expected(const char* what);