diff --git a/crates/oxc_parser/src/cursor.rs b/crates/oxc_parser/src/cursor.rs index e0e4d35da389c..eccb1f7846f8f 100644 --- a/crates/oxc_parser/src/cursor.rs +++ b/crates/oxc_parser/src/cursor.rs @@ -344,7 +344,14 @@ impl<'a> ParserImpl<'a> { { self.expect(open); let mut list = self.ast.vec(); - while !self.at(close) && !self.has_fatal_error() { + loop { + let kind = self.cur_kind(); + if kind == close + || matches!(kind, Kind::Eof | Kind::Undetermined) + || self.fatal_error.is_some() + { + break; + } list.push(f(self)); } self.expect(close); @@ -386,16 +393,25 @@ impl<'a> ParserImpl<'a> { F: Fn(&mut Self) -> T, { let mut list = self.ast.vec(); - if self.at(close) || self.has_fatal_error() { + // Cache cur_kind() to avoid redundant calls in compound checks + let kind = self.cur_kind(); + if kind == close + || matches!(kind, Kind::Eof | Kind::Undetermined) + || self.fatal_error.is_some() + { return (list, None); } list.push(f(self)); loop { - if self.at(close) || self.has_fatal_error() { + let kind = self.cur_kind(); + if kind == close + || matches!(kind, Kind::Eof | Kind::Undetermined) + || self.fatal_error.is_some() + { return (list, None); } self.expect(separator); - if self.at(close) { + if self.cur_kind() == close { let trailing_separator = self.prev_token_end - 1; return (list, Some(trailing_separator)); } @@ -417,7 +433,11 @@ impl<'a> ParserImpl<'a> { let mut rest: Option> = None; let mut first = true; loop { - if self.at(close) || self.has_fatal_error() { + let kind = self.cur_kind(); + if kind == close + || matches!(kind, Kind::Eof | Kind::Undetermined) + || self.fatal_error.is_some() + { break; } @@ -425,17 +445,15 @@ impl<'a> ParserImpl<'a> { first = false; } else { let comma_span = self.cur_token().span(); - if !self.at(Kind::Comma) { - let error = diagnostics::expect_token( - Kind::Comma.to_str(), - self.cur_kind().to_str(), - comma_span, - ); + if kind != Kind::Comma { + let error = + diagnostics::expect_token(Kind::Comma.to_str(), kind.to_str(), comma_span); self.set_fatal_error(error); break; } self.bump_any(); - if self.at(close) { + let kind = self.cur_kind(); + if kind == close { if rest.is_some() && !self.ctx.has_ambient() { self.error(diagnostics::rest_element_trailing_comma(comma_span)); } @@ -448,7 +466,9 @@ impl<'a> ParserImpl<'a> { break; } - if self.at(Kind::Dot3) { + // Re-capture kind to get the current token (may have changed after else branch) + let kind = self.cur_kind(); + if kind == Kind::Dot3 { rest.replace(self.parse_rest_element()); } else { list.push(parse_element(self)); diff --git a/crates/oxc_parser/src/js/arrow.rs b/crates/oxc_parser/src/js/arrow.rs index 37ec4ba72872a..387adc8557d2d 100644 --- a/crates/oxc_parser/src/js/arrow.rs +++ b/crates/oxc_parser/src/js/arrow.rs @@ -65,7 +65,8 @@ impl<'a> ParserImpl<'a> { if self.cur_token().is_on_new_line() { return Tristate::False; } - if !self.at(Kind::LParen) && !self.at(Kind::LAngle) { + let kind = self.cur_kind(); + if kind != Kind::LParen && kind != Kind::LAngle { return Tristate::False; } } diff --git a/crates/oxc_parser/src/js/module.rs b/crates/oxc_parser/src/js/module.rs index e931bcac1a608..44e7cc19a9788 100644 --- a/crates/oxc_parser/src/js/module.rs +++ b/crates/oxc_parser/src/js/module.rs @@ -98,12 +98,13 @@ impl<'a> ParserImpl<'a> { self.error(diagnostics::escaped_keyword(token_after_import.span())); } - if self.at(Kind::LCurly) || self.at(Kind::Star) { + let kind = self.cur_kind(); + if kind == Kind::LCurly || kind == Kind::Star { // `import type { ...` // `import type * ...` import_kind = ImportOrExportKind::Type; has_default_specifier = false; - } else if self.cur_kind().is_binding_identifier() { + } else if kind.is_binding_identifier() { // `import type something ...` let token = self.cur_token(); let identifier_after_type = self.parse_binding_identifier(); diff --git a/crates/oxc_parser/src/js/statement.rs b/crates/oxc_parser/src/js/statement.rs index fd4df25ec415f..3ec3831e10479 100644 --- a/crates/oxc_parser/src/js/statement.rs +++ b/crates/oxc_parser/src/js/statement.rs @@ -620,9 +620,15 @@ impl<'a> ParserImpl<'a> { }; self.expect(Kind::Colon); let mut consequent = self.ast.vec(); - while !matches!(self.cur_kind(), Kind::Case | Kind::Default | Kind::RCurly) - && !self.has_fatal_error() - { + loop { + let kind = self.cur_kind(); + if matches!( + kind, + Kind::Case | Kind::Default | Kind::RCurly | Kind::Eof | Kind::Undetermined + ) || self.fatal_error.is_some() + { + break; + } let stmt = self.parse_statement_list_item(StatementContext::StatementList); consequent.push(stmt); } diff --git a/crates/oxc_parser/src/jsx/mod.rs b/crates/oxc_parser/src/jsx/mod.rs index 8a784648a4d0c..e6588dcc22744 100644 --- a/crates/oxc_parser/src/jsx/mod.rs +++ b/crates/oxc_parser/src/jsx/mod.rs @@ -241,16 +241,17 @@ impl<'a> ParserImpl<'a> { let span = self.start_span(); let checkpoint = self.checkpoint(); self.bump_any(); // bump `<` + let kind = self.cur_kind(); // <> open fragment - if self.at(Kind::RAngle) { + if kind == Kind::RAngle { return Some(JSXChild::Fragment(self.parse_jsx_fragment(span, true))); } // ParserImpl<'a> { /// `JSXAttribute` `JSXAttributes_opt` fn parse_jsx_attributes(&mut self) -> Vec<'a, JSXAttributeItem<'a>> { let mut attributes = self.ast.vec(); - while !matches!(self.cur_kind(), Kind::LAngle | Kind::RAngle | Kind::Slash) - && self.fatal_error.is_none() - { - let attribute = match self.cur_kind() { + loop { + let kind = self.cur_kind(); + if matches!(kind, Kind::LAngle | Kind::RAngle | Kind::Slash) + || self.fatal_error.is_some() + { + break; + } + let attribute = match kind { Kind::LCurly => { JSXAttributeItem::SpreadAttribute(self.parse_jsx_spread_attribute()) } @@ -405,7 +410,8 @@ impl<'a> ParserImpl<'a> { /// `JSXIdentifier` [no `WhiteSpace` or Comment here] - fn parse_jsx_identifier(&mut self) -> JSXIdentifier<'a> { let span = self.start_span(); - if !self.at(Kind::Ident) && !self.cur_kind().is_any_keyword() { + let kind = self.cur_kind(); + if kind != Kind::Ident && !kind.is_any_keyword() { return self.unexpected(); } // Currently at a valid normal Ident or Keyword, keep on lexing for `-` in `` diff --git a/crates/oxc_parser/src/lexer/kind.rs b/crates/oxc_parser/src/lexer/kind.rs index e3d6f8afe458c..f2b5eb1a32400 100644 --- a/crates/oxc_parser/src/lexer/kind.rs +++ b/crates/oxc_parser/src/lexer/kind.rs @@ -270,9 +270,10 @@ impl Kind { } /// `IdentifierName` + /// All identifier names are either `Ident` or keywords (Await..=Null in the enum). #[inline] pub fn is_identifier_name(self) -> bool { - self == Ident || self.is_any_keyword() + self == Ident || matches!(self as u8, x if x >= Await as u8 && x <= Null as u8) } /// Check the succeeding token of a `let` keyword. diff --git a/crates/oxc_parser/src/modifiers.rs b/crates/oxc_parser/src/modifiers.rs index 89d35ebc46b81..1cdd73b319a72 100644 --- a/crates/oxc_parser/src/modifiers.rs +++ b/crates/oxc_parser/src/modifiers.rs @@ -386,7 +386,7 @@ impl<'a> ParserImpl<'a> { let span = self.start_span(); let kind = self.cur_kind(); - if matches!(self.cur_kind(), Kind::Const) { + if kind == Kind::Const { if !permit_const_as_modifier { return None; } @@ -398,10 +398,10 @@ impl<'a> ParserImpl<'a> { } else if // we're at the start of a static block (stop_on_start_of_class_static_block - && matches!(self.cur_kind(), Kind::Static) + && kind == Kind::Static && self.lexer.peek_token().kind() == Kind::LCurly) // we may be at the start of a static block - || (has_seen_static_modifier && matches!(self.cur_kind(), Kind::Static)) + || (has_seen_static_modifier && kind == Kind::Static) // next token is not a modifier || (!self.parse_any_contextual_modifier()) { diff --git a/crates/oxc_parser/src/ts/types.rs b/crates/oxc_parser/src/ts/types.rs index ca63bf1edb434..7ad836cef21d2 100644 --- a/crates/oxc_parser/src/ts/types.rs +++ b/crates/oxc_parser/src/ts/types.rs @@ -85,17 +85,17 @@ impl<'a> ParserImpl<'a> { if self.at(Kind::LAngle) { return true; } - if self.at(Kind::New) { + let kind = self.cur_kind(); + if kind == Kind::New { return true; } - if !self.at(Kind::LParen) && !self.at(Kind::Abstract) { + if kind != Kind::LParen && kind != Kind::Abstract { return false; } let checkpoint = self.checkpoint(); - let first = self.cur_kind(); self.bump_any(); - match first { + match kind { Kind::Abstract => { // `abstract new ...` if self.at(Kind::New) { @@ -140,11 +140,12 @@ impl<'a> ParserImpl<'a> { if self.cur_kind().is_modifier_kind() { self.parse_modifiers(false, false); } - if self.cur_kind().is_identifier() || self.at(Kind::This) { + let kind = self.cur_kind(); + if kind.is_identifier() || kind == Kind::This { self.bump_any(); return true; } - if matches!(self.cur_kind(), Kind::LBrack | Kind::LCurly) { + if matches!(kind, Kind::LBrack | Kind::LCurly) { let errors_count = self.errors_count(); self.parse_binding_pattern_kind(); if !self.has_fatal_error() && errors_count == self.errors_count() { @@ -555,7 +556,8 @@ impl<'a> ParserImpl<'a> { fn is_start_of_mapped_type(&mut self) -> bool { self.bump_any(); - if self.at(Kind::Plus) || self.at(Kind::Minus) { + let kind = self.cur_kind(); + if kind == Kind::Plus || kind == Kind::Minus { self.bump_any(); return self.at(Kind::Readonly); } @@ -1184,7 +1186,8 @@ impl<'a> ParserImpl<'a> { let (key, computed) = self.parse_property_name(); let optional = self.eat(Kind::Question); - if self.at(Kind::LParen) || self.at(Kind::LAngle) { + let kind = self.cur_kind(); + if kind == Kind::LParen || kind == Kind::LAngle { for modifier in modifiers.iter() { if modifier.kind == ModifierKind::Readonly { self.error(