1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-25 16:17:45 +00:00

LibJS: Parse FunctionExpressions

FunctionExpression is mostly like FunctionDeclaration, except the name
is optional. Share the parsing logic in parse_function_node<NodeType>.

This allows us to do nice things like:

    document.addEventListener("DOMContentLoaded", function() {
        alert("Hello friends!");
    });
This commit is contained in:
Andreas Kling 2020-03-19 11:52:56 +01:00
parent b1b4c9844e
commit 07679e347c
3 changed files with 21 additions and 5 deletions

View file

@ -154,6 +154,8 @@ class FunctionDeclaration final
: public Statement : public Statement
, public FunctionNode { , public FunctionNode {
public: public:
static bool must_have_name() { return true; }
FunctionDeclaration(String name, NonnullRefPtr<ScopeNode> body, Vector<String> parameters = {}) FunctionDeclaration(String name, NonnullRefPtr<ScopeNode> body, Vector<String> parameters = {})
: FunctionNode(move(name), move(body), move(parameters)) : FunctionNode(move(name), move(body), move(parameters))
{ {
@ -169,6 +171,8 @@ private:
class FunctionExpression final : public Expression class FunctionExpression final : public Expression
, public FunctionNode { , public FunctionNode {
public: public:
static bool must_have_name() { return false; }
FunctionExpression(String name, NonnullRefPtr<ScopeNode> body, Vector<String> parameters = {}) FunctionExpression(String name, NonnullRefPtr<ScopeNode> body, Vector<String> parameters = {})
: FunctionNode(move(name), move(body), move(parameters)) : FunctionNode(move(name), move(body), move(parameters))
{ {

View file

@ -187,7 +187,7 @@ NonnullRefPtr<Statement> Parser::parse_statement()
switch (m_current_token.type()) { switch (m_current_token.type()) {
case TokenType::Function: case TokenType::Function:
return parse_function_declaration(); return parse_function_node<FunctionDeclaration>();
case TokenType::CurlyOpen: case TokenType::CurlyOpen:
return parse_block_statement(); return parse_block_statement();
case TokenType::Return: case TokenType::Return:
@ -231,6 +231,8 @@ NonnullRefPtr<Expression> Parser::parse_primary_expression()
return create_ast_node<UndefinedLiteral>(); return create_ast_node<UndefinedLiteral>();
case TokenType::CurlyOpen: case TokenType::CurlyOpen:
return parse_object_expression(); return parse_object_expression();
case TokenType::Function:
return parse_function_node<FunctionExpression>();
default: default:
m_has_errors = true; m_has_errors = true;
expected("primary expression (missing switch case)"); expected("primary expression (missing switch case)");
@ -416,10 +418,17 @@ NonnullRefPtr<BlockStatement> Parser::parse_block_statement()
return block; return block;
} }
NonnullRefPtr<FunctionDeclaration> Parser::parse_function_declaration() template<typename FunctionNodeType>
NonnullRefPtr<FunctionNodeType> Parser::parse_function_node()
{ {
consume(TokenType::Function); consume(TokenType::Function);
auto name = consume(TokenType::Identifier).value(); String name;
if (FunctionNodeType::must_have_name()) {
name = consume(TokenType::Identifier).value();
} else {
if (match(TokenType::Identifier))
name = consume(TokenType::Identifier).value();
}
consume(TokenType::ParenOpen); consume(TokenType::ParenOpen);
Vector<String> parameters; Vector<String> parameters;
while (match(TokenType::Identifier)) { while (match(TokenType::Identifier)) {
@ -432,7 +441,7 @@ NonnullRefPtr<FunctionDeclaration> Parser::parse_function_declaration()
} }
consume(TokenType::ParenClose); consume(TokenType::ParenClose);
auto body = parse_block_statement(); auto body = parse_block_statement();
return create_ast_node<FunctionDeclaration>(name, move(body), move(parameters)); return create_ast_node<FunctionNodeType>(name, move(body), move(parameters));
} }
NonnullRefPtr<VariableDeclaration> Parser::parse_variable_declaration() NonnullRefPtr<VariableDeclaration> Parser::parse_variable_declaration()
@ -526,6 +535,7 @@ bool Parser::match_expression() const
|| type == TokenType::CurlyOpen || type == TokenType::CurlyOpen
|| type == TokenType::BracketOpen || type == TokenType::BracketOpen
|| type == TokenType::ParenOpen || type == TokenType::ParenOpen
|| type == TokenType::Function
|| match_unary_prefixed_expression(); || match_unary_prefixed_expression();
} }

View file

@ -43,10 +43,12 @@ public:
NonnullRefPtr<Program> parse_program(); NonnullRefPtr<Program> parse_program();
template<typename FunctionNodeType>
NonnullRefPtr<FunctionNodeType> parse_function_node();
NonnullRefPtr<Statement> parse_statement(); NonnullRefPtr<Statement> parse_statement();
NonnullRefPtr<BlockStatement> parse_block_statement(); NonnullRefPtr<BlockStatement> parse_block_statement();
NonnullRefPtr<ReturnStatement> parse_return_statement(); NonnullRefPtr<ReturnStatement> parse_return_statement();
NonnullRefPtr<FunctionDeclaration> parse_function_declaration();
NonnullRefPtr<VariableDeclaration> parse_variable_declaration(); NonnullRefPtr<VariableDeclaration> parse_variable_declaration();
NonnullRefPtr<ForStatement> parse_for_statement(); NonnullRefPtr<ForStatement> parse_for_statement();