1mod block;
11mod r#if;
12mod labelled;
13mod r#return;
14mod switch;
15mod throw;
16mod r#try;
17mod with;
18
19pub mod iteration;
20
21pub use self::{
22 block::Block,
23 r#if::If,
24 iteration::{Break, Continue, DoWhileLoop, ForInLoop, ForLoop, ForOfLoop, WhileLoop},
25 labelled::{Labelled, LabelledItem},
26 r#return::Return,
27 switch::{Case, Switch},
28 throw::Throw,
29 r#try::{Catch, ErrorHandler, Finally, Try},
30 with::With,
31};
32use core::ops::ControlFlow;
33
34use crate::visitor::{VisitWith, Visitor, VisitorMut};
35use boa_interner::{Interner, ToIndentedString, ToInternedString};
36
37use super::{declaration::VarDeclaration, expression::Expression};
38
39#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
43#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
44#[derive(Clone, Debug, PartialEq)]
45pub enum Statement {
46 Block(Block),
48
49 Var(VarDeclaration),
51
52 Empty,
63
64 Expression(Expression),
66
67 If(If),
69
70 DoWhileLoop(DoWhileLoop),
72
73 WhileLoop(WhileLoop),
75
76 ForLoop(ForLoop),
78
79 ForInLoop(ForInLoop),
81
82 ForOfLoop(ForOfLoop),
84
85 Switch(Switch),
87
88 Continue(Continue),
90
91 Break(Break),
93
94 Return(Return),
96
97 Labelled(Labelled),
99
100 Throw(Throw),
102
103 Try(Try),
105
106 With(With),
108
109 Debugger,
120}
121
122impl Statement {
123 pub(super) fn to_no_indent_string(&self, interner: &Interner, indentation: usize) -> String {
128 let mut s = match self {
129 Self::Block(block) => return block.to_indented_string(interner, indentation),
130 Self::Var(var) => var.to_interned_string(interner),
131 Self::Empty => return ";".to_owned(),
132 Self::Expression(expr) => expr.to_indented_string(interner, indentation),
133 Self::If(if_smt) => return if_smt.to_indented_string(interner, indentation),
134 Self::DoWhileLoop(do_while) => do_while.to_indented_string(interner, indentation),
135 Self::WhileLoop(while_loop) => {
136 return while_loop.to_indented_string(interner, indentation);
137 }
138 Self::ForLoop(for_loop) => return for_loop.to_indented_string(interner, indentation),
139 Self::ForInLoop(for_in) => return for_in.to_indented_string(interner, indentation),
140 Self::ForOfLoop(for_of) => return for_of.to_indented_string(interner, indentation),
141 Self::Switch(switch) => return switch.to_indented_string(interner, indentation),
142 Self::Continue(cont) => cont.to_interned_string(interner),
143 Self::Break(break_smt) => break_smt.to_interned_string(interner),
144 Self::Return(ret) => ret.to_interned_string(interner),
145 Self::Labelled(labelled) => return labelled.to_interned_string(interner),
146 Self::Throw(throw) => throw.to_interned_string(interner),
147 Self::Try(try_catch) => return try_catch.to_indented_string(interner, indentation),
148 Self::With(with) => return with.to_interned_string(interner),
149 Self::Debugger => "debugger".to_owned(),
150 };
151 s.push(';');
152 s
153 }
154
155 #[inline]
168 #[must_use]
169 pub fn is_labelled_function(&self) -> bool {
170 match self {
171 Self::Labelled(stmt) => match stmt.item() {
172 LabelledItem::FunctionDeclaration(_) => true,
173 LabelledItem::Statement(stmt) => stmt.is_labelled_function(),
174 },
175 _ => false,
176 }
177 }
178}
179
180impl ToIndentedString for Statement {
181 fn to_indented_string(&self, interner: &Interner, indentation: usize) -> String {
192 let mut buf = match *self {
193 Self::Block(_) => String::new(),
194 _ => " ".repeat(indentation),
195 };
196
197 buf.push_str(&self.to_no_indent_string(interner, indentation));
198
199 buf
200 }
201}
202
203impl VisitWith for Statement {
204 fn visit_with<'a, V>(&'a self, visitor: &mut V) -> ControlFlow<V::BreakTy>
205 where
206 V: Visitor<'a>,
207 {
208 match self {
209 Self::Block(b) => visitor.visit_block(b),
210 Self::Var(v) => visitor.visit_var_declaration(v),
211 Self::Empty | Self::Debugger => {
212 ControlFlow::Continue(())
214 }
215 Self::Expression(e) => visitor.visit_expression(e),
216 Self::If(i) => visitor.visit_if(i),
217 Self::DoWhileLoop(dw) => visitor.visit_do_while_loop(dw),
218 Self::WhileLoop(w) => visitor.visit_while_loop(w),
219 Self::ForLoop(f) => visitor.visit_for_loop(f),
220 Self::ForInLoop(fi) => visitor.visit_for_in_loop(fi),
221 Self::ForOfLoop(fo) => visitor.visit_for_of_loop(fo),
222 Self::Switch(s) => visitor.visit_switch(s),
223 Self::Continue(c) => visitor.visit_continue(c),
224 Self::Break(b) => visitor.visit_break(b),
225 Self::Return(r) => visitor.visit_return(r),
226 Self::Labelled(l) => visitor.visit_labelled(l),
227 Self::Throw(th) => visitor.visit_throw(th),
228 Self::Try(tr) => visitor.visit_try(tr),
229 Self::With(with) => visitor.visit_with(with),
230 }
231 }
232
233 fn visit_with_mut<'a, V>(&'a mut self, visitor: &mut V) -> ControlFlow<V::BreakTy>
234 where
235 V: VisitorMut<'a>,
236 {
237 match self {
238 Self::Block(b) => visitor.visit_block_mut(b),
239 Self::Var(v) => visitor.visit_var_declaration_mut(v),
240 Self::Empty | Self::Debugger => {
241 ControlFlow::Continue(())
243 }
244 Self::Expression(e) => visitor.visit_expression_mut(e),
245 Self::If(i) => visitor.visit_if_mut(i),
246 Self::DoWhileLoop(dw) => visitor.visit_do_while_loop_mut(dw),
247 Self::WhileLoop(w) => visitor.visit_while_loop_mut(w),
248 Self::ForLoop(f) => visitor.visit_for_loop_mut(f),
249 Self::ForInLoop(fi) => visitor.visit_for_in_loop_mut(fi),
250 Self::ForOfLoop(fo) => visitor.visit_for_of_loop_mut(fo),
251 Self::Switch(s) => visitor.visit_switch_mut(s),
252 Self::Continue(c) => visitor.visit_continue_mut(c),
253 Self::Break(b) => visitor.visit_break_mut(b),
254 Self::Return(r) => visitor.visit_return_mut(r),
255 Self::Labelled(l) => visitor.visit_labelled_mut(l),
256 Self::Throw(th) => visitor.visit_throw_mut(th),
257 Self::Try(tr) => visitor.visit_try_mut(tr),
258 Self::With(with) => visitor.visit_with_mut(with),
259 }
260 }
261}