diff --git a/crates/oxc_parser/src/cursor.rs b/crates/oxc_parser/src/cursor.rs index af18ec6a5..f7b20a8cb 100644 --- a/crates/oxc_parser/src/cursor.rs +++ b/crates/oxc_parser/src/cursor.rs @@ -294,31 +294,16 @@ impl<'a> ParserImpl<'a> { answer } - pub(crate) fn without_context(&mut self, flags: Context, cb: F) -> T + #[allow(clippy::inline_always)] + #[inline(always)] // inline because this is always on a hot path + pub(crate) fn context(&mut self, add_flags: Context, remove_flags: Context, cb: F) -> T where F: FnOnce(&mut Self) -> T, { - let context_flags_to_clear = flags & self.ctx; - if !context_flags_to_clear.is_empty() { - self.ctx &= !context_flags_to_clear; - let result = cb(self); - self.ctx |= context_flags_to_clear; - return result; - } - cb(self) - } - - pub(crate) fn with_context(&mut self, flags: Context, cb: F) -> T - where - F: FnOnce(&mut Self) -> T, - { - let context_flags_to_set = flags & !self.ctx; - if !context_flags_to_set.is_empty() { - self.ctx |= context_flags_to_set; - let result = cb(self); - self.ctx &= !context_flags_to_set; - return result; - } - cb(self) + let ctx = self.ctx; + self.ctx = ctx.difference(remove_flags).union(add_flags); + let result = cb(self); + self.ctx = ctx; + result } } diff --git a/crates/oxc_parser/src/js/binding.rs b/crates/oxc_parser/src/js/binding.rs index 96ff6ae46..c7f886fa0 100644 --- a/crates/oxc_parser/src/js/binding.rs +++ b/crates/oxc_parser/src/js/binding.rs @@ -13,7 +13,7 @@ impl<'a> ParserImpl<'a> { pub(super) fn parse_binding_pattern_with_initializer(&mut self) -> Result> { let span = self.start_span(); let pattern = self.parse_binding_pattern(true)?; - self.with_context(Context::In, |p| p.parse_initializer(span, pattern)) + self.context(Context::In, Context::empty(), |p| p.parse_initializer(span, pattern)) } pub(super) fn parse_binding_pattern( @@ -74,8 +74,8 @@ impl<'a> ParserImpl<'a> { let type_annotation = self.parse_ts_type_annotation()?; let pattern = self.ast.binding_pattern(kind, type_annotation, false); // Rest element does not allow `= initializer`, . - let argument = - self.with_context(Context::In, |p| p.parse_initializer(init_span, pattern))?; + let argument = self + .context(Context::In, Context::empty(), |p| p.parse_initializer(init_span, pattern))?; let span = self.end_span(span); if self.at(Kind::Comma) { @@ -110,7 +110,7 @@ impl<'a> ParserImpl<'a> { let binding_identifier = BindingIdentifier::new(ident.span, ident.name.clone()); let identifier = self.ast.binding_pattern_identifier(binding_identifier); let left = self.ast.binding_pattern(identifier, None, false); - self.with_context(Context::In, |p| p.parse_initializer(span, left))? + self.context(Context::In, Context::empty(), |p| p.parse_initializer(span, left))? } else { return Err(self.unexpected()); } diff --git a/crates/oxc_parser/src/js/class.rs b/crates/oxc_parser/src/js/class.rs index 378e62e12..80ea93016 100644 --- a/crates/oxc_parser/src/js/class.rs +++ b/crates/oxc_parser/src/js/class.rs @@ -4,7 +4,7 @@ use oxc_diagnostics::Result; use oxc_span::{GetSpan, Span}; use super::list::ClassElements; -use crate::{diagnostics, lexer::Kind, list::NormalList, ParserImpl, StatementContext}; +use crate::{diagnostics, lexer::Kind, list::NormalList, Context, ParserImpl, StatementContext}; type Extends<'a> = Vec<'a, (Expression<'a>, Option>>, Span)>; @@ -452,12 +452,8 @@ impl<'a> ParserImpl<'a> { /// `ClassStaticBlockStatementList` : /// `StatementList`[~Yield, +Await, ~Return] fn parse_class_static_block(&mut self, span: Span) -> Result> { - let has_await = self.ctx.has_await(); - let has_yield = self.ctx.has_yield(); - let has_return = self.ctx.has_return(); - self.ctx = self.ctx.and_await(true).and_yield(false).and_return(false); - let block = self.parse_block()?; - self.ctx = self.ctx.and_await(has_await).and_yield(has_yield).and_return(has_return); + let block = + self.context(Context::Await, Context::Yield | Context::Return, Self::parse_block)?; Ok(self.ast.static_block(self.end_span(span), block.unbox().body)) } diff --git a/crates/oxc_parser/src/js/expression.rs b/crates/oxc_parser/src/js/expression.rs index 4b506aef3..f1ab54714 100644 --- a/crates/oxc_parser/src/js/expression.rs +++ b/crates/oxc_parser/src/js/expression.rs @@ -204,11 +204,7 @@ impl<'a> ParserImpl<'a> { } fn parse_parenthesized_expression(&mut self, span: Span) -> Result> { - let has_in = self.ctx.has_in(); - let has_decorator = self.ctx.has_decorator(); - self.ctx = self.ctx.and_in(true).and_decorator(false); - let list = SequenceExpressionList::parse(self)?; - self.ctx = self.ctx.and_in(has_in).and_decorator(has_decorator); + let list = self.context(Context::In, Context::Decorator, SequenceExpressionList::parse)?; let mut expressions = list.elements; let paren_span = self.end_span(span); @@ -361,10 +357,7 @@ impl<'a> ParserImpl<'a> { /// [ `ElementList`[?Yield, ?Await] , Elisionopt ] pub(crate) fn parse_array_expression(&mut self) -> Result> { let span = self.start_span(); - let has_in = self.ctx.has_in(); - self.ctx = self.ctx.and_in(true); - let list = ArrayExpressionList::parse(self)?; - self.ctx = self.ctx.and_in(has_in); + let list = self.context(Context::In, Context::empty(), ArrayExpressionList::parse)?; Ok(self.ast.array_expression(self.end_span(span), list.elements, list.trailing_comma)) } @@ -390,7 +383,7 @@ impl<'a> ParserImpl<'a> { Kind::TemplateHead => { quasis.push(self.parse_template_element(tagged)); // TemplateHead Expression[+In, ?Yield, ?Await] - let expr = self.with_context(Context::In, Self::parse_expression)?; + let expr = self.context(Context::In, Context::empty(), Self::parse_expression)?; expressions.push(expr); self.re_lex_template_substitution_tail(); loop { @@ -405,7 +398,11 @@ impl<'a> ParserImpl<'a> { } _ => { // TemplateMiddle Expression[+In, ?Yield, ?Await] - let expr = self.with_context(Context::In, Self::parse_expression)?; + let expr = self.context( + Context::In, + Context::empty(), + Self::parse_expression, + )?; expressions.push(expr); self.re_lex_template_substitution_tail(); } @@ -652,10 +649,7 @@ impl<'a> ParserImpl<'a> { optional: bool, ) -> Result> { self.bump_any(); // advance `[` - let has_in = self.ctx.has_in(); - self.ctx = self.ctx.and_in(true); - let property = self.parse_expression()?; - self.ctx = self.ctx.and_in(has_in); + let property = self.context(Context::In, Context::empty(), Self::parse_expression)?; self.expect(Kind::RBrack)?; Ok(self.ast.computed_member_expression(self.end_span(lhs_span), lhs, property, optional)) } @@ -683,7 +677,7 @@ impl<'a> ParserImpl<'a> { let arguments = if self.at(Kind::LParen) { // ArgumentList[Yield, Await] : // AssignmentExpression[+In, ?Yield, ?Await] - self.with_context(Context::In, CallArguments::parse)?.elements + self.context(Context::In, Context::empty(), CallArguments::parse)?.elements } else { self.ast.new_vec() }; @@ -750,10 +744,7 @@ impl<'a> ParserImpl<'a> { ) -> Result> { // ArgumentList[Yield, Await] : // AssignmentExpression[+In, ?Yield, ?Await] - let ctx = self.ctx; - self.ctx = ctx.and_in(true).and_decorator(false); - let call_arguments = CallArguments::parse(self)?; - self.ctx = ctx; + let call_arguments = self.context(Context::In, Context::Decorator, CallArguments::parse)?; Ok(self.ast.call_expression( self.end_span(lhs_span), lhs, @@ -928,12 +919,8 @@ impl<'a> ParserImpl<'a> { if !self.eat(Kind::Question) { return Ok(lhs); } - - let has_in = self.ctx.has_in(); - self.ctx = self.ctx.and_in(true); - let consequent = self.parse_assignment_expression_base()?; - self.ctx = self.ctx.and_in(has_in); - + let consequent = + self.context(Context::In, Context::empty(), Self::parse_assignment_expression_base)?; self.expect(Kind::Colon)?; let alternate = self.parse_assignment_expression_base()?; Ok(self.ast.conditional_expression(self.end_span(span), lhs, consequent, alternate)) @@ -1047,9 +1034,9 @@ impl<'a> ParserImpl<'a> { if !has_await { self.error(diagnostics::await_expression(Span::new(span.start, span.start + 5))); } - self.ctx = self.ctx.and_await(true); - let argument = self.parse_unary_expression_base(lhs_span)?; - self.ctx = self.ctx.and_await(has_await); + let argument = self.context(Context::Await, Context::empty(), |p| { + p.parse_unary_expression_base(lhs_span) + })?; Ok(self.ast.await_expression(self.end_span(span), argument)) } @@ -1060,7 +1047,8 @@ impl<'a> ParserImpl<'a> { pub(crate) fn parse_decorator(&mut self) -> Result> { let span = self.start_span(); self.bump_any(); // bump @ - let expr = self.with_context(Context::Decorator, Self::parse_lhs_expression)?; + let expr = + self.context(Context::Decorator, Context::empty(), Self::parse_lhs_expression)?; Ok(self.ast.decorator(self.end_span(span), expr)) } diff --git a/crates/oxc_parser/src/js/function.rs b/crates/oxc_parser/src/js/function.rs index 023b91aa6..d947a2a94 100644 --- a/crates/oxc_parser/src/js/function.rs +++ b/crates/oxc_parser/src/js/function.rs @@ -57,7 +57,7 @@ impl<'a> ParserImpl<'a> { let span = self.start_span(); self.expect(Kind::LCurly)?; - let (directives, statements) = self.with_context(Context::Return, |p| { + let (directives, statements) = self.context(Context::Return, Context::empty(), |p| { p.parse_directives_and_statements(/* is_top_level */ false) })?; diff --git a/crates/oxc_parser/src/js/module.rs b/crates/oxc_parser/src/js/module.rs index c0b3ff4bb..eec6ee8d6 100644 --- a/crates/oxc_parser/src/js/module.rs +++ b/crates/oxc_parser/src/js/module.rs @@ -125,11 +125,8 @@ impl<'a> ParserImpl<'a> { // import { export1 , export2 as alias2 , [...] } from "module-name"; fn parse_import_specifiers(&mut self) -> Result>> { - let ctx = self.ctx; - self.ctx = Context::default(); - let specifiers = ImportSpecifierList::parse(self)?.import_specifiers; - self.ctx = ctx; - Ok(specifiers) + self.context(Context::empty(), self.ctx, ImportSpecifierList::parse) + .map(|x| x.import_specifiers) } /// [Import Attributes](https://tc39.es/proposal-import-attributes) @@ -142,11 +139,7 @@ impl<'a> ParserImpl<'a> { } }; let span = self.start_span(); - let ctx = self.ctx; - self.ctx = Context::default(); - let with_entries = AssertEntries::parse(self)?.elements; - self.ctx = ctx; - + let with_entries = self.context(Context::empty(), self.ctx, AssertEntries::parse)?.elements; Ok(Some(WithClause { span: self.end_span(span), attributes_keyword, with_entries })) } @@ -225,12 +218,8 @@ impl<'a> ParserImpl<'a> { span: Span, ) -> Result>> { let export_kind = self.parse_import_or_export_kind(); - - let ctx = self.ctx; - self.ctx = Context::default(); - let specifiers = ExportNamedSpecifiers::parse(self)?.elements; - self.ctx = ctx; - + let specifiers = + self.context(Context::empty(), self.ctx, ExportNamedSpecifiers::parse)?.elements; let (source, with_clause) = if self.eat(Kind::From) && self.cur_kind().is_literal() { let source = self.parse_literal_string()?; (Some(source), self.parse_import_attributes()?) diff --git a/crates/oxc_parser/src/js/object.rs b/crates/oxc_parser/src/js/object.rs index 45fa5333b..8a74725cf 100644 --- a/crates/oxc_parser/src/js/object.rs +++ b/crates/oxc_parser/src/js/object.rs @@ -5,7 +5,7 @@ use oxc_span::Span; use oxc_syntax::operator::AssignmentOperator; use super::list::ObjectExpressionProperties; -use crate::{lexer::Kind, list::SeparatedList, ParserImpl}; +use crate::{lexer::Kind, list::SeparatedList, Context, ParserImpl}; impl<'a> ParserImpl<'a> { /// [Object Expression](https://tc39.es/ecma262/#sec-object-initializer) @@ -15,12 +15,8 @@ impl<'a> ParserImpl<'a> { /// { `PropertyDefinitionList`[?Yield, ?Await] , } pub(crate) fn parse_object_expression(&mut self) -> Result> { let span = self.start_span(); - - let has_in = self.ctx.has_in(); - self.ctx = self.ctx.and_in(true); - let object_expression_properties = ObjectExpressionProperties::parse(self)?; - self.ctx = self.ctx.and_in(has_in); - + let object_expression_properties = + self.context(Context::In, Context::empty(), ObjectExpressionProperties::parse)?; Ok(self.ast.object_expression( self.end_span(span), object_expression_properties.elements, @@ -176,10 +172,8 @@ impl<'a> ParserImpl<'a> { pub(crate) fn parse_computed_property_name(&mut self) -> Result> { self.bump_any(); // advance `[` - let has_in = self.ctx.has_in(); - self.ctx = self.ctx.and_in(true); - let expression = self.parse_assignment_expression_base()?; - self.ctx = self.ctx.and_in(has_in); + let expression = + self.context(Context::In, Context::empty(), Self::parse_assignment_expression_base)?; self.expect(Kind::RBrack)?; Ok(expression) diff --git a/crates/oxc_parser/src/js/statement.rs b/crates/oxc_parser/src/js/statement.rs index 17c2f835b..f74a153fa 100644 --- a/crates/oxc_parser/src/js/statement.rs +++ b/crates/oxc_parser/src/js/statement.rs @@ -283,7 +283,8 @@ impl<'a> ParserImpl<'a> { return self.parse_for_loop(span, None, r#await); } - let init_expression = self.without_context(Context::In, ParserImpl::parse_expression)?; + let init_expression = + self.context(Context::empty(), Context::In, ParserImpl::parse_expression)?; // for (a.b in ...), for ([a] in ..), for ({a} in ..) if self.at(Kind::In) || self.at(Kind::Of) { @@ -308,7 +309,7 @@ impl<'a> ParserImpl<'a> { r#await: bool, ) -> Result> { let start_span = self.start_span(); - let init_declaration = self.without_context(Context::In, |p| { + let init_declaration = self.context(Context::empty(), Context::In, |p| { let decl_ctx = VariableDeclarationContext::new(VariableDeclarationParent::For); p.parse_variable_declaration(start_span, decl_ctx, Modifiers::empty()) })?; @@ -359,7 +360,7 @@ impl<'a> ParserImpl<'a> { ) -> Result> { self.expect(Kind::Semicolon)?; let test = if !self.at(Kind::Semicolon) && !self.at(Kind::RParen) { - Some(self.with_context(Context::In, ParserImpl::parse_expression)?) + Some(self.context(Context::In, Context::empty(), ParserImpl::parse_expression)?) } else { None }; @@ -367,7 +368,7 @@ impl<'a> ParserImpl<'a> { let update = if self.at(Kind::RParen) { None } else { - Some(self.with_context(Context::In, ParserImpl::parse_expression)?) + Some(self.context(Context::In, Context::empty(), ParserImpl::parse_expression)?) }; self.expect(Kind::RParen)?; if r#await { @@ -433,7 +434,7 @@ impl<'a> ParserImpl<'a> { let argument = if self.eat(Kind::Semicolon) || self.can_insert_semicolon() { None } else { - let expr = self.with_context(Context::In, ParserImpl::parse_expression)?; + let expr = self.context(Context::In, Context::empty(), ParserImpl::parse_expression)?; self.asi()?; Some(expr) }; diff --git a/crates/oxc_parser/src/jsx/mod.rs b/crates/oxc_parser/src/jsx/mod.rs index 3c15514e7..2c281afaa 100644 --- a/crates/oxc_parser/src/jsx/mod.rs +++ b/crates/oxc_parser/src/jsx/mod.rs @@ -79,11 +79,7 @@ impl<'a> ParserImpl<'a> { let name = self.parse_jsx_element_name()?; // for tsx let type_parameters = if self.ts_enabled() { - let ctx = self.ctx; - self.ctx = Context::default(); - let args = self.parse_ts_type_arguments()?; - self.ctx = ctx; - args + self.context(Context::default(), self.ctx, Self::parse_ts_type_arguments)? } else { None }; @@ -258,14 +254,13 @@ impl<'a> ParserImpl<'a> { } fn parse_jsx_assignment_expression(&mut self) -> Result> { - let ctx = self.ctx; - self.ctx = Context::default().and_await(ctx.has_await()); - let expr = self.parse_expression(); - if let Ok(Expression::SequenceExpression(seq)) = &expr { - return Err(diagnostics::jsx_expressions_may_not_use_the_comma_operator(seq.span)); - } - self.ctx = ctx; - expr + self.context(Context::default().and_await(self.ctx.has_await()), self.ctx, |p| { + let expr = p.parse_expression(); + if let Ok(Expression::SequenceExpression(seq)) = &expr { + return Err(diagnostics::jsx_expressions_may_not_use_the_comma_operator(seq.span)); + } + expr + }) } /// `JSXChildExpression` : diff --git a/crates/oxc_parser/src/ts/types.rs b/crates/oxc_parser/src/ts/types.rs index cd23044de..21d4a461a 100644 --- a/crates/oxc_parser/src/ts/types.rs +++ b/crates/oxc_parser/src/ts/types.rs @@ -218,18 +218,27 @@ impl<'a> ParserImpl<'a> { && !self.cur_token().is_on_new_line && self.eat(Kind::Extends) { - let extends_type = - self.with_context(Context::DisallowConditionalTypes, Self::parse_ts_type)?; + let extends_type = self.context( + Context::DisallowConditionalTypes, + Context::empty(), + Self::parse_ts_type, + )?; self.expect(Kind::Question)?; - let true_type = - self.without_context(Context::DisallowConditionalTypes, Self::parse_ts_type)?; + let true_type = self.context( + Context::empty(), + Context::DisallowConditionalTypes, + Self::parse_ts_type, + )?; self.expect(Kind::Colon)?; - let false_type = - self.without_context(Context::DisallowConditionalTypes, Self::parse_ts_type)?; + let false_type = self.context( + Context::empty(), + Context::DisallowConditionalTypes, + Self::parse_ts_type, + )?; return Ok(self.ast.ts_conditional_type( self.end_span(left_span), @@ -327,8 +336,11 @@ impl<'a> ParserImpl<'a> { )); } - let mut left = self - .without_context(Context::DisallowConditionalTypes, ParserImpl::parse_ts_basic_type)?; + let mut left = self.context( + Context::empty(), + Context::DisallowConditionalTypes, + ParserImpl::parse_ts_basic_type, + )?; while !self.cur_token().is_on_new_line && self.eat(Kind::LBrack) { if self.eat(Kind::RBrack) { @@ -871,8 +883,11 @@ impl<'a> ParserImpl<'a> { fn parse_constraint_of_infer_type(&mut self) -> Result>> { if self.eat(Kind::Extends) { - let constraint = - self.with_context(Context::DisallowConditionalTypes, Self::parse_ts_type)?; + let constraint = self.context( + Context::DisallowConditionalTypes, + Context::empty(), + Self::parse_ts_type, + )?; if self.ctx.has_disallow_conditional_types() || !self.at(Kind::Question) { return Ok(Some(constraint)); } @@ -940,7 +955,7 @@ impl<'a> ParserImpl<'a> { if !self.peek_token().is_on_new_line && (asserts || is_predicate) { self.parse_ts_type_predicate() } else { - self.without_context(Context::DisallowConditionalTypes, Self::parse_ts_type) + self.context(Context::empty(), Context::DisallowConditionalTypes, Self::parse_ts_type) } }