use crate::expression::Expression;
use crate::function::PrivateName;
use crate::visitor::{VisitWith, Visitor, VisitorMut};
use crate::{Span, Spanned};
use boa_interner::{Interner, ToInternedString};
use core::ops::ControlFlow;
use super::Identifier;
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
#[derive(Clone, Debug, PartialEq)]
pub enum PropertyAccessField {
Const(Identifier),
Expr(Box<Expression>),
}
impl Spanned for PropertyAccessField {
#[inline]
fn span(&self) -> Span {
match self {
Self::Const(identifier) => identifier.span(),
Self::Expr(expression) => expression.span(),
}
}
}
impl From<Identifier> for PropertyAccessField {
#[inline]
fn from(id: Identifier) -> Self {
Self::Const(id)
}
}
impl From<Expression> for PropertyAccessField {
#[inline]
fn from(expr: Expression) -> Self {
Self::Expr(Box::new(expr))
}
}
impl VisitWith for PropertyAccessField {
fn visit_with<'a, V>(&'a self, visitor: &mut V) -> ControlFlow<V::BreakTy>
where
V: Visitor<'a>,
{
match self {
Self::Const(sym) => visitor.visit_sym(sym.sym_ref()),
Self::Expr(expr) => visitor.visit_expression(expr),
}
}
fn visit_with_mut<'a, V>(&'a mut self, visitor: &mut V) -> ControlFlow<V::BreakTy>
where
V: VisitorMut<'a>,
{
match self {
Self::Const(sym) => visitor.visit_sym_mut(sym.sym_mut()),
Self::Expr(expr) => visitor.visit_expression_mut(&mut *expr),
}
}
}
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
#[derive(Clone, Debug, PartialEq)]
pub enum PropertyAccess {
Simple(SimplePropertyAccess),
Private(PrivatePropertyAccess),
Super(SuperPropertyAccess),
}
impl Spanned for PropertyAccess {
#[inline]
fn span(&self) -> Span {
match self {
Self::Simple(access) => access.span(),
Self::Private(access) => access.span(),
Self::Super(access) => access.span(),
}
}
}
impl ToInternedString for PropertyAccess {
#[inline]
fn to_interned_string(&self, interner: &Interner) -> String {
match self {
Self::Simple(s) => s.to_interned_string(interner),
Self::Private(p) => p.to_interned_string(interner),
Self::Super(s) => s.to_interned_string(interner),
}
}
}
impl From<PropertyAccess> for Expression {
#[inline]
fn from(access: PropertyAccess) -> Self {
Self::PropertyAccess(access)
}
}
impl VisitWith for PropertyAccess {
fn visit_with<'a, V>(&'a self, visitor: &mut V) -> ControlFlow<V::BreakTy>
where
V: Visitor<'a>,
{
match self {
Self::Simple(spa) => visitor.visit_simple_property_access(spa),
Self::Private(ppa) => visitor.visit_private_property_access(ppa),
Self::Super(supa) => visitor.visit_super_property_access(supa),
}
}
fn visit_with_mut<'a, V>(&'a mut self, visitor: &mut V) -> ControlFlow<V::BreakTy>
where
V: VisitorMut<'a>,
{
match self {
Self::Simple(spa) => visitor.visit_simple_property_access_mut(spa),
Self::Private(ppa) => visitor.visit_private_property_access_mut(ppa),
Self::Super(supa) => visitor.visit_super_property_access_mut(supa),
}
}
}
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
#[derive(Clone, Debug, PartialEq)]
pub struct SimplePropertyAccess {
target: Box<Expression>,
field: PropertyAccessField,
}
impl SimplePropertyAccess {
#[inline]
#[must_use]
pub const fn target(&self) -> &Expression {
&self.target
}
#[inline]
#[must_use]
pub const fn field(&self) -> &PropertyAccessField {
&self.field
}
pub fn new<F>(target: Expression, field: F) -> Self
where
F: Into<PropertyAccessField>,
{
Self {
target: target.into(),
field: field.into(),
}
}
}
impl Spanned for SimplePropertyAccess {
#[inline]
fn span(&self) -> Span {
Span::new(self.target.span().start(), self.field.span().end())
}
}
impl ToInternedString for SimplePropertyAccess {
#[inline]
fn to_interned_string(&self, interner: &Interner) -> String {
let target = self.target.to_interned_string(interner);
match self.field {
PropertyAccessField::Const(ident) => {
format!("{target}.{}", interner.resolve_expect(ident.sym()))
}
PropertyAccessField::Expr(ref expr) => {
format!("{target}[{}]", expr.to_interned_string(interner))
}
}
}
}
impl From<SimplePropertyAccess> for PropertyAccess {
#[inline]
fn from(access: SimplePropertyAccess) -> Self {
Self::Simple(access)
}
}
impl VisitWith for SimplePropertyAccess {
fn visit_with<'a, V>(&'a self, visitor: &mut V) -> ControlFlow<V::BreakTy>
where
V: Visitor<'a>,
{
visitor.visit_expression(&self.target)?;
visitor.visit_property_access_field(&self.field)
}
fn visit_with_mut<'a, V>(&'a mut self, visitor: &mut V) -> ControlFlow<V::BreakTy>
where
V: VisitorMut<'a>,
{
visitor.visit_expression_mut(&mut self.target)?;
visitor.visit_property_access_field_mut(&mut self.field)
}
}
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
#[derive(Clone, Debug, PartialEq)]
pub struct PrivatePropertyAccess {
target: Box<Expression>,
field: PrivateName,
span: Span,
}
impl PrivatePropertyAccess {
#[inline]
#[must_use]
pub fn new(value: Expression, field: PrivateName, span: Span) -> Self {
Self {
target: value.into(),
field,
span,
}
}
#[inline]
#[must_use]
pub const fn target(&self) -> &Expression {
&self.target
}
#[inline]
#[must_use]
pub const fn field(&self) -> PrivateName {
self.field
}
}
impl Spanned for PrivatePropertyAccess {
#[inline]
fn span(&self) -> Span {
self.span
}
}
impl ToInternedString for PrivatePropertyAccess {
#[inline]
fn to_interned_string(&self, interner: &Interner) -> String {
format!(
"{}.#{}",
self.target.to_interned_string(interner),
interner.resolve_expect(self.field.description())
)
}
}
impl From<PrivatePropertyAccess> for PropertyAccess {
#[inline]
fn from(access: PrivatePropertyAccess) -> Self {
Self::Private(access)
}
}
impl VisitWith for PrivatePropertyAccess {
fn visit_with<'a, V>(&'a self, visitor: &mut V) -> ControlFlow<V::BreakTy>
where
V: Visitor<'a>,
{
visitor.visit_expression(&self.target)?;
visitor.visit_private_name(&self.field)
}
fn visit_with_mut<'a, V>(&'a mut self, visitor: &mut V) -> ControlFlow<V::BreakTy>
where
V: VisitorMut<'a>,
{
visitor.visit_expression_mut(&mut self.target)?;
visitor.visit_private_name_mut(&mut self.field)
}
}
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
#[derive(Clone, Debug, PartialEq)]
pub struct SuperPropertyAccess {
field: PropertyAccessField,
span: Span,
}
impl SuperPropertyAccess {
#[must_use]
pub const fn new(field: PropertyAccessField, span: Span) -> Self {
Self { field, span }
}
#[inline]
#[must_use]
pub const fn field(&self) -> &PropertyAccessField {
&self.field
}
}
impl Spanned for SuperPropertyAccess {
#[inline]
fn span(&self) -> Span {
self.span
}
}
impl ToInternedString for SuperPropertyAccess {
#[inline]
fn to_interned_string(&self, interner: &Interner) -> String {
match &self.field {
PropertyAccessField::Const(field) => {
format!("super.{}", interner.resolve_expect(field.sym()))
}
PropertyAccessField::Expr(field) => {
format!("super[{}]", field.to_interned_string(interner))
}
}
}
}
impl From<SuperPropertyAccess> for PropertyAccess {
#[inline]
fn from(access: SuperPropertyAccess) -> Self {
Self::Super(access)
}
}
impl VisitWith for SuperPropertyAccess {
fn visit_with<'a, V>(&'a self, visitor: &mut V) -> ControlFlow<V::BreakTy>
where
V: Visitor<'a>,
{
visitor.visit_property_access_field(&self.field)
}
fn visit_with_mut<'a, V>(&'a mut self, visitor: &mut V) -> ControlFlow<V::BreakTy>
where
V: VisitorMut<'a>,
{
visitor.visit_property_access_field_mut(&mut self.field)
}
}