mirror of
https://github.com/RGBCube/serenity
synced 2025-07-26 10:57:34 +00:00
LibJS: Treat yield as an identifier in more non-generator contexts
And disallow some cases where we are in a generator context.
This commit is contained in:
parent
26177b1826
commit
19582ccad8
1 changed files with 27 additions and 9 deletions
|
@ -831,7 +831,10 @@ Parser::PrimaryExpressionParseResult Parser::parse_primary_expression()
|
||||||
auto expression = parse_expression(0);
|
auto expression = parse_expression(0);
|
||||||
consume(TokenType::ParenClose);
|
consume(TokenType::ParenClose);
|
||||||
if (is<FunctionExpression>(*expression)) {
|
if (is<FunctionExpression>(*expression)) {
|
||||||
static_cast<FunctionExpression&>(*expression).set_cannot_auto_rename();
|
auto& function = static_cast<FunctionExpression&>(*expression);
|
||||||
|
function.set_cannot_auto_rename();
|
||||||
|
if (function.kind() == FunctionKind::Generator && function.name() == "yield"sv)
|
||||||
|
syntax_error("function is not allowed to be called 'yield' in this context", function.source_range().start);
|
||||||
}
|
}
|
||||||
return { move(expression) };
|
return { move(expression) };
|
||||||
}
|
}
|
||||||
|
@ -1072,7 +1075,7 @@ NonnullRefPtr<ObjectExpression> Parser::parse_object_expression()
|
||||||
property_type = ObjectProperty::Type::KeyValue;
|
property_type = ObjectProperty::Type::KeyValue;
|
||||||
property_name = parse_property_key();
|
property_name = parse_property_key();
|
||||||
function_kind = FunctionKind ::Generator;
|
function_kind = FunctionKind ::Generator;
|
||||||
} else if (match(TokenType::Identifier)) {
|
} else if (match_identifier()) {
|
||||||
auto identifier = consume().value();
|
auto identifier = consume().value();
|
||||||
if (identifier == "get" && match_property_key()) {
|
if (identifier == "get" && match_property_key()) {
|
||||||
property_type = ObjectProperty::Type::Getter;
|
property_type = ObjectProperty::Type::Getter;
|
||||||
|
@ -1750,6 +1753,8 @@ NonnullRefPtr<FunctionNodeType> Parser::parse_function_node(u8 parse_options)
|
||||||
|
|
||||||
check_identifier_name_for_assignment_validity(name);
|
check_identifier_name_for_assignment_validity(name);
|
||||||
}
|
}
|
||||||
|
TemporaryChange generator_change(m_state.in_generator_function_context, is_generator);
|
||||||
|
|
||||||
consume(TokenType::ParenOpen);
|
consume(TokenType::ParenOpen);
|
||||||
i32 function_length = -1;
|
i32 function_length = -1;
|
||||||
auto parameters = parse_formal_parameters(function_length, parse_options);
|
auto parameters = parse_formal_parameters(function_length, parse_options);
|
||||||
|
@ -1759,7 +1764,7 @@ NonnullRefPtr<FunctionNodeType> Parser::parse_function_node(u8 parse_options)
|
||||||
function_length = parameters.size();
|
function_length = parameters.size();
|
||||||
|
|
||||||
TemporaryChange change(m_state.in_function_context, true);
|
TemporaryChange change(m_state.in_function_context, true);
|
||||||
TemporaryChange generator_change(m_state.in_generator_function_context, m_state.in_generator_function_context || is_generator);
|
|
||||||
auto old_labels_in_scope = move(m_state.labels_in_scope);
|
auto old_labels_in_scope = move(m_state.labels_in_scope);
|
||||||
ScopeGuard guard([&]() {
|
ScopeGuard guard([&]() {
|
||||||
m_state.labels_in_scope = move(old_labels_in_scope);
|
m_state.labels_in_scope = move(old_labels_in_scope);
|
||||||
|
@ -1775,12 +1780,15 @@ NonnullRefPtr<FunctionNodeType> Parser::parse_function_node(u8 parse_options)
|
||||||
auto body = parse_block_statement(is_strict, has_binding);
|
auto body = parse_block_statement(is_strict, has_binding);
|
||||||
|
|
||||||
// If the function contains 'use strict' we need to check the parameters (again).
|
// If the function contains 'use strict' we need to check the parameters (again).
|
||||||
if (is_strict) {
|
if (is_strict || is_generator) {
|
||||||
Vector<StringView> parameter_names;
|
Vector<StringView> parameter_names;
|
||||||
for (auto& parameter : parameters) {
|
for (auto& parameter : parameters) {
|
||||||
parameter.binding.visit(
|
parameter.binding.visit(
|
||||||
[&](FlyString const& parameter_name) {
|
[&](FlyString const& parameter_name) {
|
||||||
check_identifier_name_for_assignment_validity(parameter_name, true);
|
check_identifier_name_for_assignment_validity(parameter_name, is_strict);
|
||||||
|
if (is_generator && parameter_name == "yield"sv)
|
||||||
|
syntax_error("Parameter name 'yield' not allowed in this context");
|
||||||
|
|
||||||
for (auto& previous_name : parameter_names) {
|
for (auto& previous_name : parameter_names) {
|
||||||
if (previous_name == parameter_name) {
|
if (previous_name == parameter_name) {
|
||||||
syntax_error(String::formatted("Duplicate parameter '{}' not allowed in strict mode", parameter_name));
|
syntax_error(String::formatted("Duplicate parameter '{}' not allowed in strict mode", parameter_name));
|
||||||
|
@ -1791,6 +1799,9 @@ NonnullRefPtr<FunctionNodeType> Parser::parse_function_node(u8 parse_options)
|
||||||
},
|
},
|
||||||
[&](NonnullRefPtr<BindingPattern> const& binding) {
|
[&](NonnullRefPtr<BindingPattern> const& binding) {
|
||||||
binding->for_each_bound_name([&](auto& bound_name) {
|
binding->for_each_bound_name([&](auto& bound_name) {
|
||||||
|
if (is_generator && bound_name == "yield"sv)
|
||||||
|
syntax_error("Parameter name 'yield' not allowed in this context");
|
||||||
|
|
||||||
for (auto& previous_name : parameter_names) {
|
for (auto& previous_name : parameter_names) {
|
||||||
if (previous_name == bound_name) {
|
if (previous_name == bound_name) {
|
||||||
syntax_error(String::formatted("Duplicate parameter '{}' not allowed in strict mode", bound_name));
|
syntax_error(String::formatted("Duplicate parameter '{}' not allowed in strict mode", bound_name));
|
||||||
|
@ -1801,7 +1812,7 @@ NonnullRefPtr<FunctionNodeType> Parser::parse_function_node(u8 parse_options)
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
check_identifier_name_for_assignment_validity(name, true);
|
check_identifier_name_for_assignment_validity(name, is_strict);
|
||||||
}
|
}
|
||||||
|
|
||||||
m_state.function_parameters.take_last();
|
m_state.function_parameters.take_last();
|
||||||
|
@ -2404,7 +2415,7 @@ NonnullRefPtr<CatchClause> Parser::parse_catch_clause()
|
||||||
if (match(TokenType::ParenOpen)) {
|
if (match(TokenType::ParenOpen)) {
|
||||||
should_expect_parameter = true;
|
should_expect_parameter = true;
|
||||||
consume();
|
consume();
|
||||||
if (match_identifier_name())
|
if (match_identifier_name() && (!match(TokenType::Yield) || !m_state.in_generator_function_context))
|
||||||
parameter = consume().value();
|
parameter = consume().value();
|
||||||
else
|
else
|
||||||
pattern_parameter = parse_binding_pattern();
|
pattern_parameter = parse_binding_pattern();
|
||||||
|
@ -2722,7 +2733,8 @@ bool Parser::match_variable_declaration() const
|
||||||
bool Parser::match_identifier() const
|
bool Parser::match_identifier() const
|
||||||
{
|
{
|
||||||
return m_state.current_token.type() == TokenType::Identifier
|
return m_state.current_token.type() == TokenType::Identifier
|
||||||
|| m_state.current_token.type() == TokenType::Let; // See note in Parser::parse_identifier().
|
|| (m_state.current_token.type() == TokenType::Let && !m_state.strict_mode)
|
||||||
|
|| (m_state.current_token.type() == TokenType::Yield && !m_state.in_generator_function_context && !m_state.strict_mode); // See note in Parser::parse_identifier().
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Parser::match_identifier_name() const
|
bool Parser::match_identifier_name() const
|
||||||
|
@ -2788,6 +2800,12 @@ Token Parser::consume_identifier()
|
||||||
return consume();
|
return consume();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (match(TokenType::Yield)) {
|
||||||
|
if (m_state.strict_mode || m_state.in_generator_function_context)
|
||||||
|
syntax_error("Identifier must not be a reserved word in strict mode ('yield')");
|
||||||
|
return consume();
|
||||||
|
}
|
||||||
|
|
||||||
expected("Identifier");
|
expected("Identifier");
|
||||||
return consume();
|
return consume();
|
||||||
}
|
}
|
||||||
|
@ -2910,7 +2928,7 @@ void Parser::check_identifier_name_for_assignment_validity(StringView name, bool
|
||||||
if (name.is_one_of("arguments"sv, "eval"sv))
|
if (name.is_one_of("arguments"sv, "eval"sv))
|
||||||
syntax_error("Binding pattern target may not be called 'arguments' or 'eval' in strict mode");
|
syntax_error("Binding pattern target may not be called 'arguments' or 'eval' in strict mode");
|
||||||
else if (is_strict_reserved_word(name))
|
else if (is_strict_reserved_word(name))
|
||||||
syntax_error("Binding pattern target may not be called 'yield' in strict mode");
|
syntax_error(String::formatted("Binding pattern target may not be called '{}' in strict mode", name));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue