boa_ast/statement/iteration/
for_of_loop.rs1use crate::operations::{ContainsSymbol, contains};
2use crate::scope::Scope;
3use crate::visitor::{VisitWith, Visitor, VisitorMut};
4use crate::{
5 expression::Expression,
6 statement::{Statement, iteration::IterableLoopInitializer},
7};
8use boa_interner::{Interner, ToIndentedString, ToInternedString};
9use core::ops::ControlFlow;
10
11#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
24#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
25#[derive(Clone, Debug, PartialEq)]
26pub struct ForOfLoop {
27 pub(crate) init: IterableLoopInitializer,
28 pub(crate) iterable: Expression,
29 pub(crate) body: Box<Statement>,
30 r#await: bool,
31 pub(crate) iterable_contains_direct_eval: bool,
32 pub(crate) contains_direct_eval: bool,
33
34 #[cfg_attr(feature = "serde", serde(skip))]
35 pub(crate) iterable_scope: Option<Scope>,
36
37 #[cfg_attr(feature = "serde", serde(skip))]
38 pub(crate) scope: Option<Scope>,
39}
40
41impl ForOfLoop {
42 #[inline]
44 #[must_use]
45 pub fn new(
46 init: IterableLoopInitializer,
47 iterable: Expression,
48 body: Statement,
49 r#await: bool,
50 ) -> Self {
51 let iterable_contains_direct_eval = contains(&iterable, ContainsSymbol::DirectEval);
52 let contains_direct_eval = contains(&init, ContainsSymbol::DirectEval)
53 || contains(&body, ContainsSymbol::DirectEval);
54 Self {
55 init,
56 iterable,
57 body: body.into(),
58 iterable_contains_direct_eval,
59 contains_direct_eval,
60 r#await,
61 iterable_scope: None,
62 scope: None,
63 }
64 }
65
66 #[inline]
68 #[must_use]
69 pub const fn initializer(&self) -> &IterableLoopInitializer {
70 &self.init
71 }
72
73 #[inline]
75 #[must_use]
76 pub const fn iterable(&self) -> &Expression {
77 &self.iterable
78 }
79
80 #[inline]
82 #[must_use]
83 pub const fn body(&self) -> &Statement {
84 &self.body
85 }
86
87 #[inline]
89 #[must_use]
90 pub const fn r#await(&self) -> bool {
91 self.r#await
92 }
93
94 #[inline]
96 #[must_use]
97 pub const fn iterable_scope(&self) -> Option<&Scope> {
98 self.iterable_scope.as_ref()
99 }
100
101 #[inline]
103 #[must_use]
104 pub const fn scope(&self) -> Option<&Scope> {
105 self.scope.as_ref()
106 }
107}
108
109impl ToIndentedString for ForOfLoop {
110 fn to_indented_string(&self, interner: &Interner, indentation: usize) -> String {
111 format!(
112 "for ({} of {}) {}",
113 self.init.to_interned_string(interner),
114 self.iterable.to_interned_string(interner),
115 self.body().to_indented_string(interner, indentation)
116 )
117 }
118}
119
120impl From<ForOfLoop> for Statement {
121 #[inline]
122 fn from(for_of: ForOfLoop) -> Self {
123 Self::ForOfLoop(for_of)
124 }
125}
126
127impl VisitWith for ForOfLoop {
128 fn visit_with<'a, V>(&'a self, visitor: &mut V) -> ControlFlow<V::BreakTy>
129 where
130 V: Visitor<'a>,
131 {
132 visitor.visit_iterable_loop_initializer(&self.init)?;
133 visitor.visit_expression(&self.iterable)?;
134 visitor.visit_statement(&self.body)
135 }
136
137 fn visit_with_mut<'a, V>(&'a mut self, visitor: &mut V) -> ControlFlow<V::BreakTy>
138 where
139 V: VisitorMut<'a>,
140 {
141 visitor.visit_iterable_loop_initializer_mut(&mut self.init)?;
142 visitor.visit_expression_mut(&mut self.iterable)?;
143 visitor.visit_statement_mut(&mut self.body)
144 }
145}