1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-25 05:47:35 +00:00

LibJS: Implement generator functions (only in bytecode mode)

This commit is contained in:
Ali Mohammad Pur 2021-06-11 01:38:30 +04:30 committed by Andreas Kling
parent c53a86a3fe
commit 3234697eca
21 changed files with 407 additions and 34 deletions

View file

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