Change new() parser to make use of matching-) functionality

This commit is contained in:
dkanus 2026-04-30 17:27:27 +07:00
parent b1f0714483
commit c58bcd4aac

View File

@ -223,7 +223,7 @@ impl<'src, 'arena> Parser<'src, 'arena> {
state: &mut NewArgumentListParseState<'src, 'arena>, state: &mut NewArgumentListParseState<'src, 'arena>,
) -> Option<NewClassSpecifierParseAction> { ) -> Option<NewClassSpecifierParseAction> {
let has_parsed_all_allowed_arguments = let has_parsed_all_allowed_arguments =
state.call_argument_list_parse_state.parsed_slot_count > 2; state.call_argument_list_parse_state.parsed_slot_count >= 3;
let likely_missing_comma = !self.next_token_definitely_cannot_start_expression() let likely_missing_comma = !self.next_token_definitely_cannot_start_expression()
&& !has_parsed_all_allowed_arguments; && !has_parsed_all_allowed_arguments;
if likely_missing_comma { if likely_missing_comma {
@ -282,29 +282,42 @@ impl<'src, 'arena> Parser<'src, 'arena> {
} }
} }
/// Reports a missing closing `)` in a `new(...)` argument list and /// Recovers from a missing closing `)` in a `new(...)` argument list.
/// determines whether the class specifier should be parsed or skipped. ///
/// Returns whether class-specifier parsing should continue after recovery.
#[must_use] #[must_use]
fn recover_from_missing_new_closing_parenthesis( fn recover_from_missing_new_closing_parenthesis(
&mut self, &mut self,
state: &NewArgumentListParseState<'src, 'arena>, state: &NewArgumentListParseState<'src, 'arena>,
) -> NewClassSpecifierParseAction { ) -> NewClassSpecifierParseAction {
let mut error = self self.make_error_at_last_consumed(ParseErrorKind::NewMissingClosingParenthesis)
.make_error_at_last_consumed(ParseErrorKind::NewMissingClosingParenthesis)
.widen_error_span_from(state.left_parenthesis_position) .widen_error_span_from(state.left_parenthesis_position)
.blame_token(self.peek_position_or_eof()) .blame_token(self.peek_position_or_eof())
.related_token("new_keyword", state.new_keyword_position) .related_token("new_keyword", state.new_keyword_position)
.related_token("left_parenthesis", state.left_parenthesis_position); .related_token("left_parenthesis", state.left_parenthesis_position)
let class_specifier_parse_action = if self.next_token_definitely_cannot_start_expression() { .report(self);
error = error.sync_error_at_matching_delimiter(self, state.left_parenthesis_position); // Missing-delimiter recovery normally syncs to the matching `)`.
// Skipping the class specifier avoids cascading errors when // `new(...) ClassName` is an exception: after a missing `)`, the next
// the next token cannot start an expression anyway. // expression may already be the class specifier, not another argument.
let matching_right_parenthesis_ahead = self
.file
.matching_delimiter(state.left_parenthesis_position)
.is_some_and(|right_parenthesis_position| {
self.peek_position_or_eof() <= right_parenthesis_position
});
if matching_right_parenthesis_ahead {
self.recover_at_matching_delimiter_or_sync(state.left_parenthesis_position);
// After syncing through the matched `)`, the argument-list error is
// contained, so class-specifier parsing can proceed normally.
return NewClassSpecifierParseAction::Parse;
}
if self.next_token_definitely_cannot_start_expression() {
// There is no plausible class specifier to parse, so skip it to
// avoid error cascade.
NewClassSpecifierParseAction::Skip NewClassSpecifierParseAction::Skip
} else { } else {
NewClassSpecifierParseAction::Parse NewClassSpecifierParseAction::Parse
}; }
error.report_error(self);
class_specifier_parse_action
} }
/// Parses the class specifier of a `new` expression after argument-list /// Parses the class specifier of a `new` expression after argument-list