diff --git a/crates/oxc_parser/src/cursor.rs b/crates/oxc_parser/src/cursor.rs index bbe8c46c744d..aa05b880fc1f 100644 --- a/crates/oxc_parser/src/cursor.rs +++ b/crates/oxc_parser/src/cursor.rs @@ -334,4 +334,30 @@ impl<'a> ParserImpl<'a> { let decorators = std::mem::take(&mut self.state.decorators); self.ast.new_vec_from_iter(decorators) } + + pub(crate) fn parse_normal_list( + &mut self, + open: Kind, + close: Kind, + f: F, + ) -> Result> + where + F: Fn(&mut Self) -> Result>, + { + let mut list = self.ast.new_vec(); + self.expect(open)?; + loop { + let kind = self.cur_kind(); + if kind == close || kind == Kind::Eof { + break; + } + if let Some(e) = f(self)? { + list.push(e); + } else { + break; + } + } + self.expect(close)?; + Ok(list) + } } diff --git a/crates/oxc_parser/src/js/class.rs b/crates/oxc_parser/src/js/class.rs index 788a8d7daaf9..d37de034b643 100644 --- a/crates/oxc_parser/src/js/class.rs +++ b/crates/oxc_parser/src/js/class.rs @@ -3,11 +3,9 @@ use oxc_ast::{ast::*, syntax_directed_operations::PropName}; use oxc_diagnostics::Result; use oxc_span::{GetSpan, Span}; -use super::list::ClassElements; use crate::{ diagnostics, lexer::Kind, - list::NormalList, modifiers::{ModifierFlags, ModifierKind, Modifiers}, Context, ParserImpl, StatementContext, }; @@ -170,13 +168,20 @@ impl<'a> ParserImpl<'a> { fn parse_class_body(&mut self) -> Result>> { let span = self.start_span(); - let mut class_elements = ClassElements::new(self); - class_elements.parse(self)?; - let body = class_elements.elements; - Ok(self.ast.class_body(self.end_span(span), body)) + let class_elements = + self.parse_normal_list(Kind::LCurly, Kind::RCurly, Self::parse_class_element)?; + Ok(self.ast.class_body(self.end_span(span), class_elements)) } - pub(crate) fn parse_class_element(&mut self) -> Result> { + pub(crate) fn parse_class_element(&mut self) -> Result>> { + // skip empty class element `;` + while self.at(Kind::Semicolon) { + self.bump_any(); + } + if self.at(Kind::RCurly) { + return Ok(None); + } + let span = self.start_span(); let modifiers = self.parse_modifiers(true, false, true); @@ -199,7 +204,7 @@ impl<'a> ParserImpl<'a> { // static { block } if self.peek_at(Kind::LCurly) { self.bump(Kind::Static); - return self.parse_class_static_block(span); + return self.parse_class_static_block(span).map(Some); } // static ... @@ -225,7 +230,7 @@ impl<'a> ParserImpl<'a> { if self.is_at_ts_index_signature_member() { if let TSSignature::TSIndexSignature(sig) = self.parse_ts_index_signature_member()? { - return Ok(ClassElement::TSIndexSignature(sig)); + return Ok(Some(ClassElement::TSIndexSignature(sig))); } } @@ -277,13 +282,10 @@ impl<'a> ParserImpl<'a> { if accessor { self.parse_ts_type_annotation()?; - - return self.parse_class_accessor_property(span, key, computed, r#static, r#abstract); - } - - // LAngle for start of type parameters `foo` - // ^ - if self.at(Kind::LParen) || self.at(Kind::LAngle) || r#async || generator { + self.parse_class_accessor_property(span, key, computed, r#static, r#abstract).map(Some) + } else if self.at(Kind::LParen) || self.at(Kind::LAngle) || r#async || generator { + // LAngle for start of type parameters `foo` + // ^ let definition = self.parse_class_method_definition( span, kind, @@ -313,7 +315,7 @@ impl<'a> ParserImpl<'a> { } } } - Ok(definition) + Ok(Some(definition)) } else { // getter and setter has no ts type annotation if !kind.is_method() { @@ -340,7 +342,7 @@ impl<'a> ParserImpl<'a> { self.error(diagnostics::static_prototype(span)); } } - Ok(definition) + Ok(Some(definition)) } } diff --git a/crates/oxc_parser/src/js/list.rs b/crates/oxc_parser/src/js/list.rs index 72bb795c2fe0..2fa6a719a68f 100644 --- a/crates/oxc_parser/src/js/list.rs +++ b/crates/oxc_parser/src/js/list.rs @@ -4,13 +4,7 @@ use oxc_diagnostics::Result; use oxc_span::{Atom, GetSpan, Span}; use rustc_hash::FxHashMap; -use crate::{ - diagnostics, - lexer::Kind, - list::{NormalList, SeparatedList}, - modifiers::ModifierFlags, - ParserImpl, -}; +use crate::{diagnostics, lexer::Kind, list::SeparatedList, modifiers::ModifierFlags, ParserImpl}; /// ObjectExpression.properties pub struct ObjectExpressionProperties<'a> { @@ -402,66 +396,6 @@ impl<'a> SeparatedList<'a> for ExportNamedSpecifiers<'a> { } } -pub struct ClassElements<'a> { - pub elements: Vec<'a, ClassElement<'a>>, -} - -impl<'a> ClassElements<'a> { - pub(crate) fn new(p: &ParserImpl<'a>) -> Self { - Self { elements: p.ast.new_vec() } - } -} - -impl<'a> NormalList<'a> for ClassElements<'a> { - fn open(&self) -> Kind { - Kind::LCurly - } - - fn close(&self) -> Kind { - Kind::RCurly - } - - fn parse_element(&mut self, p: &mut ParserImpl<'a>) -> Result<()> { - // skip empty class element `;` - while p.at(Kind::Semicolon) { - p.bump_any(); - } - if p.at(self.close()) { - return Ok(()); - } - let element = p.parse_class_element()?; - - self.elements.push(element); - Ok(()) - } -} - -pub struct SwitchCases<'a> { - pub elements: Vec<'a, SwitchCase<'a>>, -} - -impl<'a> SwitchCases<'a> { - pub(crate) fn new(p: &ParserImpl<'a>) -> Self { - Self { elements: p.ast.new_vec() } - } -} - -impl<'a> NormalList<'a> for SwitchCases<'a> { - fn open(&self) -> Kind { - Kind::LCurly - } - - fn close(&self) -> Kind { - Kind::RCurly - } - - fn parse_element(&mut self, p: &mut ParserImpl<'a>) -> Result<()> { - let element = p.parse_switch_case()?; - self.elements.push(element); - Ok(()) - } -} - pub struct ImportSpecifierList<'a> { pub import_specifiers: Vec<'a, ImportDeclarationSpecifier<'a>>, } diff --git a/crates/oxc_parser/src/js/statement.rs b/crates/oxc_parser/src/js/statement.rs index 2e6a73b0257b..c5222bb4c564 100644 --- a/crates/oxc_parser/src/js/statement.rs +++ b/crates/oxc_parser/src/js/statement.rs @@ -3,12 +3,9 @@ use oxc_ast::ast::*; use oxc_diagnostics::Result; use oxc_span::{Atom, GetSpan, Span}; -use super::{ - grammar::CoverGrammar, list::SwitchCases, VariableDeclarationContext, VariableDeclarationParent, -}; +use super::{grammar::CoverGrammar, VariableDeclarationContext, VariableDeclarationParent}; use crate::{ - diagnostics, lexer::Kind, list::NormalList, modifiers::Modifiers, Context, ParserImpl, - StatementContext, + diagnostics, lexer::Kind, modifiers::Modifiers, Context, ParserImpl, StatementContext, }; impl<'a> ParserImpl<'a> { @@ -441,15 +438,11 @@ impl<'a> ParserImpl<'a> { let span = self.start_span(); self.bump_any(); // advance `switch` let discriminant = self.parse_paren_expression()?; - let cases = { - let mut switch_cases = SwitchCases::new(self); - switch_cases.parse(self)?; - switch_cases.elements - }; + let cases = self.parse_normal_list(Kind::LCurly, Kind::RCurly, Self::parse_switch_case)?; Ok(self.ast.switch_statement(self.end_span(span), discriminant, cases)) } - pub(crate) fn parse_switch_case(&mut self) -> Result> { + pub(crate) fn parse_switch_case(&mut self) -> Result>> { let span = self.start_span(); let test = match self.cur_kind() { Kind::Default => { @@ -469,7 +462,7 @@ impl<'a> ParserImpl<'a> { let stmt = self.parse_statement_list_item(StatementContext::StatementList)?; consequent.push(stmt); } - Ok(self.ast.switch_case(self.end_span(span), test, consequent)) + Ok(Some(self.ast.switch_case(self.end_span(span), test, consequent))) } /// Section 14.14 Throw Statement diff --git a/crates/oxc_parser/src/list.rs b/crates/oxc_parser/src/list.rs index 0b50ac1dcc69..5d31b64d7f63 100644 --- a/crates/oxc_parser/src/list.rs +++ b/crates/oxc_parser/src/list.rs @@ -2,26 +2,6 @@ use oxc_diagnostics::Result; use crate::{lexer::Kind, ParserImpl}; -pub trait NormalList<'a> { - /// Open element, e.g.. `{` `[` `(` - fn open(&self) -> Kind; - - /// Close element, e.g.. `}` `]` `)` - fn close(&self) -> Kind; - - fn parse_element(&mut self, p: &mut ParserImpl<'a>) -> Result<()>; - - /// Main entry point, parse the list - 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)?; - } - p.expect(self.close())?; - Ok(()) - } -} - pub trait SeparatedList<'a>: Sized { fn new(p: &ParserImpl<'a>) -> Self; diff --git a/crates/oxc_parser/src/ts/list.rs b/crates/oxc_parser/src/ts/list.rs index 73f041797a6d..99db19a3ea91 100644 --- a/crates/oxc_parser/src/ts/list.rs +++ b/crates/oxc_parser/src/ts/list.rs @@ -2,11 +2,7 @@ use oxc_allocator::Vec; use oxc_ast::ast::*; use oxc_diagnostics::Result; -use crate::{ - lexer::Kind, - list::{NormalList, SeparatedList}, - ParserImpl, -}; +use crate::{lexer::Kind, list::SeparatedList, ParserImpl}; pub struct TSEnumMemberList<'a> { pub members: Vec<'a, TSEnumMember<'a>>, @@ -80,32 +76,6 @@ impl<'a> SeparatedList<'a> for TSTypeParameterList<'a> { } } -pub struct TSInterfaceOrObjectBodyList<'a> { - pub body: Vec<'a, TSSignature<'a>>, -} - -impl<'a> TSInterfaceOrObjectBodyList<'a> { - pub(crate) fn new(p: &ParserImpl<'a>) -> Self { - Self { body: p.ast.new_vec() } - } -} - -impl<'a> NormalList<'a> for TSInterfaceOrObjectBodyList<'a> { - fn open(&self) -> Kind { - Kind::LCurly - } - - fn close(&self) -> Kind { - Kind::RCurly - } - - fn parse_element(&mut self, p: &mut ParserImpl<'a>) -> Result<()> { - let property = p.parse_ts_type_signature()?; - self.body.push(property); - Ok(()) - } -} - pub struct TSTypeArgumentList<'a> { pub params: Vec<'a, TSType<'a>>, in_expression: bool, diff --git a/crates/oxc_parser/src/ts/statement.rs b/crates/oxc_parser/src/ts/statement.rs index aa98b72575ad..c744879a67c7 100644 --- a/crates/oxc_parser/src/ts/statement.rs +++ b/crates/oxc_parser/src/ts/statement.rs @@ -3,12 +3,12 @@ use oxc_ast::ast::*; use oxc_diagnostics::Result; use oxc_span::Span; -use super::list::{TSEnumMemberList, TSInterfaceOrObjectBodyList}; +use super::list::TSEnumMemberList; use crate::{ diagnostics, js::{FunctionKind, VariableDeclarationContext, VariableDeclarationParent}, lexer::Kind, - list::{NormalList, SeparatedList}, + list::SeparatedList, modifiers::{ModifierFlags, ModifierKind, Modifiers}, ParserImpl, }; @@ -161,9 +161,9 @@ impl<'a> ParserImpl<'a> { fn parse_ts_interface_body(&mut self) -> Result>> { let span = self.start_span(); - let mut body_list = TSInterfaceOrObjectBodyList::new(self); - body_list.parse(self)?; - Ok(self.ast.ts_interface_body(self.end_span(span), body_list.body)) + let body_list = + self.parse_normal_list(Kind::LCurly, Kind::RCurly, Self::parse_ts_type_signature)?; + Ok(self.ast.ts_interface_body(self.end_span(span), body_list)) } pub(crate) fn is_at_interface_declaration(&mut self) -> bool { @@ -174,9 +174,9 @@ impl<'a> ParserImpl<'a> { } } - pub(crate) fn parse_ts_type_signature(&mut self) -> Result> { + pub(crate) fn parse_ts_type_signature(&mut self) -> Result>> { if self.is_at_ts_index_signature_member() { - return self.parse_ts_index_signature_member(); + return self.parse_ts_index_signature_member().map(Some); } match self.cur_kind() { @@ -192,6 +192,7 @@ impl<'a> ParserImpl<'a> { } _ => self.parse_ts_property_or_method_signature_member(), } + .map(Some) } /// Must be at `[ident:` or ` [ident:` diff --git a/crates/oxc_parser/src/ts/types.rs b/crates/oxc_parser/src/ts/types.rs index 9e785372bbd0..f9137468283d 100644 --- a/crates/oxc_parser/src/ts/types.rs +++ b/crates/oxc_parser/src/ts/types.rs @@ -4,13 +4,11 @@ use oxc_diagnostics::Result; use oxc_span::GetSpan; use oxc_syntax::operator::UnaryOperator; -use super::list::{ - TSInterfaceOrObjectBodyList, TSTupleElementList, TSTypeArgumentList, TSTypeParameterList, -}; +use super::list::{TSTupleElementList, TSTypeArgumentList, TSTypeParameterList}; use crate::{ diagnostics, lexer::Kind, - list::{NormalList, SeparatedList}, + list::SeparatedList, modifiers::{Modifier, ModifierFlags, ModifierKind, Modifiers}, ts::list::TSImportAttributeList, Context, ParserImpl, @@ -618,9 +616,9 @@ impl<'a> ParserImpl<'a> { fn parse_type_literal(&mut self) -> Result> { let span = self.start_span(); - let mut member_list = TSInterfaceOrObjectBodyList::new(self); - member_list.parse(self)?; - Ok(self.ast.ts_type_literal(self.end_span(span), member_list.body)) + let member_list = + self.parse_normal_list(Kind::LCurly, Kind::RCurly, Self::parse_ts_type_signature)?; + Ok(self.ast.ts_type_literal(self.end_span(span), member_list)) } fn parse_type_query(&mut self) -> Result> {