mirror of
https://github.com/danbulant/oxc
synced 2026-05-19 04:08:41 +00:00
refactor(parser): use function instead of trait to parse delimited lists (#4014)
relates #3887 The rest of the list parsing trait implementations involves ... parsing `rest`, which I'll refactor in another PR.
This commit is contained in:
parent
e2c9015ef6
commit
1dacb1fc5b
11 changed files with 301 additions and 507 deletions
|
|
@ -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 {
|
||||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
@ -21,7 +20,6 @@ use super::{
|
|||
use crate::{
|
||||
diagnostics,
|
||||
lexer::{parse_big_int, parse_float, parse_int, Kind},
|
||||
list::SeparatedList,
|
||||
Context, ParserImpl,
|
||||
};
|
||||
|
||||
|
|
@ -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() {
|
||||
|
|
@ -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 :
|
||||
|
|
@ -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()
|
||||
};
|
||||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -1,47 +1,10 @@
|
|||
use oxc_allocator::Vec;
|
||||
use oxc_ast::ast::*;
|
||||
use oxc_diagnostics::Result;
|
||||
use oxc_span::{Atom, GetSpan, Span};
|
||||
use rustc_hash::FxHashMap;
|
||||
use oxc_span::GetSpan;
|
||||
|
||||
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>>,
|
||||
|
|
@ -78,43 +41,6 @@ impl<'a> SeparatedList<'a> for ObjectPatternProperties<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
/// ArrayExpression.elements
|
||||
pub struct ArrayExpressionList<'a> {
|
||||
pub elements: Vec<'a, ArrayExpressionElement<'a>>,
|
||||
pub trailing_comma: Option<Span>,
|
||||
}
|
||||
|
||||
impl<'a> SeparatedList<'a> for ArrayExpressionList<'a> {
|
||||
fn new(p: &ParserImpl<'a>) -> Self {
|
||||
Self { elements: p.ast.new_vec(), trailing_comma: None }
|
||||
}
|
||||
|
||||
fn open(&self) -> Kind {
|
||||
Kind::LBrack
|
||||
}
|
||||
|
||||
fn close(&self) -> Kind {
|
||||
Kind::RBrack
|
||||
}
|
||||
|
||||
fn parse_element(&mut self, p: &mut ParserImpl<'a>) -> Result<()> {
|
||||
let element = match p.cur_kind() {
|
||||
Kind::Comma => Ok(p.parse_elision()),
|
||||
Kind::Dot3 => p.parse_spread_element().map(ArrayExpressionElement::SpreadElement),
|
||||
_ => p.parse_assignment_expression_or_higher().map(ArrayExpressionElement::from),
|
||||
};
|
||||
|
||||
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(())
|
||||
}
|
||||
}
|
||||
|
||||
/// ArrayPattern.elements
|
||||
pub struct ArrayPatternList<'a> {
|
||||
pub elements: Vec<'a, Option<BindingPattern<'a>>>,
|
||||
|
|
@ -154,87 +80,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>>,
|
||||
|
|
@ -301,122 +146,3 @@ impl<'a> SeparatedList<'a> for FormalParameterList<'a> {
|
|||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// [Assert Entries](https://tc39.es/proposal-import-assertions)
|
||||
pub struct AssertEntries<'a> {
|
||||
pub elements: Vec<'a, ImportAttribute<'a>>,
|
||||
keys: FxHashMap<Atom<'a>, Span>,
|
||||
}
|
||||
|
||||
impl<'a> SeparatedList<'a> for AssertEntries<'a> {
|
||||
fn new(p: &ParserImpl<'a>) -> Self {
|
||||
Self { elements: p.ast.new_vec(), keys: FxHashMap::default() }
|
||||
}
|
||||
|
||||
fn open(&self) -> Kind {
|
||||
Kind::LCurly
|
||||
}
|
||||
|
||||
fn close(&self) -> Kind {
|
||||
Kind::RCurly
|
||||
}
|
||||
|
||||
fn parse_element(&mut self, p: &mut ParserImpl<'a>) -> Result<()> {
|
||||
let span = p.start_span();
|
||||
let key = match p.cur_kind() {
|
||||
Kind::Str => ImportAttributeKey::StringLiteral(p.parse_literal_string()?),
|
||||
_ => ImportAttributeKey::Identifier(p.parse_identifier_name()?),
|
||||
};
|
||||
|
||||
if let Some(old_span) = self.keys.get(&key.as_atom()) {
|
||||
p.error(diagnostics::redeclaration(key.as_atom().as_str(), *old_span, key.span()));
|
||||
} else {
|
||||
self.keys.insert(key.as_atom(), key.span());
|
||||
}
|
||||
|
||||
p.expect(Kind::Colon)?;
|
||||
let value = p.parse_literal_string()?;
|
||||
let element = ImportAttribute { span: p.end_span(span), key, value };
|
||||
self.elements.push(element);
|
||||
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(())
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,15 +1,11 @@
|
|||
use oxc_allocator::{Box, Vec};
|
||||
use oxc_ast::ast::*;
|
||||
use oxc_diagnostics::Result;
|
||||
use oxc_span::Span;
|
||||
use oxc_span::{GetSpan, Span};
|
||||
use rustc_hash::FxHashMap;
|
||||
|
||||
use super::{
|
||||
list::{AssertEntries, ExportNamedSpecifiers, ImportSpecifierList},
|
||||
FunctionKind,
|
||||
};
|
||||
use crate::{
|
||||
diagnostics, lexer::Kind, list::SeparatedList, modifiers::Modifiers, Context, ParserImpl,
|
||||
};
|
||||
use super::FunctionKind;
|
||||
use crate::{diagnostics, lexer::Kind, modifiers::Modifiers, Context, ParserImpl};
|
||||
|
||||
impl<'a> ParserImpl<'a> {
|
||||
/// [Import Call](https://tc39.es/ecma262/#sec-import-calls)
|
||||
|
|
@ -127,8 +123,17 @@ impl<'a> ParserImpl<'a> {
|
|||
|
||||
// import { export1 , export2 as alias2 , [...] } from "module-name";
|
||||
fn parse_import_specifiers(&mut self) -> Result<Vec<'a, ImportDeclarationSpecifier<'a>>> {
|
||||
self.context(Context::empty(), self.ctx, ImportSpecifierList::parse)
|
||||
.map(|x| x.import_specifiers)
|
||||
self.expect(Kind::LCurly)?;
|
||||
let list = self.context(Context::empty(), self.ctx, |p| {
|
||||
p.parse_delimited_list(
|
||||
Kind::RCurly,
|
||||
Kind::Comma,
|
||||
/* trailing_separator */ true,
|
||||
Self::parse_import_specifier,
|
||||
)
|
||||
})?;
|
||||
self.expect(Kind::RCurly)?;
|
||||
Ok(list)
|
||||
}
|
||||
|
||||
/// [Import Attributes](https://tc39.es/proposal-import-attributes)
|
||||
|
|
@ -141,10 +146,40 @@ impl<'a> ParserImpl<'a> {
|
|||
}
|
||||
};
|
||||
let span = self.start_span();
|
||||
let with_entries = self.context(Context::empty(), self.ctx, AssertEntries::parse)?.elements;
|
||||
self.expect(Kind::LCurly)?;
|
||||
let with_entries = self.context(Context::empty(), self.ctx, |p| {
|
||||
p.parse_delimited_list(
|
||||
Kind::RCurly,
|
||||
Kind::Comma,
|
||||
/*trailing_separator*/ true,
|
||||
Self::parse_import_attribute,
|
||||
)
|
||||
})?;
|
||||
self.expect(Kind::RCurly)?;
|
||||
|
||||
let mut keys = FxHashMap::default();
|
||||
for e in &with_entries {
|
||||
let key = e.key.as_atom().as_str();
|
||||
let span = e.key.span();
|
||||
if let Some(old_span) = keys.insert(key, span) {
|
||||
self.error(diagnostics::redeclaration(key, old_span, span));
|
||||
}
|
||||
}
|
||||
|
||||
Ok(Some(WithClause { span: self.end_span(span), attributes_keyword, with_entries }))
|
||||
}
|
||||
|
||||
fn parse_import_attribute(&mut self) -> Result<ImportAttribute<'a>> {
|
||||
let span = self.start_span();
|
||||
let key = match self.cur_kind() {
|
||||
Kind::Str => ImportAttributeKey::StringLiteral(self.parse_literal_string()?),
|
||||
_ => ImportAttributeKey::Identifier(self.parse_identifier_name()?),
|
||||
};
|
||||
self.expect(Kind::Colon)?;
|
||||
let value = self.parse_literal_string()?;
|
||||
Ok(ImportAttribute { span: self.end_span(span), key, value })
|
||||
}
|
||||
|
||||
pub(crate) fn parse_ts_export_assignment_declaration(
|
||||
&mut self,
|
||||
start_span: Span,
|
||||
|
|
@ -220,8 +255,16 @@ impl<'a> ParserImpl<'a> {
|
|||
span: Span,
|
||||
) -> Result<Box<'a, ExportNamedDeclaration<'a>>> {
|
||||
let export_kind = self.parse_import_or_export_kind();
|
||||
let mut specifiers =
|
||||
self.context(Context::empty(), self.ctx, ExportNamedSpecifiers::parse)?.elements;
|
||||
self.expect(Kind::LCurly)?;
|
||||
let mut specifiers = self.context(Context::empty(), self.ctx, |p| {
|
||||
p.parse_delimited_list(
|
||||
Kind::RCurly,
|
||||
Kind::Comma,
|
||||
/* trailing_separator */ true,
|
||||
Self::parse_export_named_specifier,
|
||||
)
|
||||
})?;
|
||||
self.expect(Kind::RCurly)?;
|
||||
let (source, with_clause) = if self.eat(Kind::From) && self.cur_kind().is_literal() {
|
||||
let source = self.parse_literal_string()?;
|
||||
(Some(source), self.parse_import_attributes()?)
|
||||
|
|
@ -380,7 +423,7 @@ impl<'a> ParserImpl<'a> {
|
|||
// ImportSpecifier :
|
||||
// ImportedBinding
|
||||
// ModuleExportName as ImportedBinding
|
||||
pub(crate) fn parse_import_specifier(&mut self) -> Result<Box<'a, ImportSpecifier<'a>>> {
|
||||
pub(crate) fn parse_import_specifier(&mut self) -> Result<ImportDeclarationSpecifier<'a>> {
|
||||
let specifier_span = self.start_span();
|
||||
let peek_kind = self.peek_kind();
|
||||
let mut import_kind = ImportOrExportKind::Value;
|
||||
|
|
@ -411,12 +454,12 @@ impl<'a> ParserImpl<'a> {
|
|||
let imported = IdentifierName { span: local.span, name: local.name.clone() };
|
||||
(ModuleExportName::IdentifierName(imported), local)
|
||||
};
|
||||
Ok(self.ast.alloc(ImportSpecifier {
|
||||
Ok(ImportDeclarationSpecifier::ImportSpecifier(self.ast.alloc(ImportSpecifier {
|
||||
span: self.end_span(specifier_span),
|
||||
imported,
|
||||
local,
|
||||
import_kind,
|
||||
}))
|
||||
})))
|
||||
}
|
||||
|
||||
// ModuleExportName :
|
||||
|
|
@ -472,4 +515,37 @@ impl<'a> ParserImpl<'a> {
|
|||
|
||||
ImportOrExportKind::Value
|
||||
}
|
||||
|
||||
fn parse_export_named_specifier(&mut self) -> Result<ExportSpecifier<'a>> {
|
||||
let specifier_span = self.start_span();
|
||||
let peek_kind = self.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 self.ts_enabled() && self.at(Kind::Type) {
|
||||
if self.peek_at(Kind::As) {
|
||||
if self.nth_at(2, Kind::As) {
|
||||
if self.nth_at(3, Kind::Str) || self.nth_kind(3).is_identifier_name() {
|
||||
export_kind = ImportOrExportKind::Type;
|
||||
}
|
||||
} else if !(self.nth_at(2, Kind::Str) || self.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 {
|
||||
self.bump_any();
|
||||
}
|
||||
|
||||
let local = self.parse_module_export_name()?;
|
||||
let exported =
|
||||
if self.eat(Kind::As) { self.parse_module_export_name()? } else { local.clone() };
|
||||
Ok(ExportSpecifier { span: self.end_span(specifier_span), local, exported, export_kind })
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,10 +4,7 @@ use oxc_diagnostics::Result;
|
|||
use oxc_span::Span;
|
||||
use oxc_syntax::operator::AssignmentOperator;
|
||||
|
||||
use super::list::ObjectExpressionProperties;
|
||||
use crate::{
|
||||
diagnostics, lexer::Kind, list::SeparatedList, modifiers::Modifier, Context, ParserImpl,
|
||||
};
|
||||
use crate::{diagnostics, lexer::Kind, modifiers::Modifier, Context, ParserImpl};
|
||||
|
||||
impl<'a> ParserImpl<'a> {
|
||||
/// [Object Expression](https://tc39.es/ecma262/#sec-object-initializer)
|
||||
|
|
@ -17,15 +14,35 @@ impl<'a> ParserImpl<'a> {
|
|||
/// { `PropertyDefinitionList`[?Yield, ?Await] , }
|
||||
pub(crate) fn parse_object_expression(&mut self) -> Result<Expression<'a>> {
|
||||
let span = self.start_span();
|
||||
let object_expression_properties =
|
||||
self.context(Context::In, Context::empty(), ObjectExpressionProperties::parse)?;
|
||||
self.expect(Kind::LCurly)?;
|
||||
let object_expression_properties = self.context(Context::In, Context::empty(), |p| {
|
||||
p.parse_delimited_list(
|
||||
Kind::RCurly,
|
||||
Kind::Comma,
|
||||
/* trailing_separator */ false,
|
||||
Self::parse_object_expression_property,
|
||||
)
|
||||
})?;
|
||||
let trailing_comma = self.at(Kind::Comma).then(|| {
|
||||
let span = self.start_span();
|
||||
self.bump_any();
|
||||
self.end_span(span)
|
||||
});
|
||||
self.expect(Kind::RCurly)?;
|
||||
Ok(self.ast.object_expression(
|
||||
self.end_span(span),
|
||||
object_expression_properties.elements,
|
||||
object_expression_properties.trailing_comma,
|
||||
object_expression_properties,
|
||||
trailing_comma,
|
||||
))
|
||||
}
|
||||
|
||||
fn parse_object_expression_property(&mut self) -> Result<ObjectPropertyKind<'a>> {
|
||||
match self.cur_kind() {
|
||||
Kind::Dot3 => self.parse_spread_element().map(ObjectPropertyKind::SpreadProperty),
|
||||
_ => self.parse_property_definition().map(ObjectPropertyKind::ObjectProperty),
|
||||
}
|
||||
}
|
||||
|
||||
/// `PropertyDefinition`[Yield, Await]
|
||||
pub(crate) fn parse_property_definition(&mut self) -> Result<Box<'a, ObjectProperty<'a>>> {
|
||||
let peek_kind = self.peek_kind();
|
||||
|
|
|
|||
|
|
@ -1,172 +0,0 @@
|
|||
use oxc_allocator::Vec;
|
||||
use oxc_ast::ast::*;
|
||||
use oxc_diagnostics::Result;
|
||||
|
||||
use crate::{lexer::Kind, list::SeparatedList, ParserImpl};
|
||||
|
||||
pub struct TSEnumMemberList<'a> {
|
||||
pub members: Vec<'a, TSEnumMember<'a>>,
|
||||
}
|
||||
|
||||
impl<'a> SeparatedList<'a> for TSEnumMemberList<'a> {
|
||||
fn new(p: &ParserImpl<'a>) -> Self {
|
||||
Self { members: 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 element = p.parse_ts_enum_member()?;
|
||||
self.members.push(element);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub struct TSTupleElementList<'a> {
|
||||
pub elements: Vec<'a, TSTupleElement<'a>>,
|
||||
}
|
||||
|
||||
impl<'a> SeparatedList<'a> for TSTupleElementList<'a> {
|
||||
fn new(p: &ParserImpl<'a>) -> Self {
|
||||
Self { elements: p.ast.new_vec() }
|
||||
}
|
||||
|
||||
fn open(&self) -> Kind {
|
||||
Kind::LBrack
|
||||
}
|
||||
|
||||
fn close(&self) -> Kind {
|
||||
Kind::RBrack
|
||||
}
|
||||
|
||||
fn parse_element(&mut self, p: &mut ParserImpl<'a>) -> Result<()> {
|
||||
let ty = p.parse_tuple_element_name_or_tuple_element_type()?;
|
||||
self.elements.push(ty);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub struct TSTypeParameterList<'a> {
|
||||
pub params: Vec<'a, TSTypeParameter<'a>>,
|
||||
}
|
||||
|
||||
impl<'a> SeparatedList<'a> for TSTypeParameterList<'a> {
|
||||
fn new(p: &ParserImpl<'a>) -> Self {
|
||||
Self { params: p.ast.new_vec() }
|
||||
}
|
||||
|
||||
fn open(&self) -> Kind {
|
||||
Kind::LAngle
|
||||
}
|
||||
|
||||
fn close(&self) -> Kind {
|
||||
Kind::RAngle
|
||||
}
|
||||
|
||||
fn parse_element(&mut self, p: &mut ParserImpl<'a>) -> Result<()> {
|
||||
let param = p.parse_ts_type_parameter()?;
|
||||
self.params.push(param);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub struct TSTypeArgumentList<'a> {
|
||||
pub params: Vec<'a, TSType<'a>>,
|
||||
in_expression: bool,
|
||||
}
|
||||
|
||||
impl<'a> TSTypeArgumentList<'a> {
|
||||
pub fn parse(p: &mut ParserImpl<'a>, in_expression: bool) -> Result<Self> {
|
||||
let mut list = Self::new(p);
|
||||
list.in_expression = in_expression;
|
||||
list.parse_list(p)?;
|
||||
Ok(list)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> SeparatedList<'a> for TSTypeArgumentList<'a> {
|
||||
fn new(p: &ParserImpl<'a>) -> Self {
|
||||
Self { params: p.ast.new_vec(), in_expression: false }
|
||||
}
|
||||
|
||||
fn open(&self) -> Kind {
|
||||
Kind::LAngle
|
||||
}
|
||||
|
||||
fn close(&self) -> Kind {
|
||||
Kind::RAngle
|
||||
}
|
||||
|
||||
fn parse_element(&mut self, p: &mut ParserImpl<'a>) -> Result<()> {
|
||||
let ty = p.parse_ts_type()?;
|
||||
self.params.push(ty);
|
||||
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())?;
|
||||
if p.at(self.close()) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
self.parse_element(p)?;
|
||||
}
|
||||
|
||||
if self.in_expression {
|
||||
// `a < b> = c`` is valid but `a < b >= c` is BinaryExpression
|
||||
if matches!(p.re_lex_right_angle(), Kind::GtEq) {
|
||||
return Err(p.unexpected());
|
||||
}
|
||||
p.re_lex_ts_r_angle();
|
||||
}
|
||||
p.expect(self.close())?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub struct TSImportAttributeList<'a> {
|
||||
pub elements: Vec<'a, TSImportAttribute<'a>>,
|
||||
}
|
||||
|
||||
impl<'a> SeparatedList<'a> for TSImportAttributeList<'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 span = p.start_span();
|
||||
let name = match p.cur_kind() {
|
||||
Kind::Str => TSImportAttributeName::StringLiteral(p.parse_literal_string()?),
|
||||
_ => TSImportAttributeName::Identifier(p.parse_identifier_name()?),
|
||||
};
|
||||
|
||||
p.expect(Kind::Colon)?;
|
||||
let value = p.parse_expr()?;
|
||||
let element = TSImportAttribute { span: p.end_span(span), name, value };
|
||||
self.elements.push(element);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
@ -1,3 +1,2 @@
|
|||
mod list;
|
||||
mod statement;
|
||||
mod types;
|
||||
|
|
|
|||
|
|
@ -3,12 +3,10 @@ use oxc_ast::ast::*;
|
|||
use oxc_diagnostics::Result;
|
||||
use oxc_span::Span;
|
||||
|
||||
use super::list::TSEnumMemberList;
|
||||
use crate::{
|
||||
diagnostics,
|
||||
js::{FunctionKind, VariableDeclarationContext, VariableDeclarationParent},
|
||||
lexer::Kind,
|
||||
list::SeparatedList,
|
||||
modifiers::{ModifierFlags, ModifierKind, Modifiers},
|
||||
ParserImpl,
|
||||
};
|
||||
|
|
@ -27,17 +25,21 @@ impl<'a> ParserImpl<'a> {
|
|||
modifiers: &Modifiers<'a>,
|
||||
) -> Result<Declaration<'a>> {
|
||||
self.bump_any(); // bump `enum`
|
||||
|
||||
let id = self.parse_binding_identifier()?;
|
||||
let members = TSEnumMemberList::parse(self)?.members;
|
||||
self.expect(Kind::LCurly)?;
|
||||
let members = self.parse_delimited_list(
|
||||
Kind::RCurly,
|
||||
Kind::Comma,
|
||||
/* trailing_separator */ true,
|
||||
Self::parse_ts_enum_member,
|
||||
)?;
|
||||
self.expect(Kind::RCurly)?;
|
||||
let span = self.end_span(span);
|
||||
|
||||
self.verify_modifiers(
|
||||
modifiers,
|
||||
ModifierFlags::DECLARE | ModifierFlags::CONST,
|
||||
diagnostics::modifier_cannot_be_used_here,
|
||||
);
|
||||
|
||||
Ok(self.ast.ts_enum_declaration(
|
||||
span,
|
||||
id,
|
||||
|
|
|
|||
|
|
@ -4,13 +4,10 @@ use oxc_diagnostics::Result;
|
|||
use oxc_span::GetSpan;
|
||||
use oxc_syntax::operator::UnaryOperator;
|
||||
|
||||
use super::list::{TSTupleElementList, TSTypeArgumentList, TSTypeParameterList};
|
||||
use crate::{
|
||||
diagnostics,
|
||||
lexer::Kind,
|
||||
list::SeparatedList,
|
||||
modifiers::{Modifier, ModifierFlags, ModifierKind, Modifiers},
|
||||
ts::list::TSImportAttributeList,
|
||||
Context, ParserImpl,
|
||||
};
|
||||
|
||||
|
|
@ -142,7 +139,14 @@ impl<'a> ParserImpl<'a> {
|
|||
return Ok(None);
|
||||
}
|
||||
let span = self.start_span();
|
||||
let params = TSTypeParameterList::parse(self)?.params;
|
||||
self.expect(Kind::LAngle)?;
|
||||
let params = self.parse_delimited_list(
|
||||
Kind::RAngle,
|
||||
Kind::Comma,
|
||||
/* trailing_separator */ true,
|
||||
Self::parse_ts_type_parameter,
|
||||
)?;
|
||||
self.expect(Kind::RAngle)?;
|
||||
Ok(Some(self.ast.ts_type_parameters(self.end_span(span), params)))
|
||||
}
|
||||
|
||||
|
|
@ -756,7 +760,14 @@ impl<'a> ParserImpl<'a> {
|
|||
) -> Result<Option<Box<'a, TSTypeParameterInstantiation<'a>>>> {
|
||||
if self.at(Kind::LAngle) {
|
||||
let span = self.start_span();
|
||||
let params = TSTypeArgumentList::parse(self, false)?.params;
|
||||
self.expect(Kind::LAngle)?;
|
||||
let params = self.parse_delimited_list(
|
||||
Kind::RAngle,
|
||||
Kind::Comma,
|
||||
/* trailing_separator */ true,
|
||||
Self::parse_ts_type,
|
||||
)?;
|
||||
self.expect(Kind::RAngle)?;
|
||||
return Ok(Some(self.ast.ts_type_arguments(self.end_span(span), params)));
|
||||
}
|
||||
Ok(None)
|
||||
|
|
@ -768,7 +779,14 @@ impl<'a> ParserImpl<'a> {
|
|||
self.re_lex_l_angle();
|
||||
if !self.cur_token().is_on_new_line && self.re_lex_l_angle() == Kind::LAngle {
|
||||
let span = self.start_span();
|
||||
let params = TSTypeArgumentList::parse(self, false)?.params;
|
||||
self.expect(Kind::LAngle)?;
|
||||
let params = self.parse_delimited_list(
|
||||
Kind::RAngle,
|
||||
Kind::Comma,
|
||||
/* trailing_separator */ true,
|
||||
Self::parse_ts_type,
|
||||
)?;
|
||||
self.expect(Kind::RAngle)?;
|
||||
return Ok(Some(self.ast.ts_type_arguments(self.end_span(span), params)));
|
||||
}
|
||||
Ok(None)
|
||||
|
|
@ -784,7 +802,19 @@ impl<'a> ParserImpl<'a> {
|
|||
if self.re_lex_l_angle() != Kind::LAngle {
|
||||
return Ok(None);
|
||||
}
|
||||
let params = TSTypeArgumentList::parse(self, /* in_expression */ true)?.params;
|
||||
self.expect(Kind::LAngle)?;
|
||||
let params = self.parse_delimited_list(
|
||||
Kind::RAngle,
|
||||
Kind::Comma,
|
||||
/* trailing_separator */ true,
|
||||
Self::parse_ts_type,
|
||||
)?;
|
||||
// `a < b> = c`` is valid but `a < b >= c` is BinaryExpression
|
||||
if matches!(self.re_lex_right_angle(), Kind::GtEq) {
|
||||
return Err(self.unexpected());
|
||||
}
|
||||
self.re_lex_ts_r_angle();
|
||||
self.expect(Kind::RAngle)?;
|
||||
if self.can_follow_type_arguments_in_expr() {
|
||||
return Ok(Some(self.ast.ts_type_arguments(self.end_span(span), params)));
|
||||
}
|
||||
|
|
@ -805,7 +835,14 @@ impl<'a> ParserImpl<'a> {
|
|||
|
||||
fn parse_tuple_type(&mut self) -> Result<TSType<'a>> {
|
||||
let span = self.start_span();
|
||||
let elements = TSTupleElementList::parse(self)?.elements;
|
||||
self.expect(Kind::LBrack)?;
|
||||
let elements = self.parse_delimited_list(
|
||||
Kind::RBrack,
|
||||
Kind::Comma,
|
||||
/* trailing_separator */ true,
|
||||
Self::parse_tuple_element_name_or_tuple_element_type,
|
||||
)?;
|
||||
self.expect(Kind::RBrack)?;
|
||||
Ok(self.ast.ts_tuple_type(self.end_span(span), elements))
|
||||
}
|
||||
|
||||
|
|
@ -955,11 +992,30 @@ impl<'a> ParserImpl<'a> {
|
|||
self.expect(Kind::LCurly)?;
|
||||
self.expect(Kind::With)?;
|
||||
self.expect(Kind::Colon)?;
|
||||
let elements = TSImportAttributeList::parse(self)?.elements;
|
||||
self.expect(Kind::LCurly)?;
|
||||
let elements = self.parse_delimited_list(
|
||||
Kind::RCurly,
|
||||
Kind::Comma,
|
||||
/* trailing_separator */ true,
|
||||
Self::parse_ts_import_attribute,
|
||||
)?;
|
||||
self.expect(Kind::RCurly)?;
|
||||
self.expect(Kind::RCurly)?;
|
||||
Ok(TSImportAttributes { span, elements })
|
||||
}
|
||||
|
||||
fn parse_ts_import_attribute(&mut self) -> Result<TSImportAttribute<'a>> {
|
||||
let span = self.start_span();
|
||||
let name = match self.cur_kind() {
|
||||
Kind::Str => TSImportAttributeName::StringLiteral(self.parse_literal_string()?),
|
||||
_ => TSImportAttributeName::Identifier(self.parse_identifier_name()?),
|
||||
};
|
||||
|
||||
self.expect(Kind::Colon)?;
|
||||
let value = self.parse_expr()?;
|
||||
Ok(TSImportAttribute { span: self.end_span(span), name, value })
|
||||
}
|
||||
|
||||
fn try_parse_constraint_of_infer_type(&mut self) -> Result<Option<TSType<'a>>> {
|
||||
if self.eat(Kind::Extends) {
|
||||
let constraint = self.context(
|
||||
|
|
|
|||
|
|
@ -5209,10 +5209,11 @@ Expect to Parse: "typescript/types/const-type-parameters-babel-7/input.ts"
|
|||
· ─
|
||||
╰────
|
||||
|
||||
× Unexpected token
|
||||
╭─[es2017/trailing-function-commas/7/input.js:1:8]
|
||||
× Expected `)` but found `,`
|
||||
╭─[es2017/trailing-function-commas/7/input.js:1:7]
|
||||
1 │ ('foo',)
|
||||
· ─
|
||||
· ┬
|
||||
· ╰── `)` expected
|
||||
╰────
|
||||
|
||||
× Expected `(` but found `await`
|
||||
|
|
|
|||
|
|
@ -15592,11 +15592,12 @@ Expect to Parse: "conformance/salsa/plainJSRedeclare3.ts"
|
|||
8 │ this += value;
|
||||
╰────
|
||||
|
||||
× Unexpected token
|
||||
╭─[conformance/expressions/commaOperator/commaOperatorWithoutOperand.ts:9:7]
|
||||
× Expected `)` but found `,`
|
||||
╭─[conformance/expressions/commaOperator/commaOperatorWithoutOperand.ts:9:5]
|
||||
8 │ // Missing the second operand
|
||||
9 │ (ANY, );
|
||||
· ─
|
||||
· ┬
|
||||
· ╰── `)` expected
|
||||
10 │ (BOOLEAN, );
|
||||
╰────
|
||||
|
||||
|
|
@ -16114,11 +16115,12 @@ Expect to Parse: "conformance/salsa/plainJSRedeclare3.ts"
|
|||
· ─
|
||||
╰────
|
||||
|
||||
× Unexpected token
|
||||
╭─[conformance/externalModules/topLevelAwaitErrors.1.ts:4:10]
|
||||
× Expected `)` but found `,`
|
||||
╭─[conformance/externalModules/topLevelAwaitErrors.1.ts:4:9]
|
||||
3 │ // reparse call as invalid await should error
|
||||
4 │ await (1,);
|
||||
· ─
|
||||
· ┬
|
||||
· ╰── `)` expected
|
||||
5 │ await <number, string>(1);
|
||||
╰────
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue