summaryrefslogtreecommitdiff
path: root/Libraries
diff options
context:
space:
mode:
authorAndreas Kling <kling@serenityos.org>2020-03-19 11:52:56 +0100
committerAndreas Kling <kling@serenityos.org>2020-03-19 11:54:11 +0100
commit07679e347cbe58aa90ea039013c0f884cf9ee7b2 (patch)
treeff2ab3fa4aaf7cc11d9fdf23c1b9481d24fa8fd4 /Libraries
parentb1b4c9844e63a65a19f5772c614df29015b37ce1 (diff)
downloadserenity-07679e347cbe58aa90ea039013c0f884cf9ee7b2.zip
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!"); });
Diffstat (limited to 'Libraries')
-rw-r--r--Libraries/LibJS/AST.h4
-rw-r--r--Libraries/LibJS/Parser.cpp18
-rw-r--r--Libraries/LibJS/Parser.h4
3 files changed, 21 insertions, 5 deletions
diff --git a/Libraries/LibJS/AST.h b/Libraries/LibJS/AST.h
index 4b942fc8bb..5fe383a315 100644
--- a/Libraries/LibJS/AST.h
+++ b/Libraries/LibJS/AST.h
@@ -154,6 +154,8 @@ class FunctionDeclaration final
: public Statement
, public FunctionNode {
public:
+ static bool must_have_name() { return true; }
+
FunctionDeclaration(String name, NonnullRefPtr<ScopeNode> body, Vector<String> parameters = {})
: FunctionNode(move(name), move(body), move(parameters))
{
@@ -169,6 +171,8 @@ private:
class FunctionExpression final : public Expression
, public FunctionNode {
public:
+ static bool must_have_name() { return false; }
+
FunctionExpression(String name, NonnullRefPtr<ScopeNode> body, Vector<String> parameters = {})
: FunctionNode(move(name), move(body), move(parameters))
{
diff --git a/Libraries/LibJS/Parser.cpp b/Libraries/LibJS/Parser.cpp
index 051fec8983..e474abb6ed 100644
--- a/Libraries/LibJS/Parser.cpp
+++ b/Libraries/LibJS/Parser.cpp
@@ -187,7 +187,7 @@ NonnullRefPtr<Statement> Parser::parse_statement()
switch (m_current_token.type()) {
case TokenType::Function:
- return parse_function_declaration();
+ return parse_function_node<FunctionDeclaration>();
case TokenType::CurlyOpen:
return parse_block_statement();
case TokenType::Return:
@@ -231,6 +231,8 @@ NonnullRefPtr<Expression> Parser::parse_primary_expression()
return create_ast_node<UndefinedLiteral>();
case TokenType::CurlyOpen:
return parse_object_expression();
+ case TokenType::Function:
+ return parse_function_node<FunctionExpression>();
default:
m_has_errors = true;
expected("primary expression (missing switch case)");
@@ -416,10 +418,17 @@ NonnullRefPtr<BlockStatement> Parser::parse_block_statement()
return block;
}
-NonnullRefPtr<FunctionDeclaration> Parser::parse_function_declaration()
+template<typename FunctionNodeType>
+NonnullRefPtr<FunctionNodeType> Parser::parse_function_node()
{
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);
Vector<String> parameters;
while (match(TokenType::Identifier)) {
@@ -432,7 +441,7 @@ NonnullRefPtr<FunctionDeclaration> Parser::parse_function_declaration()
}
consume(TokenType::ParenClose);
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()
@@ -526,6 +535,7 @@ bool Parser::match_expression() const
|| type == TokenType::CurlyOpen
|| type == TokenType::BracketOpen
|| type == TokenType::ParenOpen
+ || type == TokenType::Function
|| match_unary_prefixed_expression();
}
diff --git a/Libraries/LibJS/Parser.h b/Libraries/LibJS/Parser.h
index 229c507e11..6115c9424b 100644
--- a/Libraries/LibJS/Parser.h
+++ b/Libraries/LibJS/Parser.h
@@ -43,10 +43,12 @@ public:
NonnullRefPtr<Program> parse_program();
+ template<typename FunctionNodeType>
+ NonnullRefPtr<FunctionNodeType> parse_function_node();
+
NonnullRefPtr<Statement> parse_statement();
NonnullRefPtr<BlockStatement> parse_block_statement();
NonnullRefPtr<ReturnStatement> parse_return_statement();
- NonnullRefPtr<FunctionDeclaration> parse_function_declaration();
NonnullRefPtr<VariableDeclaration> parse_variable_declaration();
NonnullRefPtr<ForStatement> parse_for_statement();