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.
This commit is contained in:
overlookmotel 2024-02-07 15:22:08 +00:00 committed by GitHub
parent 3268d7d66e
commit 0bdecb5043
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
18 changed files with 169 additions and 120 deletions

View file

@ -7,7 +7,7 @@ use oxc_span::Span;
use crate::{ use crate::{
diagnostics, diagnostics,
lexer::{Kind, LexerCheckpoint, LexerContext, Token}, lexer::{Kind, LexerCheckpoint, LexerContext, Token},
Context, Parser, Context, ParserImpl,
}; };
#[derive(Clone, Copy)] #[derive(Clone, Copy)]
@ -18,7 +18,7 @@ pub struct ParserCheckpoint<'a> {
errors_pos: usize, errors_pos: usize,
} }
impl<'a> Parser<'a> { impl<'a> ParserImpl<'a> {
pub(crate) fn start_span(&self) -> Span { pub(crate) fn start_span(&self) -> Span {
let token = self.cur_token(); let token = self.cur_token();
Span::new(token.start, 0) Span::new(token.start, 0)
@ -266,7 +266,7 @@ impl<'a> Parser<'a> {
/// # Errors /// # Errors
pub(crate) fn try_parse<T>( pub(crate) fn try_parse<T>(
&mut self, &mut self,
func: impl FnOnce(&mut Parser<'a>) -> Result<T>, func: impl FnOnce(&mut ParserImpl<'a>) -> Result<T>,
) -> Result<T> { ) -> Result<T> {
let checkpoint = self.checkpoint(); let checkpoint = self.checkpoint();
let ctx = self.ctx; let ctx = self.ctx;
@ -278,7 +278,7 @@ impl<'a> Parser<'a> {
result result
} }
pub(crate) fn lookahead<U>(&mut self, predicate: impl Fn(&mut Parser<'a>) -> U) -> U { pub(crate) fn lookahead<U>(&mut self, predicate: impl Fn(&mut ParserImpl<'a>) -> U) -> U {
let checkpoint = self.checkpoint(); let checkpoint = self.checkpoint();
let answer = predicate(self); let answer = predicate(self);
self.rewind(checkpoint); self.rewind(checkpoint);

View file

@ -4,9 +4,9 @@ use oxc_diagnostics::Result;
use oxc_span::Span; use oxc_span::Span;
use super::list::{ArrayPatternList, ObjectPatternProperties}; 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 /// Destructuring Binding Patterns
/// `LexicalBinding` /// `LexicalBinding`
/// `BindingIdentifier` `Initializer_opt` /// `BindingIdentifier` `Initializer_opt`

View file

@ -4,7 +4,7 @@ use oxc_diagnostics::Result;
use oxc_span::{GetSpan, Span}; use oxc_span::{GetSpan, Span};
use super::list::ClassElements; 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> = type Extends<'a> =
Vec<'a, (Expression<'a>, Option<Box<'a, TSTypeParameterInstantiation<'a>>>, Span)>; Vec<'a, (Expression<'a>, Option<Box<'a, TSTypeParameterInstantiation<'a>>>, Span)>;
@ -12,7 +12,7 @@ type Extends<'a> =
type Implements<'a> = Vec<'a, Box<'a, TSClassImplements<'a>>>; type Implements<'a> = Vec<'a, Box<'a, TSClassImplements<'a>>>;
/// Section 15.7 Class Definitions /// 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. // `start_span` points at the start of all decoractors and `class` keyword.
pub(crate) fn parse_class_statement( pub(crate) fn parse_class_statement(
&mut self, &mut self,

View file

@ -3,7 +3,7 @@ use oxc_ast::ast::*;
use oxc_diagnostics::Result; use oxc_diagnostics::Result;
use oxc_span::{GetSpan, Span}; 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)] #[derive(Clone, Debug, Copy, Eq, PartialEq)]
pub enum VariableDeclarationParent { 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<Statement<'a>> { pub(crate) fn parse_let(&mut self, stmt_ctx: StatementContext) -> Result<Statement<'a>> {
let span = self.start_span(); let span = self.start_span();
let peeked = self.peek_kind(); let peeked = self.peek_kind();

View file

@ -19,10 +19,10 @@ use crate::{
diagnostics, diagnostics,
lexer::{parse_big_int, parse_float, parse_int, Kind}, lexer::{parse_big_int, parse_float, parse_int, Kind},
list::SeparatedList, list::SeparatedList,
Context, Parser, Context, ParserImpl,
}; };
impl<'a> Parser<'a> { impl<'a> ParserImpl<'a> {
pub(crate) fn parse_paren_expression(&mut self) -> Result<Expression<'a>> { pub(crate) fn parse_paren_expression(&mut self) -> Result<Expression<'a>> {
self.expect(Kind::LParen)?; self.expect(Kind::LParen)?;
let expression = self.parse_expression()?; let expression = self.parse_expression()?;
@ -977,7 +977,7 @@ impl<'a> Parser<'a> {
let pos = self.cur_token().start; let pos = self.cur_token().start;
if !self.state.not_parenthesized_arrow.contains(&pos) { if !self.state.not_parenthesized_arrow.contains(&pos) {
if let Ok((type_parameters, params, return_type, r#async, span)) = 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( return self.parse_arrow_function_body(
span, span,

View file

@ -6,7 +6,7 @@ use oxc_diagnostics::Result;
use oxc_span::{GetSpan, Span}; use oxc_span::{GetSpan, Span};
use super::list::FormalParameterList; 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> = ( type ArrowFunctionHead<'a> = (
Option<Box<'a, TSTypeParameterDeclaration<'a>>>, Option<Box<'a, TSTypeParameterDeclaration<'a>>>,
@ -41,7 +41,7 @@ impl FunctionKind {
} }
} }
impl<'a> Parser<'a> { impl<'a> ParserImpl<'a> {
pub(crate) fn at_function_with_async(&mut self) -> bool { pub(crate) fn at_function_with_async(&mut self) -> bool {
self.at(Kind::Function) self.at(Kind::Function)
|| self.at(Kind::Async) || self.at(Kind::Async)

View file

@ -4,14 +4,14 @@ use oxc_ast::ast::*;
use oxc_diagnostics::Result; use oxc_diagnostics::Result;
use oxc_span::GetSpan; use oxc_span::GetSpan;
use crate::{diagnostics, Parser}; use crate::{diagnostics, ParserImpl};
pub trait CoverGrammar<'a, T>: Sized { pub trait CoverGrammar<'a, T>: Sized {
fn cover(value: T, p: &mut Parser<'a>) -> Result<Self>; fn cover(value: T, p: &mut ParserImpl<'a>) -> Result<Self>;
} }
impl<'a> CoverGrammar<'a, Expression<'a>> for AssignmentTarget<'a> { impl<'a> CoverGrammar<'a, Expression<'a>> for AssignmentTarget<'a> {
fn cover(expr: Expression<'a>, p: &mut Parser<'a>) -> Result<Self> { fn cover(expr: Expression<'a>, p: &mut ParserImpl<'a>) -> Result<Self> {
match expr { match expr {
Expression::ArrayExpression(array_expr) => { Expression::ArrayExpression(array_expr) => {
ArrayAssignmentTarget::cover(array_expr.unbox(), p) 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> { impl<'a> CoverGrammar<'a, Expression<'a>> for SimpleAssignmentTarget<'a> {
#[allow(clippy::only_used_in_recursion)] #[allow(clippy::only_used_in_recursion)]
fn cover(expr: Expression<'a>, p: &mut Parser<'a>) -> Result<Self> { fn cover(expr: Expression<'a>, p: &mut ParserImpl<'a>) -> Result<Self> {
match expr { match expr {
Expression::Identifier(ident) => { Expression::Identifier(ident) => {
Ok(SimpleAssignmentTarget::AssignmentTargetIdentifier(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> { impl<'a> CoverGrammar<'a, ArrayExpression<'a>> for ArrayAssignmentTarget<'a> {
fn cover(expr: ArrayExpression<'a>, p: &mut Parser<'a>) -> Result<Self> { fn cover(expr: ArrayExpression<'a>, p: &mut ParserImpl<'a>) -> Result<Self> {
let mut elements = p.ast.new_vec(); let mut elements = p.ast.new_vec();
let mut rest = None; 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> { impl<'a> CoverGrammar<'a, Expression<'a>> for AssignmentTargetMaybeDefault<'a> {
fn cover(expr: Expression<'a>, p: &mut Parser<'a>) -> Result<Self> { fn cover(expr: Expression<'a>, p: &mut ParserImpl<'a>) -> Result<Self> {
match expr { match expr {
Expression::AssignmentExpression(assignment_expr) => { Expression::AssignmentExpression(assignment_expr) => {
let target = AssignmentTargetWithDefault::cover(assignment_expr.unbox(), p)?; 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> { impl<'a> CoverGrammar<'a, AssignmentExpression<'a>> for AssignmentTargetWithDefault<'a> {
fn cover(expr: AssignmentExpression<'a>, _p: &mut Parser<'a>) -> Result<Self> { fn cover(expr: AssignmentExpression<'a>, _p: &mut ParserImpl<'a>) -> Result<Self> {
Ok(Self { span: expr.span, binding: expr.left, init: expr.right }) Ok(Self { span: expr.span, binding: expr.left, init: expr.right })
} }
} }
impl<'a> CoverGrammar<'a, ObjectExpression<'a>> for ObjectAssignmentTarget<'a> { impl<'a> CoverGrammar<'a, ObjectExpression<'a>> for ObjectAssignmentTarget<'a> {
fn cover(expr: ObjectExpression<'a>, p: &mut Parser<'a>) -> Result<Self> { fn cover(expr: ObjectExpression<'a>, p: &mut ParserImpl<'a>) -> Result<Self> {
let mut properties = p.ast.new_vec(); let mut properties = p.ast.new_vec();
let mut rest = None; 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> { impl<'a> CoverGrammar<'a, ObjectProperty<'a>> for AssignmentTargetProperty<'a> {
fn cover(property: ObjectProperty<'a>, p: &mut Parser<'a>) -> Result<Self> { fn cover(property: ObjectProperty<'a>, p: &mut ParserImpl<'a>) -> Result<Self> {
if property.shorthand { if property.shorthand {
let binding = match property.key { let binding = match property.key {
PropertyKey::Identifier(ident) => { PropertyKey::Identifier(ident) => {

View file

@ -12,7 +12,7 @@ use crate::{
diagnostics, diagnostics,
lexer::Kind, lexer::Kind,
list::{NormalList, SeparatedList}, list::{NormalList, SeparatedList},
Parser, ParserImpl,
}; };
#[derive(Debug, Error, Diagnostic)] #[derive(Debug, Error, Diagnostic)]
@ -31,7 +31,7 @@ pub struct ObjectExpressionProperties<'a> {
} }
impl<'a> SeparatedList<'a> for 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 } Self { elements: p.ast.new_vec(), trailing_comma: None }
} }
@ -43,7 +43,7 @@ impl<'a> SeparatedList<'a> for ObjectExpressionProperties<'a> {
Kind::RCurly 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() { let element = match p.cur_kind() {
Kind::Dot3 => p.parse_spread_element().map(ObjectPropertyKind::SpreadProperty), Kind::Dot3 => p.parse_spread_element().map(ObjectPropertyKind::SpreadProperty),
_ => p.parse_property_definition().map(ObjectPropertyKind::ObjectProperty), _ => p.parse_property_definition().map(ObjectPropertyKind::ObjectProperty),
@ -65,7 +65,7 @@ pub struct ObjectPatternProperties<'a> {
} }
impl<'a> SeparatedList<'a> for 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 } Self { elements: p.ast.new_vec(), rest: None }
} }
@ -77,7 +77,7 @@ impl<'a> SeparatedList<'a> for ObjectPatternProperties<'a> {
Kind::RCurly 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 { if p.cur_kind() == Kind::Dot3 {
let rest = p.parse_rest_element()?; let rest = p.parse_rest_element()?;
if !matches!(&rest.argument.kind, BindingPatternKind::BindingIdentifier(_)) { if !matches!(&rest.argument.kind, BindingPatternKind::BindingIdentifier(_)) {
@ -101,7 +101,7 @@ pub struct ArrayExpressionList<'a> {
} }
impl<'a> SeparatedList<'a> for 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 } Self { elements: p.ast.new_vec(), trailing_comma: None }
} }
@ -113,7 +113,7 @@ impl<'a> SeparatedList<'a> for ArrayExpressionList<'a> {
Kind::RBrack 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() { let element = match p.cur_kind() {
Kind::Comma => Ok(p.parse_elision()), Kind::Comma => Ok(p.parse_elision()),
Kind::Dot3 => p.parse_spread_element().map(ArrayExpressionElement::SpreadElement), Kind::Dot3 => p.parse_spread_element().map(ArrayExpressionElement::SpreadElement),
@ -136,7 +136,7 @@ pub struct ArrayPatternList<'a> {
} }
impl<'a> SeparatedList<'a> for 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 } Self { elements: p.ast.new_vec(), rest: None }
} }
@ -148,7 +148,7 @@ impl<'a> SeparatedList<'a> for ArrayPatternList<'a> {
Kind::RBrack 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() { match p.cur_kind() {
Kind::Comma => { Kind::Comma => {
self.elements.push(None); self.elements.push(None);
@ -175,7 +175,7 @@ pub struct CallArguments<'a> {
} }
impl<'a> SeparatedList<'a> for 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 } 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 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 element = if p.at(Kind::Dot3) {
let result = p.parse_spread_element().map(Argument::SpreadElement); let result = p.parse_spread_element().map(Argument::SpreadElement);
if p.at(Kind::Comma) { if p.at(Kind::Comma) {
@ -209,7 +209,7 @@ pub struct SequenceExpressionList<'a> {
} }
impl<'a> SeparatedList<'a> for 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() } 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 // read everything as expression and map to it to either
// ParenthesizedExpression or ArrowFormalParameters later // 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()?; let element = p.parse_assignment_expression_base()?;
self.elements.push(element); self.elements.push(element);
Ok(()) Ok(())
@ -238,7 +238,7 @@ pub struct FormalParameterList<'a> {
} }
impl<'a> SeparatedList<'a> for 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 } 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 // 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(); let span = p.start_span();
p.eat_decorators()?; p.eat_decorators()?;
@ -295,7 +295,7 @@ pub struct AssertEntries<'a> {
} }
impl<'a> SeparatedList<'a> for 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() } Self { elements: p.ast.new_vec(), keys: FxHashMap::default() }
} }
@ -307,7 +307,7 @@ impl<'a> SeparatedList<'a> for AssertEntries<'a> {
Kind::RCurly 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 span = p.start_span();
let key = match p.cur_kind() { let key = match p.cur_kind() {
Kind::Str => ImportAttributeKey::StringLiteral(p.parse_literal_string()?), Kind::Str => ImportAttributeKey::StringLiteral(p.parse_literal_string()?),
@ -333,7 +333,7 @@ pub struct ExportNamedSpecifiers<'a> {
} }
impl<'a> SeparatedList<'a> for 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() } Self { elements: p.ast.new_vec() }
} }
@ -345,7 +345,7 @@ impl<'a> SeparatedList<'a> for ExportNamedSpecifiers<'a> {
Kind::RCurly 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 specifier_span = p.start_span();
let peek_kind = p.peek_kind(); let peek_kind = p.peek_kind();
@ -396,13 +396,13 @@ pub struct ClassElements<'a> {
} }
impl<'a> 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() } Self { elements: p.ast.new_vec(), private_bound_identifiers: FxHashMap::default() }
} }
fn detect_private_name_conflict( fn detect_private_name_conflict(
&self, &self,
p: &mut Parser, p: &mut ParserImpl,
private_ident: &PrivateIdentifier, private_ident: &PrivateIdentifier,
r#static: bool, r#static: bool,
kind: Option<MethodDefinitionKind>, kind: Option<MethodDefinitionKind>,
@ -430,7 +430,7 @@ impl<'a> ClassElements<'a> {
fn on_declare_private_property( fn on_declare_private_property(
&mut self, &mut self,
p: &mut Parser, p: &mut ParserImpl,
private_ident: &PrivateIdentifier, private_ident: &PrivateIdentifier,
r#static: bool, r#static: bool,
kind: Option<MethodDefinitionKind>, kind: Option<MethodDefinitionKind>,
@ -453,7 +453,7 @@ impl<'a> NormalList<'a> for ClassElements<'a> {
Kind::RCurly 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 `;` // skip empty class element `;`
while p.at(Kind::Semicolon) { while p.at(Kind::Semicolon) {
p.bump_any(); p.bump_any();
@ -482,7 +482,7 @@ pub struct SwitchCases<'a> {
} }
impl<'a> 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() } Self { elements: p.ast.new_vec() }
} }
} }
@ -496,7 +496,7 @@ impl<'a> NormalList<'a> for SwitchCases<'a> {
Kind::RCurly 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()?; let element = p.parse_switch_case()?;
self.elements.push(element); self.elements.push(element);
Ok(()) Ok(())
@ -508,7 +508,7 @@ pub struct ImportSpecifierList<'a> {
} }
impl<'a> SeparatedList<'a> for 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() } Self { import_specifiers: p.ast.new_vec() }
} }
@ -520,7 +520,7 @@ impl<'a> SeparatedList<'a> for ImportSpecifierList<'a> {
Kind::RCurly 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 import_specifier = p.parse_import_specifier()?;
let specifier = ImportDeclarationSpecifier::ImportSpecifier(import_specifier); let specifier = ImportDeclarationSpecifier::ImportSpecifier(import_specifier);
self.import_specifiers.push(specifier); self.import_specifiers.push(specifier);

View file

@ -7,9 +7,9 @@ use super::{
function::FunctionKind, function::FunctionKind,
list::{AssertEntries, ExportNamedSpecifiers, ImportSpecifierList}, 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) /// [Import Call](https://tc39.es/ecma262/#sec-import-calls)
/// `ImportCall` : import ( `AssignmentExpression` ) /// `ImportCall` : import ( `AssignmentExpression` )
pub(crate) fn parse_import_expression(&mut self, span: Span) -> Result<Expression<'a>> { pub(crate) fn parse_import_expression(&mut self, span: Span) -> Result<Expression<'a>> {

View file

@ -5,9 +5,9 @@ use oxc_span::Span;
use oxc_syntax::operator::AssignmentOperator; use oxc_syntax::operator::AssignmentOperator;
use super::list::ObjectExpressionProperties; 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) /// [Object Expression](https://tc39.es/ecma262/#sec-object-initializer)
/// `ObjectLiteral`[Yield, Await] : /// `ObjectLiteral`[Yield, Await] :
/// { } /// { }

View file

@ -8,9 +8,9 @@ use super::{
grammar::CoverGrammar, grammar::CoverGrammar,
list::SwitchCases, 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 // Section 12
// The InputElementHashbangOrRegExp goal is used at the start of a Script // The InputElementHashbangOrRegExp goal is used at the start of a Script
// or Module. // or Module.
@ -283,7 +283,7 @@ impl<'a> Parser<'a> {
return self.parse_for_loop(span, None, r#await); 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 ..) // for (a.b in ...), for ([a] in ..), for ({a} in ..)
if self.at(Kind::In) || self.at(Kind::Of) { if self.at(Kind::In) || self.at(Kind::Of) {
@ -359,7 +359,7 @@ impl<'a> Parser<'a> {
) -> Result<Statement<'a>> { ) -> Result<Statement<'a>> {
self.expect(Kind::Semicolon)?; self.expect(Kind::Semicolon)?;
let test = if !self.at(Kind::Semicolon) && !self.at(Kind::RParen) { 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 { } else {
None None
}; };
@ -367,7 +367,7 @@ impl<'a> Parser<'a> {
let update = if self.at(Kind::RParen) { let update = if self.at(Kind::RParen) {
None None
} else { } else {
Some(self.with_context(Context::In, Parser::parse_expression)?) Some(self.with_context(Context::In, ParserImpl::parse_expression)?)
}; };
self.expect(Kind::RParen)?; self.expect(Kind::RParen)?;
if r#await { if r#await {
@ -433,7 +433,7 @@ impl<'a> Parser<'a> {
let argument = if self.eat(Kind::Semicolon) || self.can_insert_semicolon() { let argument = if self.eat(Kind::Semicolon) || self.can_insert_semicolon() {
None None
} else { } else {
let expr = self.with_context(Context::In, Parser::parse_expression)?; let expr = self.with_context(Context::In, ParserImpl::parse_expression)?;
self.asi()?; self.asi()?;
Some(expr) Some(expr)
}; };

View file

@ -7,9 +7,9 @@ use oxc_ast::ast::*;
use oxc_diagnostics::Result; use oxc_diagnostics::Result;
use oxc_span::{Atom, Span}; 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<Expression<'a>> { pub(crate) fn parse_jsx_expression(&mut self) -> Result<Expression<'a>> {
if self.peek_at(Kind::RAngle) { if self.peek_at(Kind::RAngle) {
self.parse_jsx_fragment(false).map(Expression::JSXFragment) self.parse_jsx_fragment(false).map(Expression::JSXFragment)

View file

@ -116,10 +116,70 @@ pub struct ParserReturn<'a> {
pub panicked: bool, 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 /// Recursive Descent Parser for ECMAScript and TypeScript
/// ///
/// See [`Parser::parse`] for entry function. /// See [`Parser::parse`] for entry function.
pub struct Parser<'a> { 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>, lexer: Lexer<'a>,
/// SourceType: JavaScript or TypeScript, Script or Module, jsx support? /// SourceType: JavaScript or TypeScript, Script or Module, jsx support?
@ -152,9 +212,14 @@ pub struct Parser<'a> {
preserve_parens: bool, preserve_parens: bool,
} }
impl<'a> Parser<'a> { impl<'a> ParserImpl<'a> {
/// Create a new parser /// 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 { Self {
lexer: Lexer::new(allocator, source_text, source_type), lexer: Lexer::new(allocator, source_text, source_type),
source_type, source_type,
@ -163,32 +228,12 @@ impl<'a> Parser<'a> {
token: Token::default(), token: Token::default(),
prev_token_end: 0, prev_token_end: 0,
state: ParserState::new(allocator), state: ParserState::new(allocator),
ctx: Self::default_context(source_type), ctx: Self::default_context(source_type, options),
ast: AstBuilder::new(allocator), 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 /// Main entry point
/// ///
/// Returns an empty `Program` on unrecoverable error, /// 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)) Ok(self.ast.program(span, self.source_type, directives, hashbang, statements))
} }
fn default_context(source_type: SourceType) -> Context { fn default_context(source_type: SourceType, options: ParserOptions) -> Context {
let ctx = Context::default().and_ambient(source_type.is_typescript_definition()); let mut ctx = Context::default().and_ambient(source_type.is_typescript_definition());
match source_type.module_kind() { if source_type.module_kind() == ModuleKind::Module {
ModuleKind::Script => ctx,
// for [top-level-await](https://tc39.es/proposal-top-level-await/) // 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. /// Check for Flow declaration if the file cannot be parsed.

View file

@ -1,6 +1,6 @@
use oxc_diagnostics::Result; use oxc_diagnostics::Result;
use crate::{lexer::Kind, Parser}; use crate::{lexer::Kind, ParserImpl};
pub trait NormalList<'a> { pub trait NormalList<'a> {
/// Open element, e.g.. `{` `[` `(` /// Open element, e.g.. `{` `[` `(`
@ -9,10 +9,10 @@ pub trait NormalList<'a> {
/// Close element, e.g.. `}` `]` `)` /// Close element, e.g.. `}` `]` `)`
fn close(&self) -> Kind; 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 /// 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())?; p.expect(self.open())?;
while !p.at(self.close()) && !p.at(Kind::Eof) { while !p.at(self.close()) && !p.at(Kind::Eof) {
self.parse_element(p)?; self.parse_element(p)?;
@ -23,9 +23,9 @@ pub trait NormalList<'a> {
} }
pub trait SeparatedList<'a>: Sized { pub trait SeparatedList<'a>: Sized {
fn new(p: &Parser<'a>) -> Self; fn new(p: &ParserImpl<'a>) -> Self;
fn parse(p: &mut Parser<'a>) -> Result<Self> { fn parse(p: &mut ParserImpl<'a>) -> Result<Self> {
let mut list = Self::new(p); let mut list = Self::new(p);
list.parse_list(p)?; list.parse_list(p)?;
Ok(list) Ok(list)
@ -42,10 +42,10 @@ pub trait SeparatedList<'a>: Sized {
Kind::Comma 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 /// 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())?; p.expect(self.open())?;
let mut first = true; let mut first = true;

View file

@ -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 /// Check if the parser is at a start of a declaration
fn at_start_of_ts_declaration_worker(&mut self) -> bool { fn at_start_of_ts_declaration_worker(&mut self) -> bool {
loop { loop {
@ -80,11 +80,12 @@ mod test_is_declaration {
use oxc_span::SourceType; use oxc_span::SourceType;
use super::*; use super::*;
use crate::ParserOptions;
fn run_check(source: &str, expected: bool) { fn run_check(source: &str, expected: bool) {
let alloc = Allocator::default(); let alloc = Allocator::default();
let source_type = SourceType::default().with_typescript(true); 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. // Get the parser to the first token.
parser.bump_any(); parser.bump_any();
assert_eq!(expected, parser.at_start_of_ts_declaration()); assert_eq!(expected, parser.at_start_of_ts_declaration());

View file

@ -5,7 +5,7 @@ use oxc_diagnostics::Result;
use crate::{ use crate::{
lexer::Kind, lexer::Kind,
list::{NormalList, SeparatedList}, list::{NormalList, SeparatedList},
Parser, ParserImpl,
}; };
pub struct TSEnumMemberList<'a> { pub struct TSEnumMemberList<'a> {
@ -13,7 +13,7 @@ pub struct TSEnumMemberList<'a> {
} }
impl<'a> SeparatedList<'a> for 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() } Self { members: p.ast.new_vec() }
} }
@ -25,7 +25,7 @@ impl<'a> SeparatedList<'a> for TSEnumMemberList<'a> {
Kind::RCurly 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()?; let element = p.parse_ts_enum_member()?;
self.members.push(element); self.members.push(element);
Ok(()) Ok(())
@ -37,7 +37,7 @@ pub struct TSTupleElementList<'a> {
} }
impl<'a> SeparatedList<'a> for 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() } Self { elements: p.ast.new_vec() }
} }
@ -49,7 +49,7 @@ impl<'a> SeparatedList<'a> for TSTupleElementList<'a> {
Kind::RBrack 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(); let span = p.start_span();
if p.is_at_named_tuple_element() { if p.is_at_named_tuple_element() {
let _is_rest = p.eat(Kind::Dot3); let _is_rest = p.eat(Kind::Dot3);
@ -91,7 +91,7 @@ pub struct TSTypeParameterList<'a> {
} }
impl<'a> SeparatedList<'a> for 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() } Self { params: p.ast.new_vec() }
} }
@ -103,7 +103,7 @@ impl<'a> SeparatedList<'a> for TSTypeParameterList<'a> {
Kind::RAngle 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()?; let param = p.parse_ts_type_parameter()?;
self.params.push(param); self.params.push(param);
Ok(()) Ok(())
@ -115,7 +115,7 @@ pub struct TSInterfaceOrObjectBodyList<'a> {
} }
impl<'a> 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() } Self { body: p.ast.new_vec() }
} }
} }
@ -129,7 +129,7 @@ impl<'a> NormalList<'a> for TSInterfaceOrObjectBodyList<'a> {
Kind::RCurly 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()?; let property = p.parse_ts_type_signature()?;
self.body.push(property); self.body.push(property);
Ok(()) Ok(())
@ -141,7 +141,7 @@ pub struct TSTypeArgumentList<'a> {
} }
impl<'a> SeparatedList<'a> for 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() } Self { params: p.ast.new_vec() }
} }
@ -153,7 +153,7 @@ impl<'a> SeparatedList<'a> for TSTypeArgumentList<'a> {
Kind::RAngle 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()?; let ty = p.parse_ts_type()?;
self.params.push(ty); self.params.push(ty);
Ok(()) Ok(())

View file

@ -14,10 +14,10 @@ use crate::{
}, },
lexer::Kind, lexer::Kind,
list::{NormalList, SeparatedList}, list::{NormalList, SeparatedList},
Parser, StatementContext, ParserImpl, StatementContext,
}; };
impl<'a> Parser<'a> { impl<'a> ParserImpl<'a> {
/** ------------------- Enum ------------------ */ /** ------------------- Enum ------------------ */
pub(crate) fn is_at_enum_declaration(&mut self) -> bool { pub(crate) fn is_at_enum_declaration(&mut self) -> bool {

View file

@ -12,7 +12,7 @@ use crate::{
js::list::{ArrayPatternList, ObjectPatternProperties}, js::list::{ArrayPatternList, ObjectPatternProperties},
lexer::Kind, lexer::Kind,
list::{NormalList, SeparatedList}, list::{NormalList, SeparatedList},
Context, Parser, Context, ParserImpl,
}; };
bitflags! { bitflags! {
@ -105,7 +105,7 @@ impl ModifierFlags {
} }
} }
impl<'a> Parser<'a> { impl<'a> ParserImpl<'a> {
pub(crate) fn parse_ts_type(&mut self) -> Result<TSType<'a>> { pub(crate) fn parse_ts_type(&mut self) -> Result<TSType<'a>> {
if self.is_at_constructor_type() { if self.is_at_constructor_type() {
return self.parse_ts_constructor_type(); return self.parse_ts_constructor_type();
@ -323,8 +323,8 @@ impl<'a> Parser<'a> {
)); ));
} }
let mut left = let mut left = self
self.without_context(Context::DisallowConditionalTypes, Parser::parse_ts_basic_type)?; .without_context(Context::DisallowConditionalTypes, ParserImpl::parse_ts_basic_type)?;
while !self.cur_token().is_on_new_line && self.eat(Kind::LBrack) { while !self.cur_token().is_on_new_line && self.eat(Kind::LBrack) {
if self.eat(Kind::RBrack) { if self.eat(Kind::RBrack) {
@ -828,7 +828,7 @@ impl<'a> Parser<'a> {
let parameter_span = self.start_span(); let parameter_span = self.start_span();
let name = self.parse_binding_identifier()?; 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( let type_parameter = self.ast.ts_type_parameter(
self.end_span(parameter_span), self.end_span(parameter_span),