Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 12 additions & 13 deletions crates/oxc_parser/src/js/arrow.rs
Original file line number Diff line number Diff line change
Expand Up @@ -192,20 +192,19 @@ impl<'a> ParserImpl<'a> {
}

fn is_un_parenthesized_async_arrow_function_worker(&mut self) -> bool {
let checkpoint = self.checkpoint();
self.bump(Kind::Async);
// If the "async" is followed by "=>" token then it is not a beginning of an async arrow-function
// but instead a simple arrow-function which will be parsed inside "parseAssignmentExpressionOrHigher"
if !self.cur_token().is_on_new_line() && self.cur_kind().is_binding_identifier() {
// Arrow before newline is checked in `parse_simple_arrow_function_expression`
self.bump_any();
if self.at(Kind::Arrow) {
self.rewind(checkpoint);
return true;
// Use lookahead to avoid checkpoint/rewind
self.lookahead(|parser| {
parser.bump(Kind::Async);
// If the "async" is followed by "=>" token then it is not a beginning of an async arrow-function
// but instead a simple arrow-function which will be parsed inside "parseAssignmentExpressionOrHigher"
if !parser.cur_token().is_on_new_line() && parser.cur_kind().is_binding_identifier() {
// Arrow before newline is checked in `parse_simple_arrow_function_expression`
parser.bump_any();
parser.at(Kind::Arrow)
} else {
false
}
}
self.rewind(checkpoint);
false
})
}

pub(crate) fn parse_simple_arrow_function_expression(
Expand Down
18 changes: 10 additions & 8 deletions crates/oxc_parser/src/js/expression.rs
Original file line number Diff line number Diff line change
Expand Up @@ -731,24 +731,26 @@ impl<'a> ParserImpl<'a> {
let mut question_dot = false;
let is_property_access = if allow_optional_chain && self.at(Kind::QuestionDot) {
// ?.
let checkpoint = self.checkpoint();
self.bump_any();
let kind = self.cur_kind();
let is_identifier_or_keyword = kind.is_identifier_or_keyword();
if kind == Kind::LBrack
|| is_identifier_or_keyword
|| kind.is_template_start_of_tagged_template()
// Fast check to avoid checkpoint/rewind in common cases
let next_kind = self.lexer.peek_token().kind();
if next_kind == Kind::LBrack
|| next_kind.is_identifier_or_keyword()
|| next_kind.is_template_start_of_tagged_template()
{
// This is likely a valid optional chain, proceed with normal parsing
self.bump_any(); // consume ?.
let kind = self.cur_kind();
let is_identifier_or_keyword = kind.is_identifier_or_keyword();
// ?.[
// ?.something
// ?.template`...`
*in_optional_chain = true;
question_dot = true;
is_identifier_or_keyword
} else {
// This is not a valid optional chain pattern, don't consume ?.
// Should be a cold branch here, as most real-world optional chaining will look like
// `?.something` or `?.[expr]`
self.rewind(checkpoint);
false
}
} else {
Expand Down
13 changes: 7 additions & 6 deletions crates/oxc_parser/src/ts/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -430,14 +430,15 @@ impl<'a> ParserImpl<'a> {
Kind::LParen => self.parse_parenthesized_type(),
Kind::Import => TSType::TSImportType(self.parse_ts_import_type()),
Kind::Asserts => {
let checkpoint = self.checkpoint();
let asserts_start_span = self.start_span();
self.bump_any(); // bump `asserts`

if self.is_token_identifier_or_keyword_on_same_line() {
// Use lookahead to check if this is an asserts type predicate
if self.lookahead(|parser| {
parser.bump(Kind::Asserts);
parser.is_token_identifier_or_keyword_on_same_line()
}) {
let asserts_start_span = self.start_span();
self.bump_any(); // bump `asserts`
self.parse_asserts_type_predicate(asserts_start_span)
} else {
self.rewind(checkpoint);
self.parse_type_reference()
}
}
Expand Down
Loading