use oxc_allocator::Vec;
use oxc_ast::{ast::*, syntax_directed_operations::PrivateBoundIdentifiers};
use oxc_diagnostics::{
miette::{self, Diagnostic},
thiserror::{self, Error},
Result,
};
use oxc_span::{Atom, GetSpan, Span};
use rustc_hash::FxHashMap;
use crate::{
diagnostics,
lexer::Kind,
list::{NormalList, SeparatedList},
Parser,
};
#[derive(Debug, Error, Diagnostic)]
#[error("Identifier `{0}` has already been declared")]
#[diagnostic()]
struct Redeclaration(
pub Atom,
#[label("`{0}` has already been declared here")] pub Span,
#[label("It can not be redeclared here")] pub Span,
);
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: &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(ObjectPropertyKind::SpreadProperty),
_ => p.parse_property_definition().map(ObjectPropertyKind::ObjectProperty),
}?;
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(())
}
}
pub struct ObjectPatternProperties<'a> {
pub elements: Vec<'a, BindingProperty<'a>>,
pub rest: Option<oxc_allocator::Box<'a, RestElement<'a>>>,
}
impl<'a> SeparatedList<'a> for ObjectPatternProperties<'a> {
fn new(p: &Parser<'a>) -> Self {
Self { elements: p.ast.new_vec(), rest: None }
}
fn open(&self) -> Kind {
Kind::LCurly
}
fn close(&self) -> Kind {
Kind::RCurly
}
fn parse_element(&mut self, p: &mut Parser<'a>) -> Result<()> {
if p.cur_kind() == Kind::Dot3 {
let rest = p.parse_rest_element()?;
if !matches!(&rest.argument.kind, BindingPatternKind::BindingIdentifier(_)) {
p.error(diagnostics::InvalidRestElement(rest.argument.span()));
}
if let Some(r) = self.rest.replace(rest) {
p.error(diagnostics::RestElementLast(r.span));
}
} else {
let prop = p.parse_binding_property()?;
self.elements.push(prop);
}
Ok(())
}
}
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: &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(p.parse_elision()),
Kind::Dot3 => p.parse_spread_element().map(ArrayExpressionElement::SpreadElement),
_ => p.parse_assignment_expression_base().map(ArrayExpressionElement::Expression),
};
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(())
}
}
pub struct ArrayPatternList<'a> {
pub elements: Vec<'a, Option<BindingPattern<'a>>>,
pub rest: Option<oxc_allocator::Box<'a, RestElement<'a>>>,
}
impl<'a> SeparatedList<'a> for ArrayPatternList<'a> {
fn new(p: &Parser<'a>) -> Self {
Self { elements: p.ast.new_vec(), rest: None }
}
fn open(&self) -> Kind {
Kind::LBrack
}
fn close(&self) -> Kind {
Kind::RBrack
}
fn parse_element(&mut self, p: &mut Parser<'a>) -> Result<()> {
match p.cur_kind() {
Kind::Comma => {
self.elements.push(None);
}
Kind::Dot3 => {
let rest = p.parse_rest_element()?;
if let Some(r) = self.rest.replace(rest) {
p.error(diagnostics::RestElementLast(r.span));
}
}
_ => {
let element = p.parse_binding_pattern()?;
self.elements.push(Some(element));
}
}
Ok(())
}
}
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 elements: Vec<'a, Expression<'a>>,
}
impl<'a> SeparatedList<'a> for SequenceExpressionList<'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
}
fn parse_element(&mut self, p: &mut Parser<'a>) -> Result<()> {
let element = p.parse_assignment_expression_base()?;
self.elements.push(element);
Ok(())
}
}
pub struct FormalParameterList<'a> {
pub elements: Vec<'a, FormalParameter<'a>>,
pub rest: Option<oxc_allocator::Box<'a, RestElement<'a>>>,
}
impl<'a> SeparatedList<'a> for FormalParameterList<'a> {
fn new(p: &Parser<'a>) -> Self {
Self { elements: p.ast.new_vec(), rest: None }
}
fn open(&self) -> Kind {
Kind::LParen
}
fn close(&self) -> Kind {
Kind::RParen
}
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();
match p.cur_kind() {
Kind::This if p.ts_enabled() => {
let formal_parameter = p.parse_ts_this_parameter()?;
self.elements.push(formal_parameter);
}
Kind::Dot3 => {
let rest = p.parse_rest_element()?;
if let Some(r) = self.rest.replace(rest) {
p.error(diagnostics::RestParameterLast(r.span));
}
}
_ => {
let pattern = p.parse_binding_pattern()?;
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(())
}
}
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(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();
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 PrivateBoundIdentifierMeta {
span: Span,
r#static: bool,
kind: Option<MethodDefinitionKind>,
}
pub struct ClassElements<'a> {
pub elements: Vec<'a, ClassElement<'a>>,
pub private_bound_identifiers: FxHashMap<Atom, PrivateBoundIdentifierMeta>,
}
impl<'a> ClassElements<'a> {
pub(crate) 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(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<()> {
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(crate) 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(())
}
}
pub struct ImportSpecifierList<'a> {
pub import_specifiers: Vec<'a, ImportDeclarationSpecifier>,
}
impl<'a> SeparatedList<'a> for ImportSpecifierList<'a> {
fn new(p: &Parser<'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 Parser<'a>) -> Result<()> {
let import_specifier = p.parse_import_specifier()?;
let specifier = ImportDeclarationSpecifier::ImportSpecifier(import_specifier);
self.import_specifiers.push(specifier);
Ok(())
}
}