1use super::Declaration;
4use crate::{
5 Statement,
6 expression::{Expression, Identifier},
7 join_nodes,
8 pattern::Pattern,
9 visitor::{VisitWith, Visitor, VisitorMut},
10};
11use boa_interner::{Interner, ToInternedString};
12use core::{convert::TryFrom, fmt::Write as _, ops::ControlFlow};
13
14#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
44#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
45#[derive(Clone, Debug, PartialEq)]
46pub struct VarDeclaration(pub VariableList);
47
48impl From<VarDeclaration> for Statement {
49 fn from(var: VarDeclaration) -> Self {
50 Self::Var(var)
51 }
52}
53
54impl ToInternedString for VarDeclaration {
55 fn to_interned_string(&self, interner: &Interner) -> String {
56 format!("var {}", self.0.to_interned_string(interner))
57 }
58}
59
60impl VisitWith for VarDeclaration {
61 fn visit_with<'a, V>(&'a self, visitor: &mut V) -> ControlFlow<V::BreakTy>
62 where
63 V: Visitor<'a>,
64 {
65 visitor.visit_variable_list(&self.0)
66 }
67
68 fn visit_with_mut<'a, V>(&'a mut self, visitor: &mut V) -> ControlFlow<V::BreakTy>
69 where
70 V: VisitorMut<'a>,
71 {
72 visitor.visit_variable_list_mut(&mut self.0)
73 }
74}
75
76#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
81#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
82#[derive(Clone, Debug, PartialEq)]
83pub enum LexicalDeclaration {
84 Const(VariableList),
92
93 Let(VariableList),
104
105 Using(VariableList),
110
111 AwaitUsing(VariableList),
116}
117
118impl LexicalDeclaration {
119 #[must_use]
121 pub const fn variable_list(&self) -> &VariableList {
122 match self {
123 Self::Const(list) | Self::Let(list) | Self::Using(list) | Self::AwaitUsing(list) => {
124 list
125 }
126 }
127 }
128
129 #[must_use]
131 pub const fn is_const(&self) -> bool {
132 matches!(self, Self::Const(_))
133 }
134}
135
136impl From<LexicalDeclaration> for Declaration {
137 fn from(lex: LexicalDeclaration) -> Self {
138 Self::Lexical(lex)
139 }
140}
141
142impl ToInternedString for LexicalDeclaration {
143 fn to_interned_string(&self, interner: &Interner) -> String {
144 format!(
145 "{} {}",
146 match &self {
147 Self::Let(_) => "let",
148 Self::Const(_) => "const",
149 Self::Using(_) => "using",
150 Self::AwaitUsing(_) => "await using",
151 },
152 self.variable_list().to_interned_string(interner)
153 )
154 }
155}
156
157impl VisitWith for LexicalDeclaration {
158 fn visit_with<'a, V>(&'a self, visitor: &mut V) -> ControlFlow<V::BreakTy>
159 where
160 V: Visitor<'a>,
161 {
162 match self {
163 Self::Const(vars) | Self::Let(vars) | Self::Using(vars) | Self::AwaitUsing(vars) => {
164 visitor.visit_variable_list(vars)
165 }
166 }
167 }
168
169 fn visit_with_mut<'a, V>(&'a mut self, visitor: &mut V) -> ControlFlow<V::BreakTy>
170 where
171 V: VisitorMut<'a>,
172 {
173 match self {
174 Self::Const(vars) | Self::Let(vars) | Self::Using(vars) | Self::AwaitUsing(vars) => {
175 visitor.visit_variable_list_mut(vars)
176 }
177 }
178 }
179}
180
181#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
183#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
184#[derive(Clone, Debug, PartialEq)]
185pub struct VariableList {
186 list: Box<[Variable]>,
187}
188
189impl VariableList {
190 #[must_use]
192 pub fn new(list: Box<[Variable]>) -> Option<Self> {
193 if list.is_empty() {
194 return None;
195 }
196
197 Some(Self { list })
198 }
199}
200
201impl AsRef<[Variable]> for VariableList {
202 fn as_ref(&self) -> &[Variable] {
203 &self.list
204 }
205}
206
207impl ToInternedString for VariableList {
208 fn to_interned_string(&self, interner: &Interner) -> String {
209 join_nodes(interner, self.list.as_ref())
210 }
211}
212
213impl VisitWith for VariableList {
214 fn visit_with<'a, V>(&'a self, visitor: &mut V) -> ControlFlow<V::BreakTy>
215 where
216 V: Visitor<'a>,
217 {
218 for variable in &*self.list {
219 visitor.visit_variable(variable)?;
220 }
221 ControlFlow::Continue(())
222 }
223
224 fn visit_with_mut<'a, V>(&'a mut self, visitor: &mut V) -> ControlFlow<V::BreakTy>
225 where
226 V: VisitorMut<'a>,
227 {
228 for variable in &mut *self.list {
229 visitor.visit_variable_mut(variable)?;
230 }
231 ControlFlow::Continue(())
232 }
233}
234
235#[derive(Debug, Copy, Clone, PartialEq, Eq)]
237pub struct TryFromVariableListError(());
238
239impl std::fmt::Display for TryFromVariableListError {
240 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
241 "provided list of variables cannot be empty".fmt(f)
242 }
243}
244
245impl TryFrom<Box<[Variable]>> for VariableList {
246 type Error = TryFromVariableListError;
247
248 fn try_from(value: Box<[Variable]>) -> Result<Self, Self::Error> {
249 Self::new(value).ok_or(TryFromVariableListError(()))
250 }
251}
252
253impl TryFrom<Vec<Variable>> for VariableList {
254 type Error = TryFromVariableListError;
255
256 fn try_from(value: Vec<Variable>) -> Result<Self, Self::Error> {
257 Self::try_from(value.into_boxed_slice())
258 }
259}
260
261#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
274#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
275#[derive(Clone, Debug, PartialEq)]
276pub struct Variable {
277 binding: Binding,
278 init: Option<Expression>,
279}
280
281impl ToInternedString for Variable {
282 fn to_interned_string(&self, interner: &Interner) -> String {
283 let mut buf = self.binding.to_interned_string(interner);
284
285 if let Some(ref init) = self.init {
286 let _ = write!(buf, " = {}", init.to_interned_string(interner));
287 }
288 buf
289 }
290}
291
292impl Variable {
293 #[inline]
295 #[must_use]
296 pub const fn from_identifier(ident: Identifier, init: Option<Expression>) -> Self {
297 Self {
298 binding: Binding::Identifier(ident),
299 init,
300 }
301 }
302
303 #[inline]
305 #[must_use]
306 pub const fn from_pattern(pattern: Pattern, init: Option<Expression>) -> Self {
307 Self {
308 binding: Binding::Pattern(pattern),
309 init,
310 }
311 }
312 #[must_use]
314 pub const fn binding(&self) -> &Binding {
315 &self.binding
316 }
317
318 #[inline]
320 #[must_use]
321 pub const fn init(&self) -> Option<&Expression> {
322 self.init.as_ref()
323 }
324}
325
326impl VisitWith for Variable {
327 fn visit_with<'a, V>(&'a self, visitor: &mut V) -> ControlFlow<V::BreakTy>
328 where
329 V: Visitor<'a>,
330 {
331 visitor.visit_binding(&self.binding)?;
332 if let Some(init) = &self.init {
333 visitor.visit_expression(init)?;
334 }
335 ControlFlow::Continue(())
336 }
337
338 fn visit_with_mut<'a, V>(&'a mut self, visitor: &mut V) -> ControlFlow<V::BreakTy>
339 where
340 V: VisitorMut<'a>,
341 {
342 visitor.visit_binding_mut(&mut self.binding)?;
343 if let Some(init) = &mut self.init {
344 visitor.visit_expression_mut(init)?;
345 }
346 ControlFlow::Continue(())
347 }
348}
349
350#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
357#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
358#[derive(Clone, Debug, PartialEq)]
359pub enum Binding {
360 Identifier(Identifier),
362 Pattern(Pattern),
364}
365
366impl From<Identifier> for Binding {
367 fn from(id: Identifier) -> Self {
368 Self::Identifier(id)
369 }
370}
371
372impl From<Pattern> for Binding {
373 fn from(pat: Pattern) -> Self {
374 Self::Pattern(pat)
375 }
376}
377
378impl ToInternedString for Binding {
379 fn to_interned_string(&self, interner: &Interner) -> String {
380 match self {
381 Self::Identifier(id) => id.to_interned_string(interner),
382 Self::Pattern(pattern) => pattern.to_interned_string(interner),
383 }
384 }
385}
386
387impl VisitWith for Binding {
388 fn visit_with<'a, V>(&'a self, visitor: &mut V) -> ControlFlow<V::BreakTy>
389 where
390 V: Visitor<'a>,
391 {
392 match self {
393 Self::Identifier(id) => visitor.visit_identifier(id),
394 Self::Pattern(pattern) => visitor.visit_pattern(pattern),
395 }
396 }
397
398 fn visit_with_mut<'a, V>(&'a mut self, visitor: &mut V) -> ControlFlow<V::BreakTy>
399 where
400 V: VisitorMut<'a>,
401 {
402 match self {
403 Self::Identifier(id) => visitor.visit_identifier_mut(id),
404 Self::Pattern(pattern) => visitor.visit_pattern_mut(pattern),
405 }
406 }
407}