summaryrefslogtreecommitdiff
path: root/Userland/Libraries/LibJS/Parser.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'Userland/Libraries/LibJS/Parser.cpp')
-rw-r--r--Userland/Libraries/LibJS/Parser.cpp162
1 files changed, 81 insertions, 81 deletions
diff --git a/Userland/Libraries/LibJS/Parser.cpp b/Userland/Libraries/LibJS/Parser.cpp
index 48d286c102..36a23e12d6 100644
--- a/Userland/Libraries/LibJS/Parser.cpp
+++ b/Userland/Libraries/LibJS/Parser.cpp
@@ -1248,6 +1248,15 @@ NonnullRefPtr<AssignmentExpression> Parser::parse_assignment_expression(Assignme
return create_ast_node<AssignmentExpression>({ m_parser_state.m_current_token.filename(), rule_start.position(), position() }, assignment_op, move(lhs), move(rhs));
}
+NonnullRefPtr<Identifier> Parser::parse_identifier()
+{
+ auto identifier_start = position();
+ auto token = consume(TokenType::Identifier);
+ return create_ast_node<Identifier>(
+ { m_parser_state.m_current_token.filename(), identifier_start, position() },
+ token.value());
+}
+
NonnullRefPtr<CallExpression> Parser::parse_call_expression(NonnullRefPtr<Expression> lhs)
{
auto rule_start = push_start();
@@ -1522,36 +1531,28 @@ RefPtr<BindingPattern> Parser::parse_binding_pattern()
{
auto rule_start = push_start();
- auto pattern_ptr = adopt_ref(*new BindingPattern);
- auto& pattern = *pattern_ptr;
TokenType closing_token;
- auto allow_named_property = false;
- auto elide_extra_commas = false;
- auto allow_nested_pattern = false;
+ bool is_object = true;
if (match(TokenType::BracketOpen)) {
consume();
- pattern.kind = BindingPattern::Kind::Array;
closing_token = TokenType::BracketClose;
- elide_extra_commas = true;
- allow_nested_pattern = true;
+ is_object = false;
} else if (match(TokenType::CurlyOpen)) {
consume();
- pattern.kind = BindingPattern::Kind::Object;
closing_token = TokenType::CurlyClose;
- allow_named_property = true;
} else {
return {};
}
+ Vector<BindingPattern::BindingEntry> entries;
+
while (!match(closing_token)) {
- if (elide_extra_commas && match(TokenType::Comma))
+ if (!is_object && match(TokenType::Comma)) {
consume();
-
- ScopeGuard consume_commas { [&] {
- if (match(TokenType::Comma))
- consume();
- } };
+ entries.append(BindingPattern::BindingEntry {});
+ continue;
+ }
auto is_rest = false;
@@ -1560,89 +1561,88 @@ RefPtr<BindingPattern> Parser::parse_binding_pattern()
is_rest = true;
}
- if (match(TokenType::Identifier)) {
- auto identifier_start = position();
- auto token = consume(TokenType::Identifier);
- auto name = create_ast_node<Identifier>(
- { m_parser_state.m_current_token.filename(), identifier_start, position() },
- token.value());
+ decltype(BindingPattern::BindingEntry::name) name = Empty {};
+ decltype(BindingPattern::BindingEntry::alias) alias = Empty {};
+ RefPtr<Expression> initializer = {};
- if (!is_rest && allow_named_property && match(TokenType::Colon)) {
+ if (is_object) {
+ if (match(TokenType::Identifier)) {
+ name = parse_identifier();
+ } else if (match(TokenType::BracketOpen)) {
consume();
- if (!match(TokenType::Identifier)) {
- syntax_error("Expected a binding pattern as the value of a named element in destructuring object");
- break;
- } else {
- auto identifier_start = position();
- auto token = consume(TokenType::Identifier);
- auto alias_name = create_ast_node<Identifier>(
- { m_parser_state.m_current_token.filename(), identifier_start, position() },
- token.value());
- pattern.properties.append(BindingPattern::BindingProperty {
- .name = move(name),
- .alias = move(alias_name),
- .pattern = nullptr,
- .initializer = nullptr,
- .is_rest = false,
- });
- }
- continue;
+ name = parse_expression(0);
+ consume(TokenType::BracketOpen);
+ } else {
+ syntax_error("Expected identifier or computed property name");
+ return {};
}
- RefPtr<Expression> initializer;
- if (match(TokenType::Equals)) {
+ if (!is_rest && match(TokenType::Colon)) {
consume();
- initializer = parse_expression(2);
+ if (match(TokenType::CurlyOpen) || match(TokenType::BracketOpen)) {
+ auto binding_pattern = parse_binding_pattern();
+ if (!binding_pattern)
+ return {};
+ alias = binding_pattern.release_nonnull();
+ } else if (match_identifier_name()) {
+ alias = parse_identifier();
+ } else {
+ syntax_error("Expected identifier or binding pattern");
+ return {};
+ }
+ }
+ } else {
+ if (match(TokenType::Identifier)) {
+ // BindingElement must always have an Empty name field
+ alias = parse_identifier();
+ } else if (match(TokenType::BracketOpen) || match(TokenType::CurlyOpen)) {
+ auto pattern = parse_binding_pattern();
+ if (!pattern) {
+ syntax_error("Expected binding pattern");
+ return {};
+ }
+ alias = pattern.release_nonnull();
+ } else {
+ syntax_error("Expected identifier or binding pattern");
+ return {};
}
- pattern.properties.append(BindingPattern::BindingProperty {
- .name = move(name),
- .alias = nullptr,
- .pattern = nullptr,
- .initializer = move(initializer),
- .is_rest = is_rest,
- });
- if (is_rest)
- break;
- continue;
}
- if (allow_nested_pattern) {
- auto binding_pattern = parse_binding_pattern();
- if (!binding_pattern) {
- if (is_rest)
- syntax_error("Expected a binding pattern after ... in destructuring list");
- else
- syntax_error("Expected a binding pattern or identifier in destructuring list");
- break;
- } else {
- RefPtr<Expression> initializer;
- if (match(TokenType::Equals)) {
- consume();
- initializer = parse_expression(2);
- }
- pattern.properties.append(BindingPattern::BindingProperty {
- .name = nullptr,
- .alias = nullptr,
- .pattern = move(binding_pattern),
- .initializer = move(initializer),
- .is_rest = is_rest,
- });
- if (is_rest)
- break;
- continue;
+ if (match(TokenType::Equals)) {
+ if (is_rest) {
+ syntax_error("Unexpected initializer after rest element");
+ return {};
}
- continue;
+ consume();
+
+ initializer = parse_expression(2);
+ if (!initializer) {
+ syntax_error("Expected initialization expression");
+ return {};
+ }
}
- break;
+ entries.append(BindingPattern::BindingEntry { move(name), move(alias), move(initializer), is_rest });
+
+ if (match(TokenType::Comma)) {
+ if (is_rest) {
+ syntax_error("Rest element may not be followed by a comma");
+ return {};
+ }
+ consume();
+ }
}
- while (elide_extra_commas && match(TokenType::Comma))
+ while (!is_object && match(TokenType::Comma))
consume();
consume(closing_token);
+ auto kind = is_object ? BindingPattern::Kind::Object : BindingPattern::Kind::Array;
+ auto pattern = adopt_ref(*new BindingPattern);
+ pattern->entries = move(entries);
+ pattern->kind = kind;
return pattern;
}