boa_ast/statement/iteration/
mod.rs

1//! Iteration nodes
2
3mod r#break;
4mod r#continue;
5mod do_while_loop;
6mod for_in_loop;
7mod for_loop;
8mod for_of_loop;
9mod while_loop;
10
11use crate::{
12    declaration::{Binding, Variable},
13    expression::{Identifier, access::PropertyAccess},
14    pattern::Pattern,
15};
16use core::ops::ControlFlow;
17
18pub use self::{
19    r#break::Break,
20    r#continue::Continue,
21    do_while_loop::DoWhileLoop,
22    for_in_loop::ForInLoop,
23    for_loop::{ForLoop, ForLoopInitializer, ForLoopInitializerLexical},
24    for_of_loop::ForOfLoop,
25    while_loop::WhileLoop,
26};
27use crate::visitor::{VisitWith, Visitor, VisitorMut};
28use boa_interner::{Interner, ToInternedString};
29
30/// A `for-in`, `for-of` and `for-await-of` loop initializer.
31///
32/// The [spec] specifies only single bindings for the listed types of loops, which makes us
33/// unable to use plain `LexicalDeclaration`s or `VarStatement`s as initializers, since those
34/// can have more than one binding.
35///
36/// [spec]: https://tc39.es/ecma262/#prod-ForInOfStatement
37#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
38#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
39#[derive(Clone, Debug, PartialEq)]
40pub enum IterableLoopInitializer {
41    /// An already declared variable.
42    Identifier(Identifier),
43    /// A property access.
44    Access(PropertyAccess),
45    /// A new var declaration.
46    Var(Variable),
47    /// A new let declaration.
48    Let(Binding),
49    /// A new const declaration.
50    Const(Binding),
51    /// A pattern with already declared variables.
52    Pattern(Pattern),
53}
54
55impl ToInternedString for IterableLoopInitializer {
56    fn to_interned_string(&self, interner: &Interner) -> String {
57        let (binding, pre) = match self {
58            Self::Identifier(ident) => return ident.to_interned_string(interner),
59            Self::Pattern(pattern) => return pattern.to_interned_string(interner),
60            Self::Access(access) => return access.to_interned_string(interner),
61            Self::Var(binding) => (binding.to_interned_string(interner), "var"),
62            Self::Let(binding) => (binding.to_interned_string(interner), "let"),
63            Self::Const(binding) => (binding.to_interned_string(interner), "const"),
64        };
65
66        format!("{pre} {binding}")
67    }
68}
69
70impl VisitWith for IterableLoopInitializer {
71    fn visit_with<'a, V>(&'a self, visitor: &mut V) -> ControlFlow<V::BreakTy>
72    where
73        V: Visitor<'a>,
74    {
75        match self {
76            Self::Identifier(id) => visitor.visit_identifier(id),
77            Self::Access(pa) => visitor.visit_property_access(pa),
78            Self::Var(b) => visitor.visit_variable(b),
79            Self::Let(b) | Self::Const(b) => visitor.visit_binding(b),
80            Self::Pattern(p) => visitor.visit_pattern(p),
81        }
82    }
83
84    fn visit_with_mut<'a, V>(&'a mut self, visitor: &mut V) -> ControlFlow<V::BreakTy>
85    where
86        V: VisitorMut<'a>,
87    {
88        match self {
89            Self::Identifier(id) => visitor.visit_identifier_mut(id),
90            Self::Access(pa) => visitor.visit_property_access_mut(pa),
91            Self::Var(b) => visitor.visit_variable_mut(b),
92            Self::Let(b) | Self::Const(b) => visitor.visit_binding_mut(b),
93            Self::Pattern(p) => visitor.visit_pattern_mut(p),
94        }
95    }
96}