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:
Boshen 2024-07-02 14:47:56 +08:00 committed by GitHub
parent e2c9015ef6
commit 1dacb1fc5b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
11 changed files with 301 additions and 507 deletions

View file

@ -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)
}
}

View file

@ -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();

View file

@ -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(())
}
}

View file

@ -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 })
}
}

View file

@ -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();

View file

@ -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(())
}
}

View file

@ -1,3 +1,2 @@
mod list;
mod statement;
mod types;

View file

@ -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,

View file

@ -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(

View file

@ -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`

View file

@ -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);
╰────