mirror of
https://github.com/RGBCube/serenity
synced 2025-05-24 18:35:07 +00:00
LibJS: Add optional extra strict checks in parse_binding_pattern
This commit is contained in:
parent
f1f338edcd
commit
179c48e1a4
2 changed files with 40 additions and 11 deletions
|
@ -1834,7 +1834,7 @@ Vector<FunctionNode::Parameter> Parser::parse_formal_parameters(int& function_le
|
||||||
Vector<FunctionNode::Parameter> parameters;
|
Vector<FunctionNode::Parameter> parameters;
|
||||||
|
|
||||||
auto consume_identifier_or_binding_pattern = [&]() -> Variant<FlyString, NonnullRefPtr<BindingPattern>> {
|
auto consume_identifier_or_binding_pattern = [&]() -> Variant<FlyString, NonnullRefPtr<BindingPattern>> {
|
||||||
if (auto pattern = parse_binding_pattern())
|
if (auto pattern = parse_binding_pattern(true))
|
||||||
return pattern.release_nonnull();
|
return pattern.release_nonnull();
|
||||||
|
|
||||||
auto token = consume_identifier();
|
auto token = consume_identifier();
|
||||||
|
@ -1919,7 +1919,8 @@ Vector<FunctionNode::Parameter> Parser::parse_formal_parameters(int& function_le
|
||||||
}
|
}
|
||||||
|
|
||||||
static constexpr AK::Array<StringView, 36> s_reserved_words = { "break", "case", "catch", "class", "const", "continue", "debugger", "default", "delete", "do", "else", "enum", "export", "extends", "false", "finally", "for", "function", "if", "import", "in", "instanceof", "new", "null", "return", "super", "switch", "this", "throw", "true", "try", "typeof", "var", "void", "while", "with" };
|
static constexpr AK::Array<StringView, 36> s_reserved_words = { "break", "case", "catch", "class", "const", "continue", "debugger", "default", "delete", "do", "else", "enum", "export", "extends", "false", "finally", "for", "function", "if", "import", "in", "instanceof", "new", "null", "return", "super", "switch", "this", "throw", "true", "try", "typeof", "var", "void", "while", "with" };
|
||||||
RefPtr<BindingPattern> Parser::parse_binding_pattern()
|
|
||||||
|
RefPtr<BindingPattern> Parser::parse_binding_pattern(bool strict_checks)
|
||||||
{
|
{
|
||||||
auto rule_start = push_start();
|
auto rule_start = push_start();
|
||||||
|
|
||||||
|
@ -1964,7 +1965,12 @@ RefPtr<BindingPattern> Parser::parse_binding_pattern()
|
||||||
consume().value());
|
consume().value());
|
||||||
} else if (match(TokenType::BracketOpen)) {
|
} else if (match(TokenType::BracketOpen)) {
|
||||||
consume();
|
consume();
|
||||||
name = parse_expression(0);
|
auto expression = parse_expression(0);
|
||||||
|
|
||||||
|
if (strict_checks && m_state.in_generator_function_context && is<YieldExpression>(*expression))
|
||||||
|
syntax_error("Yield expression not allowed in formal parameter within generator context");
|
||||||
|
|
||||||
|
name = move(expression);
|
||||||
consume(TokenType::BracketClose);
|
consume(TokenType::BracketClose);
|
||||||
} else {
|
} else {
|
||||||
expected("identifier or computed property name");
|
expected("identifier or computed property name");
|
||||||
|
@ -1974,14 +1980,16 @@ RefPtr<BindingPattern> Parser::parse_binding_pattern()
|
||||||
if (!is_rest && match(TokenType::Colon)) {
|
if (!is_rest && match(TokenType::Colon)) {
|
||||||
consume();
|
consume();
|
||||||
if (match(TokenType::CurlyOpen) || match(TokenType::BracketOpen)) {
|
if (match(TokenType::CurlyOpen) || match(TokenType::BracketOpen)) {
|
||||||
auto binding_pattern = parse_binding_pattern();
|
auto binding_pattern = parse_binding_pattern(strict_checks);
|
||||||
if (!binding_pattern)
|
if (!binding_pattern)
|
||||||
return {};
|
return {};
|
||||||
alias = binding_pattern.release_nonnull();
|
alias = binding_pattern.release_nonnull();
|
||||||
} else if (match_identifier_name()) {
|
} else if (match_identifier_name()) {
|
||||||
alias = create_ast_node<Identifier>(
|
alias = create_ast_node<Identifier>(
|
||||||
{ m_state.current_token.filename(), rule_start.position(), position() },
|
{ m_state.current_token.filename(), rule_start.position(), position() },
|
||||||
consume().value());
|
consume_identifier().value());
|
||||||
|
if (strict_checks && match(TokenType::BracketOpen))
|
||||||
|
syntax_error("Illegal property in declaration context");
|
||||||
} else {
|
} else {
|
||||||
expected("identifier or binding pattern");
|
expected("identifier or binding pattern");
|
||||||
return {};
|
return {};
|
||||||
|
@ -1990,11 +1998,21 @@ RefPtr<BindingPattern> Parser::parse_binding_pattern()
|
||||||
} else {
|
} else {
|
||||||
if (match_identifier_name()) {
|
if (match_identifier_name()) {
|
||||||
// BindingElement must always have an Empty name field
|
// BindingElement must always have an Empty name field
|
||||||
|
auto identifier_name = consume_identifier().value();
|
||||||
alias = create_ast_node<Identifier>(
|
alias = create_ast_node<Identifier>(
|
||||||
{ m_state.current_token.filename(), rule_start.position(), position() },
|
{ m_state.current_token.filename(), rule_start.position(), position() },
|
||||||
consume().value());
|
identifier_name);
|
||||||
|
|
||||||
|
if (strict_checks) {
|
||||||
|
for (auto& entry : entries) {
|
||||||
|
if (entry.alias.has<NonnullRefPtr<Identifier>>()) {
|
||||||
|
if (entry.alias.get<NonnullRefPtr<Identifier>>()->string() == identifier_name)
|
||||||
|
syntax_error("Duplicate parameter names in bindings");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
} else if (match(TokenType::BracketOpen) || match(TokenType::CurlyOpen)) {
|
} else if (match(TokenType::BracketOpen) || match(TokenType::CurlyOpen)) {
|
||||||
auto pattern = parse_binding_pattern();
|
auto pattern = parse_binding_pattern(strict_checks);
|
||||||
if (!pattern) {
|
if (!pattern) {
|
||||||
expected("binding pattern");
|
expected("binding pattern");
|
||||||
return {};
|
return {};
|
||||||
|
@ -2019,6 +2037,8 @@ RefPtr<BindingPattern> Parser::parse_binding_pattern()
|
||||||
expected("initialization expression");
|
expected("initialization expression");
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
if (strict_checks && is<YieldExpression>(*initializer))
|
||||||
|
syntax_error("Yield expression is not allow in formal parameter");
|
||||||
}
|
}
|
||||||
|
|
||||||
entries.append(BindingPattern::BindingEntry { move(name), move(alias), move(initializer), is_rest });
|
entries.append(BindingPattern::BindingEntry { move(name), move(alias), move(initializer), is_rest });
|
||||||
|
@ -2041,7 +2061,16 @@ RefPtr<BindingPattern> Parser::parse_binding_pattern()
|
||||||
auto pattern = adopt_ref(*new BindingPattern);
|
auto pattern = adopt_ref(*new BindingPattern);
|
||||||
pattern->entries = move(entries);
|
pattern->entries = move(entries);
|
||||||
pattern->kind = kind;
|
pattern->kind = kind;
|
||||||
pattern->for_each_bound_name([this](auto& name) { check_identifier_name_for_assignment_validity(name); });
|
|
||||||
|
Vector<StringView> bound_names;
|
||||||
|
pattern->for_each_bound_name([&](auto& name) {
|
||||||
|
if (strict_checks) {
|
||||||
|
if (bound_names.contains_slow(name))
|
||||||
|
syntax_error("Duplicate parameter names in bindings");
|
||||||
|
bound_names.append(name);
|
||||||
|
}
|
||||||
|
check_identifier_name_for_assignment_validity(name);
|
||||||
|
});
|
||||||
|
|
||||||
return pattern;
|
return pattern;
|
||||||
}
|
}
|
||||||
|
@ -2121,7 +2150,7 @@ NonnullRefPtr<VariableDeclaration> Parser::parse_variable_declaration(bool for_l
|
||||||
check_declarations(declaration);
|
check_declarations(declaration);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (auto pattern = parse_binding_pattern()) {
|
} else if (auto pattern = parse_binding_pattern(declaration_kind != DeclarationKind::Var)) {
|
||||||
target = pattern.release_nonnull();
|
target = pattern.release_nonnull();
|
||||||
|
|
||||||
if ((declaration_kind == DeclarationKind::Let || declaration_kind == DeclarationKind::Const)) {
|
if ((declaration_kind == DeclarationKind::Let || declaration_kind == DeclarationKind::Const)) {
|
||||||
|
@ -2424,7 +2453,7 @@ NonnullRefPtr<CatchClause> Parser::parse_catch_clause()
|
||||||
if (match_identifier_name() && (!match(TokenType::Yield) || !m_state.in_generator_function_context))
|
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(true);
|
||||||
consume(TokenType::ParenClose);
|
consume(TokenType::ParenClose);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -42,7 +42,7 @@ public:
|
||||||
template<typename FunctionNodeType>
|
template<typename FunctionNodeType>
|
||||||
NonnullRefPtr<FunctionNodeType> parse_function_node(u8 parse_options = FunctionNodeParseOptions::CheckForFunctionAndName);
|
NonnullRefPtr<FunctionNodeType> parse_function_node(u8 parse_options = FunctionNodeParseOptions::CheckForFunctionAndName);
|
||||||
Vector<FunctionNode::Parameter> parse_formal_parameters(int& function_length, u8 parse_options = 0);
|
Vector<FunctionNode::Parameter> parse_formal_parameters(int& function_length, u8 parse_options = 0);
|
||||||
RefPtr<BindingPattern> parse_binding_pattern();
|
RefPtr<BindingPattern> parse_binding_pattern(bool strict_checks = false);
|
||||||
|
|
||||||
struct PrimaryExpressionParseResult {
|
struct PrimaryExpressionParseResult {
|
||||||
NonnullRefPtr<Expression> result;
|
NonnullRefPtr<Expression> result;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue