boa_ast/statement/iteration/
for_in_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))]
19#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
20#[derive(Clone, Debug, PartialEq)]
21pub struct ForInLoop {
22 pub(crate) initializer: IterableLoopInitializer,
23 pub(crate) target: Expression,
24 pub(crate) body: Box<Statement>,
25 pub(crate) target_contains_direct_eval: bool,
26 pub(crate) contains_direct_eval: bool,
27
28 #[cfg_attr(feature = "serde", serde(skip))]
29 pub(crate) target_scope: Option<Scope>,
30
31 #[cfg_attr(feature = "serde", serde(skip))]
32 pub(crate) scope: Option<Scope>,
33}
34
35impl ForInLoop {
36 #[inline]
38 #[must_use]
39 pub fn new(initializer: IterableLoopInitializer, target: Expression, body: Statement) -> Self {
40 let target_contains_direct_eval = contains(&target, ContainsSymbol::DirectEval);
41 let contains_direct_eval = contains(&initializer, ContainsSymbol::DirectEval)
42 || contains(&body, ContainsSymbol::DirectEval);
43 Self {
44 initializer,
45 target,
46 body: body.into(),
47 target_contains_direct_eval,
48 contains_direct_eval,
49 target_scope: None,
50 scope: None,
51 }
52 }
53
54 #[inline]
56 #[must_use]
57 pub const fn initializer(&self) -> &IterableLoopInitializer {
58 &self.initializer
59 }
60
61 #[inline]
63 #[must_use]
64 pub const fn target(&self) -> &Expression {
65 &self.target
66 }
67
68 #[inline]
70 #[must_use]
71 pub const fn body(&self) -> &Statement {
72 &self.body
73 }
74
75 #[inline]
77 #[must_use]
78 pub const fn target_scope(&self) -> Option<&Scope> {
79 self.target_scope.as_ref()
80 }
81
82 #[inline]
84 #[must_use]
85 pub const fn scope(&self) -> Option<&Scope> {
86 self.scope.as_ref()
87 }
88}
89
90impl ToIndentedString for ForInLoop {
91 fn to_indented_string(&self, interner: &Interner, indentation: usize) -> String {
92 let mut buf = format!(
93 "for ({} in {}) ",
94 self.initializer.to_interned_string(interner),
95 self.target.to_interned_string(interner)
96 );
97 buf.push_str(&self.body().to_indented_string(interner, indentation));
98
99 buf
100 }
101}
102
103impl From<ForInLoop> for Statement {
104 #[inline]
105 fn from(for_in: ForInLoop) -> Self {
106 Self::ForInLoop(for_in)
107 }
108}
109
110impl VisitWith for ForInLoop {
111 fn visit_with<'a, V>(&'a self, visitor: &mut V) -> ControlFlow<V::BreakTy>
112 where
113 V: Visitor<'a>,
114 {
115 visitor.visit_iterable_loop_initializer(&self.initializer)?;
116 visitor.visit_expression(&self.target)?;
117 visitor.visit_statement(&self.body)
118 }
119
120 fn visit_with_mut<'a, V>(&'a mut self, visitor: &mut V) -> ControlFlow<V::BreakTy>
121 where
122 V: VisitorMut<'a>,
123 {
124 visitor.visit_iterable_loop_initializer_mut(&mut self.initializer)?;
125 visitor.visit_expression_mut(&mut self.target)?;
126 visitor.visit_statement_mut(&mut self.body)
127 }
128}