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 e2c9015 commit aa30245
Show file tree
Hide file tree
Showing 11 changed files with 301 additions and 507 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)
}
}
74 changes: 64 additions & 10 deletions crates/oxc_parser/src/js/expression.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ use oxc_syntax::{

use super::{
grammar::CoverGrammar,
list::{ArrayExpressionList, CallArguments, SequenceExpressionList},
operator::{
kind_to_precedence, map_assignment_operator, map_binary_operator, map_logical_operator,
map_unary_operator, map_update_operator,
Expand All @@ -21,7 +20,6 @@ use super::{
use crate::{
diagnostics,
lexer::{parse_big_int, parse_float, parse_int, Kind},
list::SeparatedList,
Context, ParserImpl,
};

Expand Down Expand Up @@ -203,9 +201,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 @@ -360,8 +366,30 @@ impl<'a> ParserImpl<'a> {
/// [ `ElementList`[?Yield, ?Await] , Elisionopt ]
pub(crate) fn parse_array_expression(&mut self) -> Result<Expression<'a>> {
let span = self.start_span();
let list = self.context(Context::In, Context::empty(), ArrayExpressionList::parse)?;
Ok(self.ast.array_expression(self.end_span(span), list.elements, list.trailing_comma))
self.expect(Kind::LBrack)?;
let elements = self.context(Context::In, Context::empty(), |p| {
p.parse_delimited_list(
Kind::RBrack,
Kind::Comma,
/* trailing_separator */ false,
Self::parse_array_expression_element,
)
})?;
let trailing_comma = self.at(Kind::Comma).then(|| {
let span = self.start_span();
self.bump_any();
self.end_span(span)
});
self.expect(Kind::RBrack)?;
Ok(self.ast.array_expression(self.end_span(span), elements, trailing_comma))
}

fn parse_array_expression_element(&mut self) -> Result<ArrayExpressionElement<'a>> {
match self.cur_kind() {
Kind::Comma => Ok(self.parse_elision()),
Kind::Dot3 => self.parse_spread_element().map(ArrayExpressionElement::SpreadElement),
_ => self.parse_assignment_expression_or_higher().map(ArrayExpressionElement::from),
}
}

/// Elision :
Expand Down Expand Up @@ -677,10 +705,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 +786,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
Loading

0 comments on commit aa30245

Please sign in to comment.