Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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