diff options
author | Ali Mohammad Pur <ali.mpfard@gmail.com> | 2021-06-11 01:38:30 +0430 |
---|---|---|
committer | Andreas Kling <kling@serenityos.org> | 2021-06-11 00:30:09 +0200 |
commit | 3234697ecacb41e15e230a450f2759f404c8b047 (patch) | |
tree | 54b9b4de011c95644a4ceb3ce694b79bdcf0ce49 /Userland/Libraries/LibJS/Parser.cpp | |
parent | c53a86a3fe530d6adaa095944a59a8a0333be3c6 (diff) | |
download | serenity-3234697ecacb41e15e230a450f2759f404c8b047.zip |
LibJS: Implement generator functions (only in bytecode mode)
Diffstat (limited to 'Userland/Libraries/LibJS/Parser.cpp')
-rw-r--r-- | Userland/Libraries/LibJS/Parser.cpp | 29 |
1 files changed, 26 insertions, 3 deletions
diff --git a/Userland/Libraries/LibJS/Parser.cpp b/Userland/Libraries/LibJS/Parser.cpp index c1a8051f94..bca6539426 100644 --- a/Userland/Libraries/LibJS/Parser.cpp +++ b/Userland/Libraries/LibJS/Parser.cpp @@ -590,9 +590,9 @@ NonnullRefPtr<ClassExpression> Parser::parse_class_expression(bool expect_class_ constructor_body->append(create_ast_node<ExpressionStatement>({ m_parser_state.m_current_token.filename(), rule_start.position(), position() }, move(super_call))); constructor_body->add_variables(m_parser_state.m_var_scopes.last()); - constructor = create_ast_node<FunctionExpression>({ m_parser_state.m_current_token.filename(), rule_start.position(), position() }, class_name, move(constructor_body), Vector { FunctionNode::Parameter { FlyString { "args" }, nullptr, true } }, 0, NonnullRefPtrVector<VariableDeclaration>(), true); + constructor = create_ast_node<FunctionExpression>({ m_parser_state.m_current_token.filename(), rule_start.position(), position() }, class_name, move(constructor_body), Vector { FunctionNode::Parameter { FlyString { "args" }, nullptr, true } }, 0, NonnullRefPtrVector<VariableDeclaration>(), false, true); } else { - constructor = create_ast_node<FunctionExpression>({ m_parser_state.m_current_token.filename(), rule_start.position(), position() }, class_name, move(constructor_body), Vector<FunctionNode::Parameter> {}, 0, NonnullRefPtrVector<VariableDeclaration>(), true); + constructor = create_ast_node<FunctionExpression>({ m_parser_state.m_current_token.filename(), rule_start.position(), position() }, class_name, move(constructor_body), Vector<FunctionNode::Parameter> {}, 0, NonnullRefPtrVector<VariableDeclaration>(), false, true); } } @@ -634,6 +634,7 @@ NonnullRefPtr<Expression> Parser::parse_primary_expression() syntax_error("'super' keyword unexpected here"); return create_ast_node<SuperExpression>({ m_parser_state.m_current_token.filename(), rule_start.position(), position() }); case TokenType::Identifier: { + read_as_identifier:; if (!try_parse_arrow_function_expression_failed_at_position(position())) { auto arrow_function_result = try_parse_arrow_function_expression(false); if (!arrow_function_result.is_null()) @@ -674,6 +675,10 @@ NonnullRefPtr<Expression> Parser::parse_primary_expression() } return parse_new_expression(); } + case TokenType::Yield: + if (!m_parser_state.m_in_generator_function_context) + goto read_as_identifier; + return parse_yield_expression(); default: expected("primary expression"); consume(); @@ -1256,6 +1261,16 @@ NonnullRefPtr<NewExpression> Parser::parse_new_expression() return create_ast_node<NewExpression>({ m_parser_state.m_current_token.filename(), rule_start.position(), position() }, move(callee), move(arguments)); } +NonnullRefPtr<YieldExpression> Parser::parse_yield_expression() +{ + auto rule_start = push_start(); + consume(TokenType::Yield); + RefPtr<Expression> argument; + if (match_expression()) + argument = parse_expression(0); + return create_ast_node<YieldExpression>({ m_parser_state.m_current_token.filename(), rule_start.position(), position() }, move(argument)); +} + NonnullRefPtr<ReturnStatement> Parser::parse_return_statement() { auto rule_start = push_start(); @@ -1336,9 +1351,14 @@ NonnullRefPtr<FunctionNodeType> Parser::parse_function_node(u8 parse_options) ScopePusher scope(*this, ScopePusher::Var | ScopePusher::Function); + auto is_generator = false; String name; if (parse_options & FunctionNodeParseOptions::CheckForFunctionAndName) { consume(TokenType::Function); + is_generator = match(TokenType::Asterisk); + if (is_generator) + consume(TokenType::Asterisk); + if (FunctionNodeType::must_have_name() || match(TokenType::Identifier)) name = consume(TokenType::Identifier).value(); } @@ -1351,6 +1371,7 @@ NonnullRefPtr<FunctionNodeType> Parser::parse_function_node(u8 parse_options) function_length = parameters.size(); TemporaryChange change(m_parser_state.m_in_function_context, true); + TemporaryChange generator_change(m_parser_state.m_in_generator_function_context, m_parser_state.m_in_generator_function_context || is_generator); auto old_labels_in_scope = move(m_parser_state.m_labels_in_scope); ScopeGuard guard([&]() { m_parser_state.m_labels_in_scope = move(old_labels_in_scope); @@ -1360,7 +1381,7 @@ NonnullRefPtr<FunctionNodeType> Parser::parse_function_node(u8 parse_options) auto body = parse_block_statement(is_strict); body->add_variables(m_parser_state.m_var_scopes.last()); body->add_functions(m_parser_state.m_function_scopes.last()); - return create_ast_node<FunctionNodeType>({ m_parser_state.m_current_token.filename(), rule_start.position(), position() }, name, move(body), move(parameters), function_length, NonnullRefPtrVector<VariableDeclaration>(), is_strict); + return create_ast_node<FunctionNodeType>({ m_parser_state.m_current_token.filename(), rule_start.position(), position() }, name, move(body), move(parameters), function_length, NonnullRefPtrVector<VariableDeclaration>(), is_generator, is_strict); } Vector<FunctionNode::Parameter> Parser::parse_formal_parameters(int& function_length, u8 parse_options) @@ -2009,6 +2030,7 @@ bool Parser::match_expression() const || type == TokenType::This || type == TokenType::Super || type == TokenType::RegexLiteral + || type == TokenType::Yield || match_unary_prefixed_expression(); } @@ -2085,6 +2107,7 @@ bool Parser::match_statement() const auto type = m_parser_state.m_current_token.type(); return match_expression() || type == TokenType::Return + || type == TokenType::Yield || type == TokenType::Do || type == TokenType::If || type == TokenType::Throw |