Skip to content

Commit

Permalink
refactor(parser): use function instead of trait to parse delimited lists
Browse files Browse the repository at this point in the history
closes #3887
  • Loading branch information
Boshen committed Jul 2, 2024
1 parent d995f94 commit 0e2d1f1
Show file tree
Hide file tree
Showing 11 changed files with 243 additions and 420 deletions.
35 changes: 34 additions & 1 deletion crates/oxc_parser/src/cursor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -344,8 +344,8 @@ impl<'a> ParserImpl<'a> {
where
F: Fn(&mut Self) -> Result<Option<T>>,
{
let mut list = self.ast.new_vec();
self.expect(open)?;
let mut list = self.ast.new_vec();
loop {
let kind = self.cur_kind();
if kind == close || kind == Kind::Eof {
Expand All @@ -360,4 +360,37 @@ impl<'a> ParserImpl<'a> {
self.expect(close)?;
Ok(list)
}

pub(crate) fn parse_delimited_list<F, T>(
&mut self,
close: Kind,
separator: Kind,
trailing_separator: bool,
f: F,
) -> Result<oxc_allocator::Vec<'a, T>>
where
F: Fn(&mut Self) -> Result<T>,
{
let mut list = self.ast.new_vec();
let mut first = true;
loop {
let kind = self.cur_kind();
if kind == close || kind == Kind::Eof {
break;
}
if first {
first = false;
} else {
if !trailing_separator && self.at(separator) && self.peek_at(close) {
break;
}
self.expect(separator)?;
if self.at(close) {
break;
}
}
list.push(f(self)?);
}
Ok(list)
}
}
48 changes: 41 additions & 7 deletions crates/oxc_parser/src/js/expression.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ use oxc_syntax::{

use super::{
grammar::CoverGrammar,
list::{ArrayExpressionList, CallArguments, SequenceExpressionList},
list::ArrayExpressionList,
operator::{
kind_to_precedence, map_assignment_operator, map_binary_operator, map_logical_operator,
map_unary_operator, map_update_operator,
Expand Down Expand Up @@ -203,9 +203,17 @@ impl<'a> ParserImpl<'a> {
}

fn parse_parenthesized_expression(&mut self, span: Span) -> Result<Expression<'a>> {
let list = self.context(Context::In, Context::Decorator, SequenceExpressionList::parse)?;
self.expect(Kind::LParen)?;
let mut expressions = self.context(Context::In, Context::Decorator, |p| {
p.parse_delimited_list(
Kind::RParen,
Kind::Comma,
/* trailing_separator */ false,
Self::parse_assignment_expression_or_higher,
)
})?;
self.expect(Kind::RParen)?;

let mut expressions = list.elements;
let paren_span = self.end_span(span);

if expressions.is_empty() {
Expand Down Expand Up @@ -677,10 +685,19 @@ impl<'a> ParserImpl<'a> {
}

// parse `new ident` without arguments
let arguments = if self.at(Kind::LParen) {
let arguments = if self.eat(Kind::LParen) {
// ArgumentList[Yield, Await] :
// AssignmentExpression[+In, ?Yield, ?Await]
self.context(Context::In, Context::empty(), CallArguments::parse)?.elements
let call_arguments = self.context(Context::In, Context::empty(), |p| {
p.parse_delimited_list(
Kind::RParen,
Kind::Comma,
/* trailing_separator */ true,
Self::parse_call_argument,
)
})?;
self.expect(Kind::RParen)?;
call_arguments
} else {
self.ast.new_vec()
};
Expand Down Expand Up @@ -749,16 +766,33 @@ impl<'a> ParserImpl<'a> {
) -> Result<Expression<'a>> {
// ArgumentList[Yield, Await] :
// AssignmentExpression[+In, ?Yield, ?Await]
let call_arguments = self.context(Context::In, Context::Decorator, CallArguments::parse)?;
self.expect(Kind::LParen)?;
let call_arguments = self.context(Context::In, Context::Decorator, |p| {
p.parse_delimited_list(
Kind::RParen,
Kind::Comma,
/* trailing_separator */ true,
Self::parse_call_argument,
)
})?;
self.expect(Kind::RParen)?;
Ok(self.ast.call_expression(
self.end_span(lhs_span),
lhs,
call_arguments.elements,
call_arguments,
optional,
type_parameters,
))
}

fn parse_call_argument(&mut self) -> Result<Argument<'a>> {
if self.at(Kind::Dot3) {
self.parse_spread_element().map(Argument::SpreadElement)
} else {
self.parse_assignment_expression_or_higher().map(Argument::from)
}
}

/// Section 13.4 Update Expression
fn parse_update_expression(&mut self, lhs_span: Span) -> Result<Expression<'a>> {
let kind = self.cur_kind();
Expand Down
196 changes: 0 additions & 196 deletions crates/oxc_parser/src/js/list.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,42 +6,6 @@ use rustc_hash::FxHashMap;

use crate::{diagnostics, lexer::Kind, list::SeparatedList, modifiers::ModifierFlags, ParserImpl};

/// ObjectExpression.properties
pub struct ObjectExpressionProperties<'a> {
pub elements: Vec<'a, ObjectPropertyKind<'a>>,
pub trailing_comma: Option<Span>,
}

impl<'a> SeparatedList<'a> for ObjectExpressionProperties<'a> {
fn new(p: &ParserImpl<'a>) -> Self {
Self { elements: p.ast.new_vec(), trailing_comma: None }
}

fn open(&self) -> Kind {
Kind::LCurly
}

fn close(&self) -> Kind {
Kind::RCurly
}

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),
}?;

if p.at(Kind::Comma) && p.peek_at(self.close()) {
let span = p.start_span();
p.bump_any();
self.trailing_comma = Some(p.end_span(span));
}

self.elements.push(element);
Ok(())
}
}

/// ObjectPattern.properties
pub struct ObjectPatternProperties<'a> {
pub elements: Vec<'a, BindingProperty<'a>>,
Expand Down Expand Up @@ -154,87 +118,6 @@ impl<'a> SeparatedList<'a> for ArrayPatternList<'a> {
}
}

/// Section 13.3 Arguments for `CallExpression`, `NewExpression`
pub struct CallArguments<'a> {
pub elements: Vec<'a, Argument<'a>>,
pub rest_element_with_trilling_comma: Option<Span>,
}

impl<'a> SeparatedList<'a> for CallArguments<'a> {
fn new(p: &ParserImpl<'a>) -> Self {
Self { elements: p.ast.new_vec(), rest_element_with_trilling_comma: None }
}

fn open(&self) -> Kind {
Kind::LParen
}

fn close(&self) -> Kind {
Kind::RParen
}

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) {
if let Ok(Argument::SpreadElement(argument)) = &result {
self.rest_element_with_trilling_comma = Some(argument.span);
}
}
result
} else {
p.parse_assignment_expression_or_higher().map(Argument::from)
};
self.elements.push(element?);
Ok(())
}
}

pub struct SequenceExpressionList<'a> {
pub elements: Vec<'a, Expression<'a>>,
}

impl<'a> SeparatedList<'a> for SequenceExpressionList<'a> {
fn new(p: &ParserImpl<'a>) -> Self {
Self { elements: p.ast.new_vec() }
}

fn open(&self) -> Kind {
Kind::LParen
}

fn close(&self) -> Kind {
Kind::RParen
}

// read everything as expression and map to it to either
// ParenthesizedExpression or ArrowFormalParameters later
fn parse_element(&mut self, p: &mut ParserImpl<'a>) -> Result<()> {
let element = p.parse_assignment_expression_or_higher();
self.elements.push(element?);
Ok(())
}

fn parse_list(&mut self, p: &mut ParserImpl<'a>) -> Result<()> {
p.expect(self.open())?;

let mut first = true;

while !p.at(self.close()) && !p.at(Kind::Eof) {
if first {
first = false;
} else {
p.expect(self.separator())?;
}

self.parse_element(p)?;
}

p.expect(self.close())?;
Ok(())
}
}

/// Function Parameters
pub struct FormalParameterList<'a> {
pub elements: Vec<'a, FormalParameter<'a>>,
Expand Down Expand Up @@ -341,82 +224,3 @@ impl<'a> SeparatedList<'a> for AssertEntries<'a> {
Ok(())
}
}

pub struct ExportNamedSpecifiers<'a> {
pub elements: Vec<'a, ExportSpecifier<'a>>,
}

impl<'a> SeparatedList<'a> for ExportNamedSpecifiers<'a> {
fn new(p: &ParserImpl<'a>) -> Self {
Self { elements: p.ast.new_vec() }
}

fn open(&self) -> Kind {
Kind::LCurly
}

fn close(&self) -> Kind {
Kind::RCurly
}

fn parse_element(&mut self, p: &mut ParserImpl<'a>) -> Result<()> {
let specifier_span = p.start_span();
let peek_kind = p.peek_kind();

// export { type} // name: `type`
// export { type type } // name: `type` type-export: `true`
// export { type as } // name: `as` type-export: `true`
// export { type as as } // name: `type` type-export: `false` (aliased to `as`)
// export { type as as as } // name: `as` type-export: `true`, aliased to `as`
let mut export_kind = ImportOrExportKind::Value;
if p.ts_enabled() && p.at(Kind::Type) {
if p.peek_at(Kind::As) {
if p.nth_at(2, Kind::As) {
if p.nth_at(3, Kind::Str) || p.nth_kind(3).is_identifier_name() {
export_kind = ImportOrExportKind::Type;
}
} else if !(p.nth_at(2, Kind::Str) || p.nth_kind(2).is_identifier_name()) {
export_kind = ImportOrExportKind::Type;
}
} else if (matches!(peek_kind, Kind::Str) || peek_kind.is_identifier_name()) {
export_kind = ImportOrExportKind::Type;
}
}

if export_kind == ImportOrExportKind::Type {
p.bump_any();
}

let local = p.parse_module_export_name()?;
let exported = if p.eat(Kind::As) { p.parse_module_export_name()? } else { local.clone() };
let element =
ExportSpecifier { span: p.end_span(specifier_span), local, exported, export_kind };
self.elements.push(element);
Ok(())
}
}

pub struct ImportSpecifierList<'a> {
pub import_specifiers: Vec<'a, ImportDeclarationSpecifier<'a>>,
}

impl<'a> SeparatedList<'a> for ImportSpecifierList<'a> {
fn new(p: &ParserImpl<'a>) -> Self {
Self { import_specifiers: p.ast.new_vec() }
}

fn open(&self) -> Kind {
Kind::LCurly
}

fn close(&self) -> Kind {
Kind::RCurly
}

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);
Ok(())
}
}
Loading

0 comments on commit 0e2d1f1

Please sign in to comment.