mirror of
https://github.com/danbulant/oxc
synced 2026-05-19 04:08:41 +00:00
perf(parser): precompute is_typescript (#6443)
This commit is contained in:
parent
b1bf12c336
commit
4d8bc8c8af
13 changed files with 40 additions and 52 deletions
|
|
@ -79,7 +79,7 @@ impl<'a> ParserImpl<'a> {
|
|||
Kind::RParen => {
|
||||
let third = self.nth_kind(offset + 2);
|
||||
return match third {
|
||||
Kind::Colon if self.ts_enabled() => Tristate::Maybe,
|
||||
Kind::Colon if self.is_ts => Tristate::Maybe,
|
||||
Kind::Arrow | Kind::LCurly => Tristate::True,
|
||||
_ => Tristate::False,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -19,8 +19,7 @@ impl<'a> ParserImpl<'a> {
|
|||
allow_question: bool,
|
||||
) -> Result<BindingPattern<'a>> {
|
||||
let mut kind = self.parse_binding_pattern_kind()?;
|
||||
let optional =
|
||||
if allow_question && self.ts_enabled() { self.eat(Kind::Question) } else { false };
|
||||
let optional = if allow_question && self.is_ts { self.eat(Kind::Question) } else { false };
|
||||
let type_annotation = self.parse_ts_type_annotation()?;
|
||||
if let Some(type_annotation) = &type_annotation {
|
||||
Self::extend_binding_pattern_span_end(type_annotation.span, &mut kind);
|
||||
|
|
@ -111,7 +110,7 @@ impl<'a> ParserImpl<'a> {
|
|||
|
||||
let kind = self.parse_binding_pattern_kind()?;
|
||||
// Rest element does not allow `?`, checked in checker/typescript.rs
|
||||
if self.at(Kind::Question) && self.ts_enabled() {
|
||||
if self.at(Kind::Question) && self.is_ts {
|
||||
let span = self.cur_token().span();
|
||||
self.bump_any();
|
||||
self.error(diagnostics::a_rest_parameter_cannot_be_optional(span));
|
||||
|
|
|
|||
|
|
@ -75,8 +75,7 @@ impl<'a> ParserImpl<'a> {
|
|||
None
|
||||
};
|
||||
|
||||
let type_parameters =
|
||||
if self.ts_enabled() { self.parse_ts_type_parameters()? } else { None };
|
||||
let type_parameters = if self.is_ts { self.parse_ts_type_parameters()? } else { None };
|
||||
let (extends, implements) = self.parse_heritage_clause()?;
|
||||
let mut super_class = None;
|
||||
let mut super_type_parameters = None;
|
||||
|
|
@ -283,7 +282,7 @@ impl<'a> ParserImpl<'a> {
|
|||
|
||||
if let PropertyKey::PrivateIdentifier(private_ident) = &key {
|
||||
// `private #foo`, etc. is illegal
|
||||
if self.ts_enabled() {
|
||||
if self.is_ts {
|
||||
self.verify_modifiers(
|
||||
&modifiers,
|
||||
ModifierFlags::all() - ModifierFlags::ACCESSIBILITY,
|
||||
|
|
@ -457,8 +456,7 @@ impl<'a> ParserImpl<'a> {
|
|||
optional: bool,
|
||||
definite: bool,
|
||||
) -> Result<ClassElement<'a>> {
|
||||
let type_annotation =
|
||||
if self.ts_enabled() { self.parse_ts_type_annotation()? } else { None };
|
||||
let type_annotation = if self.is_ts { self.parse_ts_type_annotation()? } else { None };
|
||||
let decorators = self.consume_decorators();
|
||||
let value = if self.eat(Kind::Eq) { Some(self.parse_expr()?) } else { None };
|
||||
self.asi()?;
|
||||
|
|
@ -506,8 +504,7 @@ impl<'a> ParserImpl<'a> {
|
|||
definite: bool,
|
||||
accessibility: Option<TSAccessibility>,
|
||||
) -> Result<ClassElement<'a>> {
|
||||
let type_annotation =
|
||||
if self.ts_enabled() { self.parse_ts_type_annotation()? } else { None };
|
||||
let type_annotation = if self.is_ts { self.parse_ts_type_annotation()? } else { None };
|
||||
let value =
|
||||
self.eat(Kind::Eq).then(|| self.parse_assignment_expression_or_higher()).transpose()?;
|
||||
let r#type = if r#abstract {
|
||||
|
|
|
|||
|
|
@ -95,7 +95,7 @@ impl<'a> ParserImpl<'a> {
|
|||
|
||||
let mut binding_kind = self.parse_binding_pattern_kind()?;
|
||||
|
||||
let (id, definite) = if self.ts_enabled() {
|
||||
let (id, definite) = if self.is_ts {
|
||||
// const x!: number = 1
|
||||
// ^ definite
|
||||
let mut definite = false;
|
||||
|
|
|
|||
|
|
@ -644,7 +644,7 @@ impl<'a> ParserImpl<'a> {
|
|||
_ => break,
|
||||
}
|
||||
}
|
||||
Kind::Bang if !self.cur_token().is_on_new_line && self.ts_enabled() => {
|
||||
Kind::Bang if !self.cur_token().is_on_new_line && self.is_ts => {
|
||||
self.bump_any();
|
||||
self.ast.expression_ts_non_null(self.end_span(lhs_span), lhs)
|
||||
}
|
||||
|
|
@ -905,7 +905,7 @@ impl<'a> ParserImpl<'a> {
|
|||
if self.source_type.is_jsx() {
|
||||
return self.parse_jsx_expression();
|
||||
}
|
||||
if self.ts_enabled() {
|
||||
if self.is_ts {
|
||||
return self.parse_ts_type_assertion();
|
||||
}
|
||||
Err(self.unexpected())
|
||||
|
|
@ -951,13 +951,12 @@ impl<'a> ParserImpl<'a> {
|
|||
// Pratt Parsing Algorithm
|
||||
// <https://matklad.github.io/2020/04/13/simple-but-powerful-pratt-parsing.html>
|
||||
let mut lhs = lhs;
|
||||
let is_ts = self.ts_enabled();
|
||||
loop {
|
||||
// re-lex for `>=` `>>` `>>>`
|
||||
// This is need for jsx `<div>=</div>` case
|
||||
let kind = self.re_lex_right_angle();
|
||||
|
||||
let Some(left_precedence) = kind_to_precedence(kind, is_ts) else { break };
|
||||
let Some(left_precedence) = kind_to_precedence(kind, self.is_ts) else { break };
|
||||
|
||||
let stop = if left_precedence.is_right_associative() {
|
||||
left_precedence < min_precedence
|
||||
|
|
@ -976,7 +975,7 @@ impl<'a> ParserImpl<'a> {
|
|||
break;
|
||||
}
|
||||
|
||||
if self.ts_enabled() && matches!(kind, Kind::As | Kind::Satisfies) {
|
||||
if self.is_ts && matches!(kind, Kind::As | Kind::Satisfies) {
|
||||
if self.cur_token().is_on_new_line {
|
||||
break;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -47,7 +47,7 @@ impl<'a> ParserImpl<'a> {
|
|||
) -> Result<(Option<TSThisParameter<'a>>, Box<'a, FormalParameters<'a>>)> {
|
||||
let span = self.start_span();
|
||||
self.expect(Kind::LParen)?;
|
||||
let this_param = if self.ts_enabled() && self.at(Kind::This) {
|
||||
let this_param = if self.is_ts && self.at(Kind::This) {
|
||||
let param = self.parse_ts_this_parameter()?;
|
||||
if !self.at(Kind::RParen) {
|
||||
self.expect(Kind::Comma)?;
|
||||
|
|
@ -135,7 +135,7 @@ impl<'a> ParserImpl<'a> {
|
|||
self.ctx =
|
||||
self.ctx.and_in(ctx.has_in()).and_await(ctx.has_await()).and_yield(ctx.has_yield());
|
||||
|
||||
if !self.ts_enabled() && body.is_none() {
|
||||
if !self.is_ts && body.is_none() {
|
||||
return Err(self.unexpected());
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ impl<'a> ParserImpl<'a> {
|
|||
|
||||
self.bump_any(); // advance `import`
|
||||
|
||||
if self.ts_enabled()
|
||||
if self.is_ts
|
||||
&& ((self.cur_kind().is_binding_identifier() && self.peek_at(Kind::Eq))
|
||||
|| (self.at(Kind::Type)
|
||||
&& self.peek_kind().is_binding_identifier()
|
||||
|
|
@ -208,10 +208,10 @@ impl<'a> ParserImpl<'a> {
|
|||
self.bump_any(); // advance `export`
|
||||
|
||||
let decl = match self.cur_kind() {
|
||||
Kind::Eq if self.ts_enabled() => self
|
||||
Kind::Eq if self.is_ts => self
|
||||
.parse_ts_export_assignment_declaration(span)
|
||||
.map(ModuleDeclaration::TSExportAssignment),
|
||||
Kind::As if self.peek_at(Kind::Namespace) && self.ts_enabled() => self
|
||||
Kind::As if self.peek_at(Kind::Namespace) && self.is_ts => self
|
||||
.parse_ts_export_namespace()
|
||||
.map(ModuleDeclaration::TSNamespaceExportDeclaration),
|
||||
Kind::Default => self
|
||||
|
|
@ -223,7 +223,7 @@ impl<'a> ParserImpl<'a> {
|
|||
Kind::LCurly => self
|
||||
.parse_export_named_specifiers(span)
|
||||
.map(ModuleDeclaration::ExportNamedDeclaration),
|
||||
Kind::Type if self.peek_at(Kind::LCurly) && self.ts_enabled() => self
|
||||
Kind::Type if self.peek_at(Kind::LCurly) && self.is_ts => self
|
||||
.parse_export_named_specifiers(span)
|
||||
.map(ModuleDeclaration::ExportNamedDeclaration),
|
||||
Kind::Type if self.peek_at(Kind::Star) => {
|
||||
|
|
@ -328,11 +328,8 @@ impl<'a> ParserImpl<'a> {
|
|||
// For tc39/proposal-decorators
|
||||
// For more information, please refer to <https://babeljs.io/docs/babel-plugin-proposal-decorators#decoratorsbeforeexport>
|
||||
self.eat_decorators()?;
|
||||
let modifiers = if self.ts_enabled() {
|
||||
self.eat_modifiers_before_declaration()?
|
||||
} else {
|
||||
Modifiers::empty()
|
||||
};
|
||||
let modifiers =
|
||||
if self.is_ts { self.eat_modifiers_before_declaration()? } else { Modifiers::empty() };
|
||||
|
||||
let declaration = self.parse_declaration(decl_span, &modifiers)?;
|
||||
let span = self.end_span(span);
|
||||
|
|
@ -362,16 +359,13 @@ impl<'a> ParserImpl<'a> {
|
|||
Kind::Class => self
|
||||
.parse_class_declaration(decl_span, /* modifiers */ &Modifiers::empty())
|
||||
.map(ExportDefaultDeclarationKind::ClassDeclaration)?,
|
||||
_ if self.at(Kind::Abstract) && self.peek_at(Kind::Class) && self.ts_enabled() => {
|
||||
_ if self.at(Kind::Abstract) && self.peek_at(Kind::Class) && self.is_ts => {
|
||||
// eat the abstract modifier
|
||||
let modifiers = self.eat_modifiers_before_declaration()?;
|
||||
self.parse_class_declaration(decl_span, &modifiers)
|
||||
.map(ExportDefaultDeclarationKind::ClassDeclaration)?
|
||||
}
|
||||
_ if self.at(Kind::Interface)
|
||||
&& !self.peek_token().is_on_new_line
|
||||
&& self.ts_enabled() =>
|
||||
{
|
||||
_ if self.at(Kind::Interface) && !self.peek_token().is_on_new_line && self.is_ts => {
|
||||
self.parse_ts_interface_declaration(decl_span, &Modifiers::empty()).map(|decl| {
|
||||
match decl {
|
||||
Declaration::TSInterfaceDeclaration(decl) => {
|
||||
|
|
@ -424,7 +418,7 @@ impl<'a> ParserImpl<'a> {
|
|||
let specifier_span = self.start_span();
|
||||
let peek_kind = self.peek_kind();
|
||||
let mut import_kind = ImportOrExportKind::Value;
|
||||
if self.ts_enabled() && self.at(Kind::Type) {
|
||||
if self.is_ts && self.at(Kind::Type) {
|
||||
if self.peek_at(Kind::As) {
|
||||
if self.nth_at(2, Kind::As) {
|
||||
if self.nth_kind(3).is_identifier_name() {
|
||||
|
|
@ -477,7 +471,7 @@ impl<'a> ParserImpl<'a> {
|
|||
}
|
||||
|
||||
fn parse_import_or_export_kind(&mut self) -> ImportOrExportKind {
|
||||
if !self.ts_enabled() {
|
||||
if !self.is_ts {
|
||||
return ImportOrExportKind::Value;
|
||||
}
|
||||
// OK
|
||||
|
|
@ -521,7 +515,7 @@ impl<'a> ParserImpl<'a> {
|
|||
// export { type as as } // name: `type` type-export: `false` (aliased to `as`)
|
||||
// export { type as as as } // name: `as` type-export: `true`, aliased to `as`
|
||||
let mut export_kind = ImportOrExportKind::Value;
|
||||
if self.ts_enabled() && self.at(Kind::Type) {
|
||||
if self.is_ts && self.at(Kind::Type) {
|
||||
if self.peek_at(Kind::As) {
|
||||
if self.nth_at(2, Kind::As) {
|
||||
if self.nth_at(3, Kind::Str) || self.nth_kind(3).is_identifier_name() {
|
||||
|
|
|
|||
|
|
@ -65,7 +65,7 @@ impl<'a> ParserImpl<'a> {
|
|||
// Report and handle illegal modifiers
|
||||
// e.g. const x = { public foo() {} }
|
||||
modifier_kind
|
||||
if self.ts_enabled()
|
||||
if self.is_ts
|
||||
&& modifier_kind.is_modifier_kind()
|
||||
&& peek_kind.is_identifier_or_keyword() =>
|
||||
{
|
||||
|
|
|
|||
|
|
@ -105,7 +105,7 @@ impl<'a> ParserImpl<'a> {
|
|||
// [+Return] ReturnStatement[?Yield, ?Await]
|
||||
Kind::Return => self.parse_return_statement(),
|
||||
Kind::Var => self.parse_variable_statement(stmt_ctx),
|
||||
Kind::Const if !(self.ts_enabled() && self.is_at_enum_declaration()) => {
|
||||
Kind::Const if !(self.is_ts && self.is_at_enum_declaration()) => {
|
||||
self.parse_variable_statement(stmt_ctx)
|
||||
}
|
||||
Kind::Let if !self.cur_token().escaped() => self.parse_let(stmt_ctx),
|
||||
|
|
@ -116,7 +116,7 @@ impl<'a> ParserImpl<'a> {
|
|||
}
|
||||
Kind::Using if self.peek_kind().is_binding_identifier() => self.parse_using(),
|
||||
_ if self.at_function_with_async() => self.parse_function_declaration(stmt_ctx),
|
||||
_ if self.ts_enabled() && self.at_start_of_ts_declaration() => {
|
||||
_ if self.is_ts && self.at_start_of_ts_declaration() => {
|
||||
self.parse_ts_declaration_statement(start_span)
|
||||
}
|
||||
_ => self.parse_expression_or_labeled_statement(),
|
||||
|
|
|
|||
|
|
@ -95,8 +95,7 @@ impl<'a> ParserImpl<'a> {
|
|||
self.expect(Kind::LAngle)?;
|
||||
let name = self.parse_jsx_element_name()?;
|
||||
// <Component<TsType> for tsx
|
||||
let type_parameters =
|
||||
if self.ts_enabled() { self.try_parse_type_arguments()? } else { None };
|
||||
let type_parameters = if self.is_ts { self.try_parse_type_arguments()? } else { None };
|
||||
let attributes = self.parse_jsx_attributes()?;
|
||||
let self_closing = self.eat(Kind::Slash);
|
||||
if !self_closing || in_jsx_child {
|
||||
|
|
|
|||
|
|
@ -356,8 +356,11 @@ struct ParserImpl<'a> {
|
|||
/// Parsing context
|
||||
ctx: Context,
|
||||
|
||||
/// Ast builder for creating AST spans
|
||||
/// Ast builder for creating AST nodes
|
||||
ast: AstBuilder<'a>,
|
||||
|
||||
/// Precomputed typescript detection
|
||||
is_ts: bool,
|
||||
}
|
||||
|
||||
impl<'a> ParserImpl<'a> {
|
||||
|
|
@ -384,6 +387,7 @@ impl<'a> ParserImpl<'a> {
|
|||
state: ParserState::default(),
|
||||
ctx: Self::default_context(source_type, options),
|
||||
ast: AstBuilder::new(allocator),
|
||||
is_ts: source_type.is_typescript(),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -508,10 +512,6 @@ impl<'a> ParserImpl<'a> {
|
|||
self.errors.len() + self.lexer.errors.len()
|
||||
}
|
||||
|
||||
fn ts_enabled(&self) -> bool {
|
||||
self.source_type.is_typescript()
|
||||
}
|
||||
|
||||
fn set_source_type_to_module_if_unambiguous(&mut self) {
|
||||
if self.source_type.is_unambiguous() {
|
||||
self.source_type = self.source_type.with_module(true);
|
||||
|
|
|
|||
|
|
@ -116,7 +116,7 @@ impl<'a> ParserImpl<'a> {
|
|||
pub(crate) fn parse_ts_type_annotation(
|
||||
&mut self,
|
||||
) -> Result<Option<Box<'a, TSTypeAnnotation<'a>>>> {
|
||||
if !self.ts_enabled() {
|
||||
if !self.is_ts {
|
||||
return Ok(None);
|
||||
}
|
||||
if !self.at(Kind::Colon) {
|
||||
|
|
@ -398,7 +398,7 @@ impl<'a> ParserImpl<'a> {
|
|||
if declare {
|
||||
self.parse_ts_declare_function(start_span, modifiers)
|
||||
.map(Declaration::FunctionDeclaration)
|
||||
} else if self.ts_enabled() {
|
||||
} else if self.is_ts {
|
||||
self.parse_ts_function_impl(start_span, FunctionKind::Declaration, modifiers)
|
||||
.map(Declaration::FunctionDeclaration)
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -138,7 +138,7 @@ impl<'a> ParserImpl<'a> {
|
|||
pub(crate) fn parse_ts_type_parameters(
|
||||
&mut self,
|
||||
) -> Result<Option<Box<'a, TSTypeParameterDeclaration<'a>>>> {
|
||||
if !self.ts_enabled() {
|
||||
if !self.is_ts {
|
||||
return Ok(None);
|
||||
}
|
||||
if !self.at(Kind::LAngle) {
|
||||
|
|
@ -811,7 +811,7 @@ impl<'a> ParserImpl<'a> {
|
|||
pub(crate) fn parse_type_arguments_in_expression(
|
||||
&mut self,
|
||||
) -> Result<Option<Box<'a, TSTypeParameterInstantiation<'a>>>> {
|
||||
if !self.ts_enabled() {
|
||||
if !self.is_ts {
|
||||
return Ok(None);
|
||||
}
|
||||
let span = self.start_span();
|
||||
|
|
@ -1049,7 +1049,7 @@ impl<'a> ParserImpl<'a> {
|
|||
kind: Kind,
|
||||
is_type: bool,
|
||||
) -> Result<Option<Box<'a, TSTypeAnnotation<'a>>>> {
|
||||
if !self.ts_enabled() {
|
||||
if !self.is_ts {
|
||||
return Ok(None);
|
||||
}
|
||||
if !self.at(Kind::Colon) {
|
||||
|
|
@ -1315,7 +1315,7 @@ impl<'a> ParserImpl<'a> {
|
|||
&mut self,
|
||||
is_constructor_parameter: bool,
|
||||
) -> Modifiers<'a> {
|
||||
if !self.ts_enabled() {
|
||||
if !self.is_ts {
|
||||
return Modifiers::empty();
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue