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