boa_ast/expression/literal/
array.rs1use crate::expression::Expression;
4use crate::expression::operator::assign::{AssignOp, AssignTarget};
5use crate::pattern::{ArrayPattern, ArrayPatternElement, Pattern};
6use crate::visitor::{VisitWith, Visitor, VisitorMut};
7use crate::{Span, Spanned};
8use boa_interner::{Interner, Sym, ToInternedString};
9use core::ops::ControlFlow;
10
11#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
28#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
29#[derive(Clone, Debug, PartialEq)]
30pub struct ArrayLiteral {
31 arr: Box<[Option<Expression>]>,
32 has_trailing_comma_spread: bool,
33 span: Span,
34}
35
36impl ArrayLiteral {
37 pub fn new<A>(array: A, has_trailing_comma_spread: bool, span: Span) -> Self
39 where
40 A: Into<Box<[Option<Expression>]>>,
41 {
42 Self {
43 arr: array.into(),
44 has_trailing_comma_spread,
45 span,
46 }
47 }
48
49 #[must_use]
52 pub const fn has_trailing_comma_spread(&self) -> bool {
53 self.has_trailing_comma_spread
54 }
55
56 #[must_use]
58 pub fn to_pattern(&self, strict: bool) -> Option<ArrayPattern> {
59 if self.has_trailing_comma_spread() {
60 return None;
61 }
62
63 let mut bindings = Vec::new();
64 for (i, expr) in self.arr.iter().enumerate() {
65 let Some(expr) = expr else {
66 bindings.push(ArrayPatternElement::Elision);
67 continue;
68 };
69 match expr {
70 Expression::Identifier(ident) => {
71 if strict && *ident == Sym::ARGUMENTS {
72 return None;
73 }
74
75 bindings.push(ArrayPatternElement::SingleName {
76 ident: *ident,
77 default_init: None,
78 });
79 }
80 Expression::Spread(spread) => {
81 match spread.target() {
82 Expression::Identifier(ident) => {
83 bindings.push(ArrayPatternElement::SingleNameRest { ident: *ident });
84 }
85 Expression::PropertyAccess(access) => {
86 bindings.push(ArrayPatternElement::PropertyAccessRest {
87 access: access.clone(),
88 });
89 }
90 Expression::ArrayLiteral(array) => {
91 let pattern = array.to_pattern(strict)?.into();
92 bindings.push(ArrayPatternElement::PatternRest { pattern });
93 }
94 Expression::ObjectLiteral(object) => {
95 let pattern = object.to_pattern(strict)?.into();
96 bindings.push(ArrayPatternElement::PatternRest { pattern });
97 }
98 _ => return None,
99 }
100 if i + 1 != self.arr.len() {
101 return None;
102 }
103 }
104 Expression::Assign(assign) => {
105 if assign.op() != AssignOp::Assign {
106 return None;
107 }
108 match assign.lhs() {
109 AssignTarget::Identifier(ident) => {
110 let mut init = assign.rhs().clone();
111 init.set_anonymous_function_definition_name(ident);
112 bindings.push(ArrayPatternElement::SingleName {
113 ident: *ident,
114 default_init: Some(init),
115 });
116 }
117 AssignTarget::Access(access) => {
118 bindings.push(ArrayPatternElement::PropertyAccess {
119 access: access.clone(),
120 default_init: Some(assign.rhs().clone()),
121 });
122 }
123 AssignTarget::Pattern(pattern) => match pattern {
124 Pattern::Object(pattern) => {
125 bindings.push(ArrayPatternElement::Pattern {
126 pattern: Pattern::Object(pattern.clone()),
127 default_init: Some(assign.rhs().clone()),
128 });
129 }
130 Pattern::Array(pattern) => {
131 bindings.push(ArrayPatternElement::Pattern {
132 pattern: Pattern::Array(pattern.clone()),
133 default_init: Some(assign.rhs().clone()),
134 });
135 }
136 },
137 }
138 }
139 Expression::ArrayLiteral(array) => {
140 let pattern = array.to_pattern(strict)?.into();
141 bindings.push(ArrayPatternElement::Pattern {
142 pattern,
143 default_init: None,
144 });
145 }
146 Expression::ObjectLiteral(object) => {
147 let pattern = object.to_pattern(strict)?.into();
148 bindings.push(ArrayPatternElement::Pattern {
149 pattern,
150 default_init: None,
151 });
152 }
153 Expression::PropertyAccess(access) => {
154 bindings.push(ArrayPatternElement::PropertyAccess {
155 access: access.clone(),
156 default_init: None,
157 });
158 }
159 _ => return None,
160 }
161 }
162 Some(ArrayPattern::new(bindings.into(), self.span))
163 }
164}
165
166impl Spanned for ArrayLiteral {
167 #[inline]
168 fn span(&self) -> Span {
169 self.span
170 }
171}
172
173impl AsRef<[Option<Expression>]> for ArrayLiteral {
174 #[inline]
175 fn as_ref(&self) -> &[Option<Expression>] {
176 &self.arr
177 }
178}
179
180impl AsMut<[Option<Expression>]> for ArrayLiteral {
181 #[inline]
182 fn as_mut(&mut self) -> &mut [Option<Expression>] {
183 &mut self.arr
184 }
185}
186
187impl ToInternedString for ArrayLiteral {
188 #[inline]
189 fn to_interned_string(&self, interner: &Interner) -> String {
190 let mut buf = String::from("[");
191 let mut elements = self.arr.iter().peekable();
192
193 while let Some(element) = elements.next() {
194 if let Some(e) = element {
195 buf.push_str(&e.to_interned_string(interner));
196 if elements.peek().is_some() {
197 buf.push_str(", ");
198 }
199 } else if elements.peek().is_some() {
200 buf.push_str(", ");
201 } else {
202 buf.push(',');
203 }
204 }
205 buf.push(']');
206 buf
207 }
208}
209
210impl From<ArrayLiteral> for Expression {
211 #[inline]
212 fn from(arr: ArrayLiteral) -> Self {
213 Self::ArrayLiteral(arr)
214 }
215}
216
217impl VisitWith for ArrayLiteral {
218 fn visit_with<'a, V>(&'a self, visitor: &mut V) -> ControlFlow<V::BreakTy>
219 where
220 V: Visitor<'a>,
221 {
222 for expr in self.arr.iter().flatten() {
223 visitor.visit_expression(expr)?;
224 }
225 ControlFlow::Continue(())
226 }
227
228 fn visit_with_mut<'a, V>(&'a mut self, visitor: &mut V) -> ControlFlow<V::BreakTy>
229 where
230 V: VisitorMut<'a>,
231 {
232 for expr in self.arr.iter_mut().flatten() {
233 visitor.visit_expression_mut(expr)?;
234 }
235 ControlFlow::Continue(())
236 }
237}