boa_ast/expression/operator/assign/
mod.rs1#![allow(clippy::doc_link_with_quotes)]
2
3mod op;
16
17use core::ops::ControlFlow;
18pub use op::*;
19
20use boa_interner::{Interner, Sym, ToInternedString};
21
22use crate::{
23 Span, Spanned,
24 expression::{Expression, access::PropertyAccess, identifier::Identifier},
25 pattern::Pattern,
26 visitor::{VisitWith, Visitor, VisitorMut},
27};
28
29#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
33#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
34#[derive(Clone, Debug, PartialEq)]
35pub struct Assign {
36 op: AssignOp,
37 lhs: Box<AssignTarget>,
38 rhs: Box<Expression>,
39}
40
41impl Assign {
42 #[inline]
44 #[must_use]
45 pub fn new(op: AssignOp, lhs: AssignTarget, rhs: Expression) -> Self {
46 Self {
47 op,
48 lhs: Box::new(lhs),
49 rhs: Box::new(rhs),
50 }
51 }
52
53 #[inline]
55 #[must_use]
56 pub const fn op(&self) -> AssignOp {
57 self.op
58 }
59
60 #[inline]
62 #[must_use]
63 pub const fn lhs(&self) -> &AssignTarget {
64 &self.lhs
65 }
66
67 #[inline]
69 #[must_use]
70 pub const fn rhs(&self) -> &Expression {
71 &self.rhs
72 }
73}
74
75impl Spanned for Assign {
76 #[inline]
77 fn span(&self) -> Span {
78 Span::new(self.lhs.span().start(), self.rhs.span().end())
79 }
80}
81
82impl ToInternedString for Assign {
83 #[inline]
84 fn to_interned_string(&self, interner: &Interner) -> String {
85 format!(
86 "{} {} {}",
87 self.lhs.to_interned_string(interner),
88 self.op,
89 self.rhs.to_interned_string(interner)
90 )
91 }
92}
93
94impl From<Assign> for Expression {
95 #[inline]
96 fn from(op: Assign) -> Self {
97 Self::Assign(op)
98 }
99}
100
101impl VisitWith for Assign {
102 fn visit_with<'a, V>(&'a self, visitor: &mut V) -> ControlFlow<V::BreakTy>
103 where
104 V: Visitor<'a>,
105 {
106 visitor.visit_assign_target(&self.lhs)?;
107 visitor.visit_expression(&self.rhs)
108 }
109
110 fn visit_with_mut<'a, V>(&'a mut self, visitor: &mut V) -> ControlFlow<V::BreakTy>
111 where
112 V: VisitorMut<'a>,
113 {
114 visitor.visit_assign_target_mut(&mut self.lhs)?;
115 visitor.visit_expression_mut(&mut self.rhs)
116 }
117}
118
119#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
124#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
125#[derive(Clone, Debug, PartialEq)]
126pub enum AssignTarget {
127 Identifier(Identifier),
129 Access(PropertyAccess),
131 Pattern(Pattern),
133}
134
135impl AssignTarget {
136 #[must_use]
139 pub fn from_expression(expression: &Expression, strict: bool) -> Option<Self> {
140 match expression {
141 Expression::ObjectLiteral(object) => {
142 let pattern = object.to_pattern(strict)?;
143 Some(Self::Pattern(pattern.into()))
144 }
145 Expression::ArrayLiteral(array) => {
146 let pattern = array.to_pattern(strict)?;
147 Some(Self::Pattern(pattern.into()))
148 }
149 e => Self::from_expression_simple(e, strict),
150 }
151 }
152
153 #[must_use]
158 pub fn from_expression_simple(expression: &Expression, strict: bool) -> Option<Self> {
159 match expression {
160 Expression::Identifier(id)
161 if strict && (id.sym() == Sym::EVAL || id.sym() == Sym::ARGUMENTS) =>
162 {
163 None
164 }
165 Expression::Identifier(id) => Some(Self::Identifier(*id)),
166 Expression::PropertyAccess(access) => Some(Self::Access(access.clone())),
167 Expression::Parenthesized(p) => Self::from_expression_simple(p.expression(), strict),
168 _ => None,
169 }
170 }
171}
172
173impl Spanned for AssignTarget {
174 #[inline]
175 fn span(&self) -> Span {
176 match self {
177 AssignTarget::Identifier(identifier) => identifier.span(),
178 AssignTarget::Access(property_access) => property_access.span(),
179 AssignTarget::Pattern(pattern) => pattern.span(),
180 }
181 }
182}
183
184impl ToInternedString for AssignTarget {
185 #[inline]
186 fn to_interned_string(&self, interner: &Interner) -> String {
187 match self {
188 Self::Identifier(id) => id.to_interned_string(interner),
189 Self::Access(access) => access.to_interned_string(interner),
190 Self::Pattern(pattern) => pattern.to_interned_string(interner),
191 }
192 }
193}
194
195impl From<Identifier> for AssignTarget {
196 #[inline]
197 fn from(target: Identifier) -> Self {
198 Self::Identifier(target)
199 }
200}
201
202impl VisitWith for AssignTarget {
203 fn visit_with<'a, V>(&'a self, visitor: &mut V) -> ControlFlow<V::BreakTy>
204 where
205 V: Visitor<'a>,
206 {
207 match self {
208 Self::Identifier(id) => visitor.visit_identifier(id),
209 Self::Access(pa) => visitor.visit_property_access(pa),
210 Self::Pattern(pat) => visitor.visit_pattern(pat),
211 }
212 }
213
214 fn visit_with_mut<'a, V>(&'a mut self, visitor: &mut V) -> ControlFlow<V::BreakTy>
215 where
216 V: VisitorMut<'a>,
217 {
218 match self {
219 Self::Identifier(id) => visitor.visit_identifier_mut(id),
220 Self::Access(pa) => visitor.visit_property_access_mut(pa),
221 Self::Pattern(pat) => visitor.visit_pattern_mut(pat),
222 }
223 }
224}