Skip to content

Commit

Permalink
refactor(parser): use function instead of trait to parse list with re…
Browse files Browse the repository at this point in the history
…st element

closes #3887
  • Loading branch information
Boshen committed Jul 2, 2024
1 parent 6254a41 commit 3945397
Show file tree
Hide file tree
Showing 12 changed files with 337 additions and 338 deletions.
48 changes: 44 additions & 4 deletions crates/oxc_parser/src/cursor.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
//! Code related to navigating `Token`s from the lexer

use oxc_allocator::Vec;
use oxc_ast::ast::{Decorator, RegExpFlags};
use oxc_diagnostics::Result;
use oxc_span::Span;
use oxc_span::{GetSpan, Span};

use crate::{
diagnostics,
Expand Down Expand Up @@ -330,7 +331,7 @@ impl<'a> ParserImpl<'a> {
result
}

pub(crate) fn consume_decorators(&mut self) -> oxc_allocator::Vec<'a, Decorator<'a>> {
pub(crate) fn consume_decorators(&mut self) -> Vec<'a, Decorator<'a>> {
let decorators = std::mem::take(&mut self.state.decorators);
self.ast.new_vec_from_iter(decorators)
}
Expand All @@ -340,7 +341,7 @@ impl<'a> ParserImpl<'a> {
open: Kind,
close: Kind,
f: F,
) -> Result<oxc_allocator::Vec<'a, T>>
) -> Result<Vec<'a, T>>
where
F: Fn(&mut Self) -> Result<Option<T>>,
{
Expand All @@ -367,7 +368,7 @@ impl<'a> ParserImpl<'a> {
separator: Kind,
trailing_separator: bool,
f: F,
) -> Result<oxc_allocator::Vec<'a, T>>
) -> Result<Vec<'a, T>>
where
F: Fn(&mut Self) -> Result<T>,
{
Expand All @@ -393,4 +394,43 @@ impl<'a> ParserImpl<'a> {
}
Ok(list)
}

pub(crate) fn parse_delimited_list_with_rest<E, R, A, B>(
&mut self,
close: Kind,
parse_element: E,
parse_rest: R,
) -> Result<(Vec<'a, A>, Option<B>)>
where
E: Fn(&mut Self) -> Result<A>,
R: Fn(&mut Self) -> Result<B>,
B: GetSpan,
{
let mut list = self.ast.new_vec();
let mut rest = None;
let mut first = true;
loop {
let kind = self.cur_kind();
if kind == close || kind == Kind::Eof {
break;
}
if first {
first = false;
} else {
self.expect(Kind::Comma)?;
if self.at(close) {
break;
}
}

if self.at(Kind::Dot3) {
if let Some(r) = rest.replace(parse_rest(self)?) {
self.error(diagnostics::binding_rest_element_last(r.span()));
}
} else {
list.push(parse_element(self)?);
}
}
Ok((list, rest))
}
}
71 changes: 50 additions & 21 deletions crates/oxc_parser/src/js/binding.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
use oxc_allocator::Box;
use oxc_ast::ast::*;
use oxc_diagnostics::Result;
use oxc_span::Span;
use oxc_span::{GetSpan, Span};

use super::list::{ArrayPatternList, ObjectPatternProperties};
use crate::{diagnostics, lexer::Kind, list::SeparatedList, Context, ParserImpl};
use crate::{diagnostics, lexer::Kind, Context, ParserImpl};

impl<'a> ParserImpl<'a> {
/// `BindingElement`
Expand Down Expand Up @@ -46,19 +44,60 @@ impl<'a> ParserImpl<'a> {
/// Section 14.3.3 Object Binding Pattern
fn parse_object_binding_pattern(&mut self) -> Result<BindingPatternKind<'a>> {
let span = self.start_span();
let props = ObjectPatternProperties::parse(self)?;
Ok(self.ast.object_pattern(self.end_span(span), props.elements, props.rest))
self.expect(Kind::LCurly)?;
let (list, rest) = self.parse_delimited_list_with_rest(
Kind::RCurly,
Self::parse_binding_property,
Self::parse_rest_binding,
)?;
if let Some(rest) = &rest {
if !matches!(&rest.argument.kind, BindingPatternKind::BindingIdentifier(_)) {
return Err(diagnostics::invalid_binding_rest_element(rest.argument.span()));
}
}
self.expect(Kind::RCurly)?;
Ok(self.ast.object_pattern(self.end_span(span), list, rest.map(|r| self.ast.alloc(r))))
}

/// Section 14.3.3 Array Binding Pattern
fn parse_array_binding_pattern(&mut self) -> Result<BindingPatternKind<'a>> {
let span = self.start_span();
let list = ArrayPatternList::parse(self)?;
Ok(self.ast.array_pattern(self.end_span(span), list.elements, list.rest))
self.expect(Kind::LBrack)?;
let (list, rest) = self.parse_delimited_list_with_rest(
Kind::RBrack,
Self::parse_array_binding_element,
Self::parse_rest_binding,
)?;
self.expect(Kind::RBrack)?;
Ok(self.ast.array_pattern(self.end_span(span), list, rest.map(|r| self.ast.alloc(r))))
}

fn parse_array_binding_element(&mut self) -> Result<Option<BindingPattern<'a>>> {
if self.at(Kind::Comma) {
Ok(None)
} else {
self.parse_binding_pattern_with_initializer().map(Some)
}
}

fn parse_rest_binding(&mut self) -> Result<BindingRestElement<'a>> {
// self.eat_decorators()?;
let elem = self.parse_rest_element()?;
if self.at(Kind::Comma) {
if matches!(self.peek_kind(), Kind::RCurly | Kind::RBrack) {
let span = self.cur_token().span();
self.bump_any();
self.error(diagnostics::binding_rest_element_trailing_comma(span));
}
if !self.ctx.has_ambient() {
self.error(diagnostics::binding_rest_element_last(elem.span));
}
}
Ok(elem)
}

/// Section 14.3.3 Binding Rest Property
pub(super) fn parse_rest_element(&mut self) -> Result<Box<'a, BindingRestElement<'a>>> {
pub(super) fn parse_rest_element(&mut self) -> Result<BindingRestElement<'a>> {
let span = self.start_span();
self.bump_any(); // advance `...`
let init_span = self.start_span();
Expand All @@ -73,22 +112,12 @@ impl<'a> ParserImpl<'a> {
// The span is not extended to its type_annotation
let type_annotation = self.parse_ts_type_annotation()?;
let pattern = self.ast.binding_pattern(kind, type_annotation, false);
// Rest element does not allow `= initializer`, .
// Rest element does not allow `= initializer`
let argument = self
.context(Context::In, Context::empty(), |p| p.parse_initializer(init_span, pattern))?;
let span = self.end_span(span);

if self.at(Kind::Comma) {
if self.peek_at(Kind::RBrack) {
self.error(diagnostics::binding_rest_element_trailing_comma(
self.cur_token().span(),
));
} else if !self.ctx.has_ambient() {
self.error(diagnostics::binding_rest_element_last(span));
}
}

Ok(self.ast.rest_element(span, argument))
Ok(BindingRestElement { span, argument })
}

/// `BindingProperty`[Yield, Await] :
Expand Down
72 changes: 66 additions & 6 deletions crates/oxc_parser/src/js/function.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,10 @@ use oxc_ast::ast::*;
use oxc_diagnostics::Result;
use oxc_span::Span;

use super::{list::FormalParameterList, FunctionKind};
use super::FunctionKind;
use crate::{
diagnostics,
lexer::Kind,
list::SeparatedList,
modifiers::{ModifierFlags, ModifierKind, Modifiers},
Context, ParserImpl, StatementContext,
};
Expand Down Expand Up @@ -49,13 +48,74 @@ impl<'a> ParserImpl<'a> {
params_kind: FormalParameterKind,
) -> Result<(Option<TSThisParameter<'a>>, Box<'a, FormalParameters<'a>>)> {
let span = self.start_span();
let list: FormalParameterList<'_> = FormalParameterList::parse(self)?;
let formal_parameters =
self.ast.formal_parameters(self.end_span(span), params_kind, list.elements, list.rest);
let this_param = list.this_param;
self.expect(Kind::LParen)?;
let this_param = if self.ts_enabled() && self.at(Kind::This) {
let param = self.parse_ts_this_parameter()?;
if !self.at(Kind::RParen) {
self.expect(Kind::Comma)?;
}
Some(param)
} else {
None
};
let (list, rest) = self.parse_delimited_list_with_rest(
Kind::RParen,
Self::parse_formal_parameter,
Self::parse_rest_parameter,
)?;
self.expect(Kind::RParen)?;
let formal_parameters = self.ast.formal_parameters(
self.end_span(span),
params_kind,
list,
rest.map(|r| self.ast.alloc(r)),
);
Ok((this_param, formal_parameters))
}

fn parse_parameter_modifiers(&mut self) -> Modifiers<'a> {
let modifiers = self.parse_class_element_modifiers(true);
self.verify_modifiers(
&modifiers,
ModifierFlags::ACCESSIBILITY
.union(ModifierFlags::READONLY)
.union(ModifierFlags::OVERRIDE),
diagnostics::cannot_appear_on_a_parameter,
);
modifiers
}

fn parse_formal_parameter(&mut self) -> Result<FormalParameter<'a>> {
let span = self.start_span();
self.eat_decorators()?;
let modifiers = self.parse_parameter_modifiers();
let pattern = self.parse_binding_pattern_with_initializer()?;
let decorators = self.consume_decorators();
Ok(self.ast.formal_parameter(
self.end_span(span),
pattern,
modifiers.accessibility(),
modifiers.contains_readonly(),
modifiers.contains_override(),
decorators,
))
}

fn parse_rest_parameter(&mut self) -> Result<BindingRestElement<'a>> {
let element = self.parse_rest_element()?;
if self.at(Kind::Comma) {
if matches!(self.peek_kind(), Kind::RCurly | Kind::RBrack) {
let span = self.cur_token().span();
self.bump_any();
self.error(diagnostics::binding_rest_element_trailing_comma(span));
}
if !self.ctx.has_ambient() {
self.error(diagnostics::rest_parameter_last(element.span));
}
}
Ok(element)
}

pub(crate) fn parse_function(
&mut self,
span: Span,
Expand Down
Loading

0 comments on commit 3945397

Please sign in to comment.