oxc/crates/oxc_parser/src/js/list.rs

480 lines
14 KiB
Rust

use oxc_allocator::Vec;
use oxc_ast::{ast::*, syntax_directed_operations::PrivateBoundIdentifiers, Atom, GetSpan, Span};
use oxc_diagnostics::Result;
use rustc_hash::FxHashMap;
use crate::diagnostics;
use crate::lexer::Kind;
use crate::list::{NormalList, SeparatedList};
use crate::Parser;
/// ObjectExpression.properties
pub struct ObjectExpressionProperties<'a> {
pub elements: Vec<'a, ObjectProperty<'a>>,
pub trailing_comma: Option<Span>,
}
impl<'a> SeparatedList<'a> for ObjectExpressionProperties<'a> {
fn new(p: &Parser<'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 Parser<'a>) -> Result<()> {
let element = match p.cur_kind() {
Kind::Dot3 => p.parse_spread_element().map(ObjectProperty::SpreadProperty),
_ => p.parse_property_definition().map(ObjectProperty::Property),
}?;
if p.at(Kind::Comma) && p.peek_at(self.close()) {
self.trailing_comma = Some(p.end_span(p.start_span()));
}
self.elements.push(element);
Ok(())
}
}
/// ObjectPattern.properties
pub struct ObjectPatternProperties<'a> {
pub elements: Vec<'a, ObjectPatternProperty<'a>>,
}
impl<'a> SeparatedList<'a> for ObjectPatternProperties<'a> {
fn new(p: &Parser<'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 Parser<'a>) -> Result<()> {
let element = match p.cur_kind() {
Kind::Dot3 => {
let rest_element = p.parse_rest_element()?;
if !matches!(rest_element.argument.kind, BindingPatternKind::BindingIdentifier(_)) {
p.error(diagnostics::InvalidRestArgument(rest_element.span));
}
ObjectPatternProperty::RestElement(rest_element)
}
_ => p
.parse_object_pattern_property()
.map(|prop| p.ast.alloc(prop))
.map(ObjectPatternProperty::Property)?,
};
self.elements.push(element);
Ok(())
}
}
/// ArrayExpression.elements, with optional element
pub struct ArrayExpressionList<'a> {
pub elements: Vec<'a, Option<Argument<'a>>>,
pub trailing_comma: Option<Span>,
}
impl<'a> SeparatedList<'a> for ArrayExpressionList<'a> {
fn new(p: &Parser<'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 Parser<'a>) -> Result<()> {
let element = match p.cur_kind() {
Kind::Comma => Ok(None),
Kind::Dot3 => p.parse_spread_element().map(Argument::SpreadElement).map(Some),
_ => p.parse_assignment_expression_base().map(Argument::Expression).map(Some),
};
if p.at(Kind::Comma) && p.peek_at(self.close()) {
self.trailing_comma = Some(p.end_span(p.start_span()));
}
self.elements.push(element?);
Ok(())
}
}
/// ArrayPattern.elements, with optional element
pub struct ArrayPatternList<'a> {
pub elements: Vec<'a, Option<BindingPattern<'a>>>,
}
impl<'a> SeparatedList<'a> for ArrayPatternList<'a> {
fn new(p: &Parser<'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 Parser<'a>) -> Result<()> {
let element = match p.cur_kind() {
Kind::Comma => None,
Kind::Dot3 => {
p.parse_rest_element().map(|rest| p.ast.rest_element_pattern(rest)).map(Some)?
}
_ => p.parse_binding_element().map(Some)?,
};
self.elements.push(element);
Ok(())
}
}
/// 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: &Parser<'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 Parser<'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_base().map(Argument::Expression)
};
self.elements.push(element?);
Ok(())
}
}
pub struct SequenceExpressionList<'a> {
pub span: Span,
pub elements: Vec<'a, Expression<'a>>,
}
impl<'a> SeparatedList<'a> for SequenceExpressionList<'a> {
fn new(p: &Parser<'a>) -> Self {
Self { elements: p.ast.new_vec(), span: Span::default() }
}
fn open(&self) -> Kind {
Kind::LParen
}
fn close(&self) -> Kind {
Kind::RParen
}
fn start_sequence(&mut self, p: &mut Parser) {
self.span = p.start_span();
}
fn finish_sequence(&mut self, p: &mut Parser) {
self.span = p.end_span(self.span);
}
// read everything as expression and map to it to either
// ParenthesizedExpression or ArrowFormalParameters later
fn parse_element(&mut self, p: &mut Parser<'a>) -> Result<()> {
let element = p.parse_assignment_expression_base()?;
self.elements.push(element);
Ok(())
}
}
/// Function Parameters
pub struct FormalParameterList<'a> {
pub elements: Vec<'a, FormalParameter<'a>>,
}
impl<'a> SeparatedList<'a> for FormalParameterList<'a> {
fn new(p: &Parser<'a>) -> Self {
Self { elements: p.ast.new_vec() }
}
fn open(&self) -> Kind {
Kind::LParen
}
fn close(&self) -> Kind {
Kind::RParen
}
// Section 15.1 Parameter Lists
fn parse_element(&mut self, p: &mut Parser<'a>) -> Result<()> {
let span = p.start_span();
p.eat_decorators()?;
let modifiers = p.parse_class_element_modifiers(true);
let accessibility = modifiers.accessibility();
let readonly = modifiers.readonly();
let pattern = match p.cur_kind() {
Kind::Dot3 => p.parse_rest_element().map(|rest| p.ast.rest_element_pattern(rest))?,
Kind::This if p.ts_enabled() => {
p.parse_ts_this_parameter()?;
// don't add this to ast fow now, the ast span shouldn't be in BindingIdentifier
return Ok(());
}
_ => p.parse_binding_element()?,
};
let decorators = p.state.consume_decorators();
let formal_parameter =
p.ast.formal_parameter(p.end_span(span), pattern, accessibility, readonly, decorators);
self.elements.push(formal_parameter);
Ok(())
}
}
/// Assert Entries
/// `https://tc39.es/proposal-import-assertions`
pub struct AssertEntries<'a> {
pub elements: Vec<'a, ImportAttribute>,
keys: FxHashMap<Atom, Span>,
}
impl<'a> SeparatedList<'a> for AssertEntries<'a> {
fn new(p: &Parser<'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 Parser<'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(), *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>,
}
impl<'a> SeparatedList<'a> for ExportNamedSpecifiers<'a> {
fn new(p: &Parser<'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 Parser<'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 };
self.elements.push(element);
Ok(())
}
}
pub struct PrivateBoundIdentifierMeta {
span: Span,
r#static: bool,
kind: Option<MethodDefinitionKind>,
}
pub struct ClassElements<'a> {
pub elements: Vec<'a, ClassElement<'a>>,
/// https://tc39.es/ecma262/#sec-static-semantics-privateboundidentifiers
pub private_bound_identifiers: FxHashMap<Atom, PrivateBoundIdentifierMeta>,
}
impl<'a> ClassElements<'a> {
pub fn new(p: &mut Parser<'a>) -> Self {
Self { elements: p.ast.new_vec(), private_bound_identifiers: FxHashMap::default() }
}
fn detect_private_name_conflict(
&self,
p: &mut Parser,
private_ident: &PrivateIdentifier,
r#static: bool,
kind: Option<MethodDefinitionKind>,
) {
if let Some(existed) = self.private_bound_identifiers.get(&private_ident.name) {
if !(r#static == existed.r#static
&& match existed.kind {
Some(MethodDefinitionKind::Get) => {
kind.as_ref().map_or(false, |kind| *kind == MethodDefinitionKind::Set)
}
Some(MethodDefinitionKind::Set) => {
kind.as_ref().map_or(false, |kind| *kind == MethodDefinitionKind::Get)
}
_ => false,
})
{
p.error(diagnostics::Redeclaration(
private_ident.name.clone(),
existed.span,
private_ident.span,
));
}
}
}
fn on_declare_private_property(
&mut self,
p: &mut Parser,
private_ident: &PrivateIdentifier,
r#static: bool,
kind: Option<MethodDefinitionKind>,
) {
self.detect_private_name_conflict(p, private_ident, r#static, kind);
self.private_bound_identifiers.insert(
private_ident.name.clone(),
PrivateBoundIdentifierMeta { r#static, kind, span: private_ident.span },
);
}
}
impl<'a> NormalList<'a> for ClassElements<'a> {
fn open(&self) -> Kind {
Kind::LCurly
}
fn close(&self) -> Kind {
Kind::RCurly
}
fn parse_element(&mut self, p: &mut Parser<'a>) -> Result<()> {
// skip empty class element `;`
while p.at(Kind::Semicolon) {
p.bump_any();
}
if p.at(self.close()) {
return Ok(());
}
let element = p.parse_class_element()?;
if let Some(private_ident) = element.private_bound_identifiers() {
self.on_declare_private_property(
p,
&private_ident,
element.r#static(),
element.method_definition_kind(),
);
}
self.elements.push(element);
Ok(())
}
}
pub struct SwitchCases<'a> {
pub elements: Vec<'a, SwitchCase<'a>>,
}
impl<'a> SwitchCases<'a> {
pub fn new(p: &mut Parser<'a>) -> Self {
Self { elements: p.ast.new_vec() }
}
}
impl<'a> NormalList<'a> for SwitchCases<'a> {
fn open(&self) -> Kind {
Kind::LCurly
}
fn close(&self) -> Kind {
Kind::RCurly
}
fn parse_element(&mut self, p: &mut Parser<'a>) -> Result<()> {
let element = p.parse_switch_case()?;
self.elements.push(element);
Ok(())
}
}