boa/syntax/ast/node/iteration/for_loop/
mod.rs1use crate::{
2 environment::declarative_environment_record::DeclarativeEnvironmentRecord,
3 exec::{Executable, InterpreterState},
4 gc::{Finalize, Trace},
5 syntax::ast::node::Node,
6 BoaProfiler, Context, JsResult, JsValue,
7};
8use std::fmt;
9
10#[cfg(feature = "deser")]
11use serde::{Deserialize, Serialize};
12
13#[cfg_attr(feature = "deser", derive(Serialize, Deserialize))]
25#[derive(Clone, Debug, Trace, Finalize, PartialEq)]
26pub struct ForLoop {
27 #[cfg_attr(feature = "deser", serde(flatten))]
28 inner: Box<InnerForLoop>,
29 label: Option<Box<str>>,
30}
31
32impl ForLoop {
33 pub(in crate::syntax) fn new<I, C, E, B>(init: I, condition: C, final_expr: E, body: B) -> Self
35 where
36 I: Into<Option<Node>>,
37 C: Into<Option<Node>>,
38 E: Into<Option<Node>>,
39 B: Into<Node>,
40 {
41 Self {
42 inner: Box::new(InnerForLoop::new(init, condition, final_expr, body)),
43 label: None,
44 }
45 }
46
47 pub fn init(&self) -> Option<&Node> {
49 self.inner.init()
50 }
51
52 pub fn condition(&self) -> Option<&Node> {
54 self.inner.condition()
55 }
56
57 pub fn final_expr(&self) -> Option<&Node> {
59 self.inner.final_expr()
60 }
61
62 pub fn body(&self) -> &Node {
64 self.inner.body()
65 }
66
67 pub(in crate::syntax::ast::node) fn display(
68 &self,
69 f: &mut fmt::Formatter<'_>,
70 indentation: usize,
71 ) -> fmt::Result {
72 if let Some(ref label) = self.label {
73 write!(f, "{}: ", label)?;
74 }
75 f.write_str("for (")?;
76 if let Some(init) = self.init() {
77 fmt::Display::fmt(init, f)?;
78 }
79 f.write_str("; ")?;
80 if let Some(condition) = self.condition() {
81 fmt::Display::fmt(condition, f)?;
82 }
83 f.write_str("; ")?;
84 if let Some(final_expr) = self.final_expr() {
85 fmt::Display::fmt(final_expr, f)?;
86 }
87 write!(f, ") ")?;
88 self.inner.body().display(f, indentation)
89 }
90
91 pub fn label(&self) -> Option<&str> {
92 self.label.as_ref().map(Box::as_ref)
93 }
94
95 pub fn set_label(&mut self, label: Box<str>) {
96 self.label = Some(label);
97 }
98}
99
100impl Executable for ForLoop {
101 fn run(&self, context: &mut Context) -> JsResult<JsValue> {
102 let _timer = BoaProfiler::global().start_event("ForLoop", "exec");
104 {
105 let env = context.get_current_environment();
106 context.push_environment(DeclarativeEnvironmentRecord::new(Some(env)));
107 }
108
109 if let Some(init) = self.init() {
110 init.run(context)?;
111 }
112
113 while self
114 .condition()
115 .map(|cond| cond.run(context).map(|v| v.to_boolean()))
116 .transpose()?
117 .unwrap_or(true)
118 {
119 let result = self.body().run(context)?;
120
121 match context.executor().get_current_state() {
122 InterpreterState::Break(label) => {
123 handle_state_with_labels!(self, label, context, break);
124 break;
125 }
126 InterpreterState::Continue(label) => {
127 handle_state_with_labels!(self, label, context, continue);
128 }
129
130 InterpreterState::Return => {
131 return Ok(result);
132 }
133 InterpreterState::Executing => {
134 }
136 }
137
138 if let Some(final_expr) = self.final_expr() {
139 final_expr.run(context)?;
140 }
141 }
142
143 let _ = context.pop_environment();
145
146 Ok(JsValue::undefined())
147 }
148}
149
150impl fmt::Display for ForLoop {
151 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
152 self.display(f, 0)
153 }
154}
155
156impl From<ForLoop> for Node {
157 fn from(for_loop: ForLoop) -> Self {
158 Self::ForLoop(for_loop)
159 }
160}
161
162#[cfg_attr(feature = "deser", derive(Serialize, Deserialize))]
164#[derive(Clone, Debug, Trace, Finalize, PartialEq)]
165struct InnerForLoop {
166 init: Option<Node>,
167 condition: Option<Node>,
168 final_expr: Option<Node>,
169 body: Node,
170}
171
172impl InnerForLoop {
173 fn new<I, C, E, B>(init: I, condition: C, final_expr: E, body: B) -> Self
175 where
176 I: Into<Option<Node>>,
177 C: Into<Option<Node>>,
178 E: Into<Option<Node>>,
179 B: Into<Node>,
180 {
181 Self {
182 init: init.into(),
183 condition: condition.into(),
184 final_expr: final_expr.into(),
185 body: body.into(),
186 }
187 }
188
189 fn init(&self) -> Option<&Node> {
191 self.init.as_ref()
192 }
193
194 fn condition(&self) -> Option<&Node> {
196 self.condition.as_ref()
197 }
198
199 fn final_expr(&self) -> Option<&Node> {
201 self.final_expr.as_ref()
202 }
203
204 fn body(&self) -> &Node {
206 &self.body
207 }
208}