From d7afbc8eccbe94d8be4222fa5f17d4c50e2bffc3 Mon Sep 17 00:00:00 2001 From: overlookmotel Date: Wed, 7 Feb 2024 15:22:08 +0000 Subject: [PATCH] refactor(parser): wrapper type for parser (#2339) Split parser into public interface `Parser` and internal implementation `ParserImpl`. This involves no changes to public API. This change is a bit annoying, but justification is that it's required for #2341, which I believe to be very worthwhile. The `ParserOptions` type also makes it a bit clearer what the defaults for `allow_return_outside_function` and `preserve_parens` are. It came as a surprise to me that `preserve_parens` defaults to `true`, and this refactor makes that a bit more obvious when reading the code. All the real changes are in [oxc_parser/src/lib.rs](https://github.com/oxc-project/oxc/pull/2339/files#diff-8e59dfd35fc50b6ac9a9ccd991e25c8b5d30826e006d565a2e01f3d15dc5f7cb). The rest of the diff is basically replacing `Parser` with `ParserImpl` everywhere else. --- crates/oxc_parser/src/cursor.rs | 8 +- crates/oxc_parser/src/js/binding.rs | 4 +- crates/oxc_parser/src/js/class.rs | 4 +- crates/oxc_parser/src/js/declaration.rs | 4 +- crates/oxc_parser/src/js/expression.rs | 6 +- crates/oxc_parser/src/js/function.rs | 4 +- crates/oxc_parser/src/js/grammar.rs | 18 ++-- crates/oxc_parser/src/js/list.rs | 54 ++++++------ crates/oxc_parser/src/js/module.rs | 4 +- crates/oxc_parser/src/js/object.rs | 4 +- crates/oxc_parser/src/js/statement.rs | 12 +-- crates/oxc_parser/src/jsx/mod.rs | 4 +- crates/oxc_parser/src/lib.rs | 106 +++++++++++++++++------- crates/oxc_parser/src/list.rs | 14 ++-- crates/oxc_parser/src/ts/declaration.rs | 7 +- crates/oxc_parser/src/ts/list.rs | 22 ++--- crates/oxc_parser/src/ts/statement.rs | 4 +- crates/oxc_parser/src/ts/types.rs | 10 +-- 18 files changed, 169 insertions(+), 120 deletions(-) diff --git a/crates/oxc_parser/src/cursor.rs b/crates/oxc_parser/src/cursor.rs index 821cc2bf51475..9ff6e55896033 100644 --- a/crates/oxc_parser/src/cursor.rs +++ b/crates/oxc_parser/src/cursor.rs @@ -7,7 +7,7 @@ use oxc_span::Span; use crate::{ diagnostics, lexer::{Kind, LexerCheckpoint, LexerContext, Token}, - Context, Parser, + Context, ParserImpl, }; #[derive(Clone, Copy)] @@ -18,7 +18,7 @@ pub struct ParserCheckpoint<'a> { errors_pos: usize, } -impl<'a> Parser<'a> { +impl<'a> ParserImpl<'a> { pub(crate) fn start_span(&self) -> Span { let token = self.cur_token(); Span::new(token.start, 0) @@ -266,7 +266,7 @@ impl<'a> Parser<'a> { /// # Errors pub(crate) fn try_parse( &mut self, - func: impl FnOnce(&mut Parser<'a>) -> Result, + func: impl FnOnce(&mut ParserImpl<'a>) -> Result, ) -> Result { let checkpoint = self.checkpoint(); let ctx = self.ctx; @@ -278,7 +278,7 @@ impl<'a> Parser<'a> { result } - pub(crate) fn lookahead(&mut self, predicate: impl Fn(&mut Parser<'a>) -> U) -> U { + pub(crate) fn lookahead(&mut self, predicate: impl Fn(&mut ParserImpl<'a>) -> U) -> U { let checkpoint = self.checkpoint(); let answer = predicate(self); self.rewind(checkpoint); diff --git a/crates/oxc_parser/src/js/binding.rs b/crates/oxc_parser/src/js/binding.rs index 15317ba9cc311..74c70904c7ee7 100644 --- a/crates/oxc_parser/src/js/binding.rs +++ b/crates/oxc_parser/src/js/binding.rs @@ -4,9 +4,9 @@ use oxc_diagnostics::Result; use oxc_span::Span; use super::list::{ArrayPatternList, ObjectPatternProperties}; -use crate::{diagnostics, lexer::Kind, list::SeparatedList, Context, Parser}; +use crate::{diagnostics, lexer::Kind, list::SeparatedList, Context, ParserImpl}; -impl<'a> Parser<'a> { +impl<'a> ParserImpl<'a> { /// Destructuring Binding Patterns /// `LexicalBinding` /// `BindingIdentifier` `Initializer_opt` diff --git a/crates/oxc_parser/src/js/class.rs b/crates/oxc_parser/src/js/class.rs index 2f31daee5a4a5..b60e80b56b1d7 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, Parser, StatementContext}; +use crate::{diagnostics, lexer::Kind, list::NormalList, ParserImpl, StatementContext}; type Extends<'a> = Vec<'a, (Expression<'a>, Option>>, Span)>; @@ -12,7 +12,7 @@ type Extends<'a> = type Implements<'a> = Vec<'a, Box<'a, TSClassImplements<'a>>>; /// Section 15.7 Class Definitions -impl<'a> Parser<'a> { +impl<'a> ParserImpl<'a> { // `start_span` points at the start of all decoractors and `class` keyword. pub(crate) fn parse_class_statement( &mut self, diff --git a/crates/oxc_parser/src/js/declaration.rs b/crates/oxc_parser/src/js/declaration.rs index e2e0e1b256d56..956169fe618bc 100644 --- a/crates/oxc_parser/src/js/declaration.rs +++ b/crates/oxc_parser/src/js/declaration.rs @@ -3,7 +3,7 @@ use oxc_ast::ast::*; use oxc_diagnostics::Result; use oxc_span::{GetSpan, Span}; -use crate::{diagnostics, lexer::Kind, Parser, StatementContext}; +use crate::{diagnostics, lexer::Kind, ParserImpl, StatementContext}; #[derive(Clone, Debug, Copy, Eq, PartialEq)] pub enum VariableDeclarationParent { @@ -23,7 +23,7 @@ impl VariableDeclarationContext { } } -impl<'a> Parser<'a> { +impl<'a> ParserImpl<'a> { pub(crate) fn parse_let(&mut self, stmt_ctx: StatementContext) -> Result> { let span = self.start_span(); let peeked = self.peek_kind(); diff --git a/crates/oxc_parser/src/js/expression.rs b/crates/oxc_parser/src/js/expression.rs index 0724cdfb48e05..31ea62025bd67 100644 --- a/crates/oxc_parser/src/js/expression.rs +++ b/crates/oxc_parser/src/js/expression.rs @@ -19,10 +19,10 @@ use crate::{ diagnostics, lexer::{parse_big_int, parse_float, parse_int, Kind}, list::SeparatedList, - Context, Parser, + Context, ParserImpl, }; -impl<'a> Parser<'a> { +impl<'a> ParserImpl<'a> { pub(crate) fn parse_paren_expression(&mut self) -> Result> { self.expect(Kind::LParen)?; let expression = self.parse_expression()?; @@ -977,7 +977,7 @@ impl<'a> Parser<'a> { let pos = self.cur_token().start; if !self.state.not_parenthesized_arrow.contains(&pos) { if let Ok((type_parameters, params, return_type, r#async, span)) = - self.try_parse(Parser::parse_parenthesized_arrow_function_head) + self.try_parse(ParserImpl::parse_parenthesized_arrow_function_head) { return self.parse_arrow_function_body( span, diff --git a/crates/oxc_parser/src/js/function.rs b/crates/oxc_parser/src/js/function.rs index 84dee6ab453b9..deb7f38bb01aa 100644 --- a/crates/oxc_parser/src/js/function.rs +++ b/crates/oxc_parser/src/js/function.rs @@ -6,7 +6,7 @@ use oxc_diagnostics::Result; use oxc_span::{GetSpan, Span}; use super::list::FormalParameterList; -use crate::{diagnostics, lexer::Kind, list::SeparatedList, Context, Parser, StatementContext}; +use crate::{diagnostics, lexer::Kind, list::SeparatedList, Context, ParserImpl, StatementContext}; type ArrowFunctionHead<'a> = ( Option>>, @@ -41,7 +41,7 @@ impl FunctionKind { } } -impl<'a> Parser<'a> { +impl<'a> ParserImpl<'a> { pub(crate) fn at_function_with_async(&mut self) -> bool { self.at(Kind::Function) || self.at(Kind::Async) diff --git a/crates/oxc_parser/src/js/grammar.rs b/crates/oxc_parser/src/js/grammar.rs index ead6dd7751636..20118dc8ebbb9 100644 --- a/crates/oxc_parser/src/js/grammar.rs +++ b/crates/oxc_parser/src/js/grammar.rs @@ -4,14 +4,14 @@ use oxc_ast::ast::*; use oxc_diagnostics::Result; use oxc_span::GetSpan; -use crate::{diagnostics, Parser}; +use crate::{diagnostics, ParserImpl}; pub trait CoverGrammar<'a, T>: Sized { - fn cover(value: T, p: &mut Parser<'a>) -> Result; + fn cover(value: T, p: &mut ParserImpl<'a>) -> Result; } impl<'a> CoverGrammar<'a, Expression<'a>> for AssignmentTarget<'a> { - fn cover(expr: Expression<'a>, p: &mut Parser<'a>) -> Result { + fn cover(expr: Expression<'a>, p: &mut ParserImpl<'a>) -> Result { match expr { Expression::ArrayExpression(array_expr) => { ArrayAssignmentTarget::cover(array_expr.unbox(), p) @@ -34,7 +34,7 @@ impl<'a> CoverGrammar<'a, Expression<'a>> for AssignmentTarget<'a> { impl<'a> CoverGrammar<'a, Expression<'a>> for SimpleAssignmentTarget<'a> { #[allow(clippy::only_used_in_recursion)] - fn cover(expr: Expression<'a>, p: &mut Parser<'a>) -> Result { + fn cover(expr: Expression<'a>, p: &mut ParserImpl<'a>) -> Result { match expr { Expression::Identifier(ident) => { Ok(SimpleAssignmentTarget::AssignmentTargetIdentifier(ident)) @@ -65,7 +65,7 @@ impl<'a> CoverGrammar<'a, Expression<'a>> for SimpleAssignmentTarget<'a> { } impl<'a> CoverGrammar<'a, ArrayExpression<'a>> for ArrayAssignmentTarget<'a> { - fn cover(expr: ArrayExpression<'a>, p: &mut Parser<'a>) -> Result { + fn cover(expr: ArrayExpression<'a>, p: &mut ParserImpl<'a>) -> Result { let mut elements = p.ast.new_vec(); let mut rest = None; @@ -100,7 +100,7 @@ impl<'a> CoverGrammar<'a, ArrayExpression<'a>> for ArrayAssignmentTarget<'a> { } impl<'a> CoverGrammar<'a, Expression<'a>> for AssignmentTargetMaybeDefault<'a> { - fn cover(expr: Expression<'a>, p: &mut Parser<'a>) -> Result { + fn cover(expr: Expression<'a>, p: &mut ParserImpl<'a>) -> Result { match expr { Expression::AssignmentExpression(assignment_expr) => { let target = AssignmentTargetWithDefault::cover(assignment_expr.unbox(), p)?; @@ -115,13 +115,13 @@ impl<'a> CoverGrammar<'a, Expression<'a>> for AssignmentTargetMaybeDefault<'a> { } impl<'a> CoverGrammar<'a, AssignmentExpression<'a>> for AssignmentTargetWithDefault<'a> { - fn cover(expr: AssignmentExpression<'a>, _p: &mut Parser<'a>) -> Result { + fn cover(expr: AssignmentExpression<'a>, _p: &mut ParserImpl<'a>) -> Result { Ok(Self { span: expr.span, binding: expr.left, init: expr.right }) } } impl<'a> CoverGrammar<'a, ObjectExpression<'a>> for ObjectAssignmentTarget<'a> { - fn cover(expr: ObjectExpression<'a>, p: &mut Parser<'a>) -> Result { + fn cover(expr: ObjectExpression<'a>, p: &mut ParserImpl<'a>) -> Result { let mut properties = p.ast.new_vec(); let mut rest = None; @@ -147,7 +147,7 @@ impl<'a> CoverGrammar<'a, ObjectExpression<'a>> for ObjectAssignmentTarget<'a> { } impl<'a> CoverGrammar<'a, ObjectProperty<'a>> for AssignmentTargetProperty<'a> { - fn cover(property: ObjectProperty<'a>, p: &mut Parser<'a>) -> Result { + fn cover(property: ObjectProperty<'a>, p: &mut ParserImpl<'a>) -> Result { if property.shorthand { let binding = match property.key { PropertyKey::Identifier(ident) => { diff --git a/crates/oxc_parser/src/js/list.rs b/crates/oxc_parser/src/js/list.rs index 6695a6cf03be2..f427340f3b2db 100644 --- a/crates/oxc_parser/src/js/list.rs +++ b/crates/oxc_parser/src/js/list.rs @@ -12,7 +12,7 @@ use crate::{ diagnostics, lexer::Kind, list::{NormalList, SeparatedList}, - Parser, + ParserImpl, }; #[derive(Debug, Error, Diagnostic)] @@ -31,7 +31,7 @@ pub struct ObjectExpressionProperties<'a> { } impl<'a> SeparatedList<'a> for ObjectExpressionProperties<'a> { - fn new(p: &Parser<'a>) -> Self { + fn new(p: &ParserImpl<'a>) -> Self { Self { elements: p.ast.new_vec(), trailing_comma: None } } @@ -43,7 +43,7 @@ impl<'a> SeparatedList<'a> for ObjectExpressionProperties<'a> { Kind::RCurly } - fn parse_element(&mut self, p: &mut Parser<'a>) -> Result<()> { + fn parse_element(&mut self, p: &mut ParserImpl<'a>) -> Result<()> { let element = match p.cur_kind() { Kind::Dot3 => p.parse_spread_element().map(ObjectPropertyKind::SpreadProperty), _ => p.parse_property_definition().map(ObjectPropertyKind::ObjectProperty), @@ -65,7 +65,7 @@ pub struct ObjectPatternProperties<'a> { } impl<'a> SeparatedList<'a> for ObjectPatternProperties<'a> { - fn new(p: &Parser<'a>) -> Self { + fn new(p: &ParserImpl<'a>) -> Self { Self { elements: p.ast.new_vec(), rest: None } } @@ -77,7 +77,7 @@ impl<'a> SeparatedList<'a> for ObjectPatternProperties<'a> { Kind::RCurly } - fn parse_element(&mut self, p: &mut Parser<'a>) -> Result<()> { + fn parse_element(&mut self, p: &mut ParserImpl<'a>) -> Result<()> { if p.cur_kind() == Kind::Dot3 { let rest = p.parse_rest_element()?; if !matches!(&rest.argument.kind, BindingPatternKind::BindingIdentifier(_)) { @@ -101,7 +101,7 @@ pub struct ArrayExpressionList<'a> { } impl<'a> SeparatedList<'a> for ArrayExpressionList<'a> { - fn new(p: &Parser<'a>) -> Self { + fn new(p: &ParserImpl<'a>) -> Self { Self { elements: p.ast.new_vec(), trailing_comma: None } } @@ -113,7 +113,7 @@ impl<'a> SeparatedList<'a> for ArrayExpressionList<'a> { Kind::RBrack } - fn parse_element(&mut self, p: &mut Parser<'a>) -> Result<()> { + fn parse_element(&mut self, p: &mut ParserImpl<'a>) -> Result<()> { let element = match p.cur_kind() { Kind::Comma => Ok(p.parse_elision()), Kind::Dot3 => p.parse_spread_element().map(ArrayExpressionElement::SpreadElement), @@ -136,7 +136,7 @@ pub struct ArrayPatternList<'a> { } impl<'a> SeparatedList<'a> for ArrayPatternList<'a> { - fn new(p: &Parser<'a>) -> Self { + fn new(p: &ParserImpl<'a>) -> Self { Self { elements: p.ast.new_vec(), rest: None } } @@ -148,7 +148,7 @@ impl<'a> SeparatedList<'a> for ArrayPatternList<'a> { Kind::RBrack } - fn parse_element(&mut self, p: &mut Parser<'a>) -> Result<()> { + fn parse_element(&mut self, p: &mut ParserImpl<'a>) -> Result<()> { match p.cur_kind() { Kind::Comma => { self.elements.push(None); @@ -175,7 +175,7 @@ pub struct CallArguments<'a> { } impl<'a> SeparatedList<'a> for CallArguments<'a> { - fn new(p: &Parser<'a>) -> Self { + fn new(p: &ParserImpl<'a>) -> Self { Self { elements: p.ast.new_vec(), rest_element_with_trilling_comma: None } } @@ -187,7 +187,7 @@ impl<'a> SeparatedList<'a> for CallArguments<'a> { Kind::RParen } - fn parse_element(&mut self, p: &mut Parser<'a>) -> Result<()> { + fn parse_element(&mut self, p: &mut ParserImpl<'a>) -> Result<()> { let element = if p.at(Kind::Dot3) { let result = p.parse_spread_element().map(Argument::SpreadElement); if p.at(Kind::Comma) { @@ -209,7 +209,7 @@ pub struct SequenceExpressionList<'a> { } impl<'a> SeparatedList<'a> for SequenceExpressionList<'a> { - fn new(p: &Parser<'a>) -> Self { + fn new(p: &ParserImpl<'a>) -> Self { Self { elements: p.ast.new_vec() } } @@ -223,7 +223,7 @@ impl<'a> SeparatedList<'a> for SequenceExpressionList<'a> { // read everything as expression and map to it to either // ParenthesizedExpression or ArrowFormalParameters later - fn parse_element(&mut self, p: &mut Parser<'a>) -> Result<()> { + fn parse_element(&mut self, p: &mut ParserImpl<'a>) -> Result<()> { let element = p.parse_assignment_expression_base()?; self.elements.push(element); Ok(()) @@ -238,7 +238,7 @@ pub struct FormalParameterList<'a> { } impl<'a> SeparatedList<'a> for FormalParameterList<'a> { - fn new(p: &Parser<'a>) -> Self { + fn new(p: &ParserImpl<'a>) -> Self { Self { elements: p.ast.new_vec(), rest: None, this_param: None } } @@ -251,7 +251,7 @@ impl<'a> SeparatedList<'a> for FormalParameterList<'a> { } // Section 15.1 Parameter Lists - fn parse_element(&mut self, p: &mut Parser<'a>) -> Result<()> { + fn parse_element(&mut self, p: &mut ParserImpl<'a>) -> Result<()> { let span = p.start_span(); p.eat_decorators()?; @@ -295,7 +295,7 @@ pub struct AssertEntries<'a> { } impl<'a> SeparatedList<'a> for AssertEntries<'a> { - fn new(p: &Parser<'a>) -> Self { + fn new(p: &ParserImpl<'a>) -> Self { Self { elements: p.ast.new_vec(), keys: FxHashMap::default() } } @@ -307,7 +307,7 @@ impl<'a> SeparatedList<'a> for AssertEntries<'a> { Kind::RCurly } - fn parse_element(&mut self, p: &mut Parser<'a>) -> Result<()> { + fn parse_element(&mut self, p: &mut ParserImpl<'a>) -> Result<()> { let span = p.start_span(); let key = match p.cur_kind() { Kind::Str => ImportAttributeKey::StringLiteral(p.parse_literal_string()?), @@ -333,7 +333,7 @@ pub struct ExportNamedSpecifiers<'a> { } impl<'a> SeparatedList<'a> for ExportNamedSpecifiers<'a> { - fn new(p: &Parser<'a>) -> Self { + fn new(p: &ParserImpl<'a>) -> Self { Self { elements: p.ast.new_vec() } } @@ -345,7 +345,7 @@ impl<'a> SeparatedList<'a> for ExportNamedSpecifiers<'a> { Kind::RCurly } - fn parse_element(&mut self, p: &mut Parser<'a>) -> Result<()> { + fn parse_element(&mut self, p: &mut ParserImpl<'a>) -> Result<()> { let specifier_span = p.start_span(); let peek_kind = p.peek_kind(); @@ -396,13 +396,13 @@ pub struct ClassElements<'a> { } impl<'a> ClassElements<'a> { - pub(crate) fn new(p: &Parser<'a>) -> Self { + pub(crate) fn new(p: &ParserImpl<'a>) -> Self { Self { elements: p.ast.new_vec(), private_bound_identifiers: FxHashMap::default() } } fn detect_private_name_conflict( &self, - p: &mut Parser, + p: &mut ParserImpl, private_ident: &PrivateIdentifier, r#static: bool, kind: Option, @@ -430,7 +430,7 @@ impl<'a> ClassElements<'a> { fn on_declare_private_property( &mut self, - p: &mut Parser, + p: &mut ParserImpl, private_ident: &PrivateIdentifier, r#static: bool, kind: Option, @@ -453,7 +453,7 @@ impl<'a> NormalList<'a> for ClassElements<'a> { Kind::RCurly } - fn parse_element(&mut self, p: &mut Parser<'a>) -> Result<()> { + fn parse_element(&mut self, p: &mut ParserImpl<'a>) -> Result<()> { // skip empty class element `;` while p.at(Kind::Semicolon) { p.bump_any(); @@ -482,7 +482,7 @@ pub struct SwitchCases<'a> { } impl<'a> SwitchCases<'a> { - pub(crate) fn new(p: &Parser<'a>) -> Self { + pub(crate) fn new(p: &ParserImpl<'a>) -> Self { Self { elements: p.ast.new_vec() } } } @@ -496,7 +496,7 @@ impl<'a> NormalList<'a> for SwitchCases<'a> { Kind::RCurly } - fn parse_element(&mut self, p: &mut Parser<'a>) -> Result<()> { + fn parse_element(&mut self, p: &mut ParserImpl<'a>) -> Result<()> { let element = p.parse_switch_case()?; self.elements.push(element); Ok(()) @@ -508,7 +508,7 @@ pub struct ImportSpecifierList<'a> { } impl<'a> SeparatedList<'a> for ImportSpecifierList<'a> { - fn new(p: &Parser<'a>) -> Self { + fn new(p: &ParserImpl<'a>) -> Self { Self { import_specifiers: p.ast.new_vec() } } @@ -520,7 +520,7 @@ impl<'a> SeparatedList<'a> for ImportSpecifierList<'a> { Kind::RCurly } - fn parse_element(&mut self, p: &mut Parser<'a>) -> Result<()> { + fn parse_element(&mut self, p: &mut ParserImpl<'a>) -> Result<()> { let import_specifier = p.parse_import_specifier()?; let specifier = ImportDeclarationSpecifier::ImportSpecifier(import_specifier); self.import_specifiers.push(specifier); diff --git a/crates/oxc_parser/src/js/module.rs b/crates/oxc_parser/src/js/module.rs index e2fa58e02fb01..ce820d2dfb85f 100644 --- a/crates/oxc_parser/src/js/module.rs +++ b/crates/oxc_parser/src/js/module.rs @@ -7,9 +7,9 @@ use super::{ function::FunctionKind, list::{AssertEntries, ExportNamedSpecifiers, ImportSpecifierList}, }; -use crate::{diagnostics, lexer::Kind, list::SeparatedList, Context, Parser}; +use crate::{diagnostics, lexer::Kind, list::SeparatedList, Context, ParserImpl}; -impl<'a> Parser<'a> { +impl<'a> ParserImpl<'a> { /// [Import Call](https://tc39.es/ecma262/#sec-import-calls) /// `ImportCall` : import ( `AssignmentExpression` ) pub(crate) fn parse_import_expression(&mut self, span: Span) -> Result> { diff --git a/crates/oxc_parser/src/js/object.rs b/crates/oxc_parser/src/js/object.rs index 31ebcda7b9046..c0115254404d0 100644 --- a/crates/oxc_parser/src/js/object.rs +++ b/crates/oxc_parser/src/js/object.rs @@ -5,9 +5,9 @@ use oxc_span::Span; use oxc_syntax::operator::AssignmentOperator; use super::list::ObjectExpressionProperties; -use crate::{lexer::Kind, list::SeparatedList, Parser}; +use crate::{lexer::Kind, list::SeparatedList, ParserImpl}; -impl<'a> Parser<'a> { +impl<'a> ParserImpl<'a> { /// [Object Expression](https://tc39.es/ecma262/#sec-object-initializer) /// `ObjectLiteral`[Yield, Await] : /// { } diff --git a/crates/oxc_parser/src/js/statement.rs b/crates/oxc_parser/src/js/statement.rs index 4e8c8ef5e5f84..10838d1b070e2 100644 --- a/crates/oxc_parser/src/js/statement.rs +++ b/crates/oxc_parser/src/js/statement.rs @@ -8,9 +8,9 @@ use super::{ grammar::CoverGrammar, list::SwitchCases, }; -use crate::{diagnostics, lexer::Kind, list::NormalList, Context, Parser, StatementContext}; +use crate::{diagnostics, lexer::Kind, list::NormalList, Context, ParserImpl, StatementContext}; -impl<'a> Parser<'a> { +impl<'a> ParserImpl<'a> { // Section 12 // The InputElementHashbangOrRegExp goal is used at the start of a Script // or Module. @@ -283,7 +283,7 @@ impl<'a> Parser<'a> { return self.parse_for_loop(span, None, r#await); } - let init_expression = self.without_context(Context::In, Parser::parse_expression)?; + let init_expression = self.without_context(Context::In, ParserImpl::parse_expression)?; // for (a.b in ...), for ([a] in ..), for ({a} in ..) if self.at(Kind::In) || self.at(Kind::Of) { @@ -359,7 +359,7 @@ impl<'a> Parser<'a> { ) -> Result> { self.expect(Kind::Semicolon)?; let test = if !self.at(Kind::Semicolon) && !self.at(Kind::RParen) { - Some(self.with_context(Context::In, Parser::parse_expression)?) + Some(self.with_context(Context::In, ParserImpl::parse_expression)?) } else { None }; @@ -367,7 +367,7 @@ impl<'a> Parser<'a> { let update = if self.at(Kind::RParen) { None } else { - Some(self.with_context(Context::In, Parser::parse_expression)?) + Some(self.with_context(Context::In, ParserImpl::parse_expression)?) }; self.expect(Kind::RParen)?; if r#await { @@ -433,7 +433,7 @@ impl<'a> Parser<'a> { let argument = if self.eat(Kind::Semicolon) || self.can_insert_semicolon() { None } else { - let expr = self.with_context(Context::In, Parser::parse_expression)?; + let expr = self.with_context(Context::In, 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 4d5fd7db11370..5ab9d1a4289fe 100644 --- a/crates/oxc_parser/src/jsx/mod.rs +++ b/crates/oxc_parser/src/jsx/mod.rs @@ -7,9 +7,9 @@ use oxc_ast::ast::*; use oxc_diagnostics::Result; use oxc_span::{Atom, Span}; -use crate::{diagnostics, lexer::Kind, Context, Parser}; +use crate::{diagnostics, lexer::Kind, Context, ParserImpl}; -impl<'a> Parser<'a> { +impl<'a> ParserImpl<'a> { pub(crate) fn parse_jsx_expression(&mut self) -> Result> { if self.peek_at(Kind::RAngle) { self.parse_jsx_fragment(false).map(Expression::JSXFragment) diff --git a/crates/oxc_parser/src/lib.rs b/crates/oxc_parser/src/lib.rs index 4f227f51c436c..719c0cbc434f7 100644 --- a/crates/oxc_parser/src/lib.rs +++ b/crates/oxc_parser/src/lib.rs @@ -116,10 +116,70 @@ pub struct ParserReturn<'a> { pub panicked: bool, } +/// Parser options +#[derive(Clone, Copy)] +struct ParserOptions { + pub allow_return_outside_function: bool, + pub preserve_parens: bool, +} + +impl Default for ParserOptions { + fn default() -> Self { + Self { allow_return_outside_function: false, preserve_parens: true } + } +} + /// Recursive Descent Parser for ECMAScript and TypeScript /// /// See [`Parser::parse`] for entry function. pub struct Parser<'a> { + allocator: &'a Allocator, + source_text: &'a str, + source_type: SourceType, + options: ParserOptions, +} + +impl<'a> Parser<'a> { + /// Create a new parser + pub fn new(allocator: &'a Allocator, source_text: &'a str, source_type: SourceType) -> Self { + let options = ParserOptions::default(); + Self { allocator, source_text, source_type, options } + } + + /// Allow return outside of function + /// + /// By default, a return statement at the top level raises an error. + /// Set this to true to accept such code. + #[must_use] + pub fn allow_return_outside_function(mut self, allow: bool) -> Self { + self.options.allow_return_outside_function = allow; + self + } + + /// Emit `ParenthesizedExpression` in AST. + /// + /// If this option is true, parenthesized expressions are represented by (non-standard) + /// `ParenthesizedExpression` nodes that have a single expression property containing the expression inside parentheses. + #[must_use] + pub fn preserve_parens(mut self, allow: bool) -> Self { + self.options.preserve_parens = allow; + self + } + + /// Main entry point + /// + /// Returns an empty `Program` on unrecoverable error, + /// Recoverable errors are stored inside `errors`. + pub fn parse(self) -> ParserReturn<'a> { + let parser = + ParserImpl::new(self.allocator, self.source_text, self.source_type, self.options); + parser.parse() + } +} + +/// Implementation of parser. +/// `Parser` is just a public wrapper, the guts of the implementation is in this type. +struct ParserImpl<'a> { lexer: Lexer<'a>, /// SourceType: JavaScript or TypeScript, Script or Module, jsx support? @@ -152,9 +212,14 @@ pub struct Parser<'a> { preserve_parens: bool, } -impl<'a> Parser<'a> { +impl<'a> ParserImpl<'a> { /// Create a new parser - pub fn new(allocator: &'a Allocator, source_text: &'a str, source_type: SourceType) -> Self { + pub fn new( + allocator: &'a Allocator, + source_text: &'a str, + source_type: SourceType, + options: ParserOptions, + ) -> Self { Self { lexer: Lexer::new(allocator, source_text, source_type), source_type, @@ -163,32 +228,12 @@ impl<'a> Parser<'a> { token: Token::default(), prev_token_end: 0, state: ParserState::new(allocator), - ctx: Self::default_context(source_type), + ctx: Self::default_context(source_type, options), ast: AstBuilder::new(allocator), - preserve_parens: true, + preserve_parens: options.preserve_parens, } } - /// Allow return outside of function - /// - /// By default, a return statement at the top level raises an error. - /// Set this to true to accept such code. - #[must_use] - pub fn allow_return_outside_function(mut self, allow: bool) -> Self { - self.ctx = self.ctx.and_return(allow); - self - } - - /// Emit `ParenthesizedExpression` in AST. - /// - /// If this option is true, parenthesized expressions are represented by (non-standard) - /// `ParenthesizedExpression` nodes that have a single expression property containing the expression inside parentheses. - #[must_use] - pub fn preserve_parens(mut self, allow: bool) -> Self { - self.preserve_parens = allow; - self - } - /// Main entry point /// /// Returns an empty `Program` on unrecoverable error, @@ -228,13 +273,16 @@ impl<'a> Parser<'a> { Ok(self.ast.program(span, self.source_type, directives, hashbang, statements)) } - fn default_context(source_type: SourceType) -> Context { - let ctx = Context::default().and_ambient(source_type.is_typescript_definition()); - match source_type.module_kind() { - ModuleKind::Script => ctx, + fn default_context(source_type: SourceType, options: ParserOptions) -> Context { + let mut ctx = Context::default().and_ambient(source_type.is_typescript_definition()); + if source_type.module_kind() == ModuleKind::Module { // for [top-level-await](https://tc39.es/proposal-top-level-await/) - ModuleKind::Module => ctx.and_await(true), + ctx = ctx.and_await(true); + } + if options.allow_return_outside_function { + ctx = ctx.and_return(true); } + ctx } /// Check for Flow declaration if the file cannot be parsed. diff --git a/crates/oxc_parser/src/list.rs b/crates/oxc_parser/src/list.rs index 6931a06f3781b..0b50ac1dcc696 100644 --- a/crates/oxc_parser/src/list.rs +++ b/crates/oxc_parser/src/list.rs @@ -1,6 +1,6 @@ use oxc_diagnostics::Result; -use crate::{lexer::Kind, Parser}; +use crate::{lexer::Kind, ParserImpl}; pub trait NormalList<'a> { /// Open element, e.g.. `{` `[` `(` @@ -9,10 +9,10 @@ pub trait NormalList<'a> { /// Close element, e.g.. `}` `]` `)` fn close(&self) -> Kind; - fn parse_element(&mut self, p: &mut Parser<'a>) -> Result<()>; + fn parse_element(&mut self, p: &mut ParserImpl<'a>) -> Result<()>; /// Main entry point, parse the list - fn parse(&mut self, p: &mut Parser<'a>) -> Result<()> { + fn parse(&mut self, p: &mut ParserImpl<'a>) -> Result<()> { p.expect(self.open())?; while !p.at(self.close()) && !p.at(Kind::Eof) { self.parse_element(p)?; @@ -23,9 +23,9 @@ pub trait NormalList<'a> { } pub trait SeparatedList<'a>: Sized { - fn new(p: &Parser<'a>) -> Self; + fn new(p: &ParserImpl<'a>) -> Self; - fn parse(p: &mut Parser<'a>) -> Result { + fn parse(p: &mut ParserImpl<'a>) -> Result { let mut list = Self::new(p); list.parse_list(p)?; Ok(list) @@ -42,10 +42,10 @@ pub trait SeparatedList<'a>: Sized { Kind::Comma } - fn parse_element(&mut self, p: &mut Parser<'a>) -> Result<()>; + fn parse_element(&mut self, p: &mut ParserImpl<'a>) -> Result<()>; /// Main entry point, parse the list - fn parse_list(&mut self, p: &mut Parser<'a>) -> Result<()> { + fn parse_list(&mut self, p: &mut ParserImpl<'a>) -> Result<()> { p.expect(self.open())?; let mut first = true; diff --git a/crates/oxc_parser/src/ts/declaration.rs b/crates/oxc_parser/src/ts/declaration.rs index b4d6c466fb480..e70aee357c8cb 100644 --- a/crates/oxc_parser/src/ts/declaration.rs +++ b/crates/oxc_parser/src/ts/declaration.rs @@ -1,6 +1,6 @@ -use crate::{lexer::Kind, Parser}; +use crate::{lexer::Kind, ParserImpl}; -impl<'a> Parser<'a> { +impl<'a> ParserImpl<'a> { /// Check if the parser is at a start of a declaration fn at_start_of_ts_declaration_worker(&mut self) -> bool { loop { @@ -80,11 +80,12 @@ mod test_is_declaration { use oxc_span::SourceType; use super::*; + use crate::ParserOptions; fn run_check(source: &str, expected: bool) { let alloc = Allocator::default(); let source_type = SourceType::default().with_typescript(true); - let mut parser = Parser::new(&alloc, source, source_type); + let mut parser = ParserImpl::new(&alloc, source, source_type, ParserOptions::default()); // Get the parser to the first token. parser.bump_any(); assert_eq!(expected, parser.at_start_of_ts_declaration()); diff --git a/crates/oxc_parser/src/ts/list.rs b/crates/oxc_parser/src/ts/list.rs index 694da7e7ddc52..a62f70267a0e4 100644 --- a/crates/oxc_parser/src/ts/list.rs +++ b/crates/oxc_parser/src/ts/list.rs @@ -5,7 +5,7 @@ use oxc_diagnostics::Result; use crate::{ lexer::Kind, list::{NormalList, SeparatedList}, - Parser, + ParserImpl, }; pub struct TSEnumMemberList<'a> { @@ -13,7 +13,7 @@ pub struct TSEnumMemberList<'a> { } impl<'a> SeparatedList<'a> for TSEnumMemberList<'a> { - fn new(p: &Parser<'a>) -> Self { + fn new(p: &ParserImpl<'a>) -> Self { Self { members: p.ast.new_vec() } } @@ -25,7 +25,7 @@ impl<'a> SeparatedList<'a> for TSEnumMemberList<'a> { Kind::RCurly } - fn parse_element(&mut self, p: &mut Parser<'a>) -> Result<()> { + fn parse_element(&mut self, p: &mut ParserImpl<'a>) -> Result<()> { let element = p.parse_ts_enum_member()?; self.members.push(element); Ok(()) @@ -37,7 +37,7 @@ pub struct TSTupleElementList<'a> { } impl<'a> SeparatedList<'a> for TSTupleElementList<'a> { - fn new(p: &Parser<'a>) -> Self { + fn new(p: &ParserImpl<'a>) -> Self { Self { elements: p.ast.new_vec() } } @@ -49,7 +49,7 @@ impl<'a> SeparatedList<'a> for TSTupleElementList<'a> { Kind::RBrack } - fn parse_element(&mut self, p: &mut Parser<'a>) -> Result<()> { + fn parse_element(&mut self, p: &mut ParserImpl<'a>) -> Result<()> { let span = p.start_span(); if p.is_at_named_tuple_element() { let _is_rest = p.eat(Kind::Dot3); @@ -91,7 +91,7 @@ pub struct TSTypeParameterList<'a> { } impl<'a> SeparatedList<'a> for TSTypeParameterList<'a> { - fn new(p: &Parser<'a>) -> Self { + fn new(p: &ParserImpl<'a>) -> Self { Self { params: p.ast.new_vec() } } @@ -103,7 +103,7 @@ impl<'a> SeparatedList<'a> for TSTypeParameterList<'a> { Kind::RAngle } - fn parse_element(&mut self, p: &mut Parser<'a>) -> Result<()> { + fn parse_element(&mut self, p: &mut ParserImpl<'a>) -> Result<()> { let param = p.parse_ts_type_parameter()?; self.params.push(param); Ok(()) @@ -115,7 +115,7 @@ pub struct TSInterfaceOrObjectBodyList<'a> { } impl<'a> TSInterfaceOrObjectBodyList<'a> { - pub(crate) fn new(p: &Parser<'a>) -> Self { + pub(crate) fn new(p: &ParserImpl<'a>) -> Self { Self { body: p.ast.new_vec() } } } @@ -129,7 +129,7 @@ impl<'a> NormalList<'a> for TSInterfaceOrObjectBodyList<'a> { Kind::RCurly } - fn parse_element(&mut self, p: &mut Parser<'a>) -> Result<()> { + fn parse_element(&mut self, p: &mut ParserImpl<'a>) -> Result<()> { let property = p.parse_ts_type_signature()?; self.body.push(property); Ok(()) @@ -141,7 +141,7 @@ pub struct TSTypeArgumentList<'a> { } impl<'a> SeparatedList<'a> for TSTypeArgumentList<'a> { - fn new(p: &Parser<'a>) -> Self { + fn new(p: &ParserImpl<'a>) -> Self { Self { params: p.ast.new_vec() } } @@ -153,7 +153,7 @@ impl<'a> SeparatedList<'a> for TSTypeArgumentList<'a> { Kind::RAngle } - fn parse_element(&mut self, p: &mut Parser<'a>) -> Result<()> { + fn parse_element(&mut self, p: &mut ParserImpl<'a>) -> Result<()> { let ty = p.parse_ts_type()?; self.params.push(ty); Ok(()) diff --git a/crates/oxc_parser/src/ts/statement.rs b/crates/oxc_parser/src/ts/statement.rs index 7cd0077c60bd3..0954d9c79626e 100644 --- a/crates/oxc_parser/src/ts/statement.rs +++ b/crates/oxc_parser/src/ts/statement.rs @@ -14,10 +14,10 @@ use crate::{ }, lexer::Kind, list::{NormalList, SeparatedList}, - Parser, StatementContext, + ParserImpl, StatementContext, }; -impl<'a> Parser<'a> { +impl<'a> ParserImpl<'a> { /** ------------------- Enum ------------------ */ pub(crate) fn is_at_enum_declaration(&mut self) -> bool { diff --git a/crates/oxc_parser/src/ts/types.rs b/crates/oxc_parser/src/ts/types.rs index 4680b7195c6a0..ca1362a9c6acb 100644 --- a/crates/oxc_parser/src/ts/types.rs +++ b/crates/oxc_parser/src/ts/types.rs @@ -12,7 +12,7 @@ use crate::{ js::list::{ArrayPatternList, ObjectPatternProperties}, lexer::Kind, list::{NormalList, SeparatedList}, - Context, Parser, + Context, ParserImpl, }; bitflags! { @@ -105,7 +105,7 @@ impl ModifierFlags { } } -impl<'a> Parser<'a> { +impl<'a> ParserImpl<'a> { pub(crate) fn parse_ts_type(&mut self) -> Result> { if self.is_at_constructor_type() { return self.parse_ts_constructor_type(); @@ -323,8 +323,8 @@ impl<'a> Parser<'a> { )); } - let mut left = - self.without_context(Context::DisallowConditionalTypes, Parser::parse_ts_basic_type)?; + let mut left = self + .without_context(Context::DisallowConditionalTypes, ParserImpl::parse_ts_basic_type)?; while !self.cur_token().is_on_new_line && self.eat(Kind::LBrack) { if self.eat(Kind::RBrack) { @@ -828,7 +828,7 @@ impl<'a> Parser<'a> { let parameter_span = self.start_span(); let name = self.parse_binding_identifier()?; - let constraint = self.try_parse(Parser::parse_constraint_of_infer_type).unwrap_or(None); + let constraint = self.try_parse(ParserImpl::parse_constraint_of_infer_type).unwrap_or(None); let type_parameter = self.ast.ts_type_parameter( self.end_span(parameter_span),