1use crate::class::Class;
4use crate::declaration::VariableDeclaration;
5use crate::expression::Expression;
6use crate::function::Function;
7use crate::identifier::Identifier;
8use crate::pattern::Pattern;
9use crate::span::Spanned;
10
11pub type Statement = Spanned<StatementKind>;
13
14#[derive(Debug, Clone, PartialEq, Eq)]
16pub enum StatementKind {
17 Block {
19 body: Vec<Statement>,
21 },
22 Empty,
24 Debugger,
26 Expression {
28 expression: Expression,
30 },
31 If {
33 test: Expression,
35 consequent: Box<Statement>,
37 alternate: Option<Box<Statement>>,
39 },
40 Switch {
42 discriminant: Expression,
44 cases: Vec<SwitchCase>,
46 },
47 For {
49 init: Option<ForInit>,
51 test: Option<Expression>,
53 update: Option<Expression>,
55 body: Box<Statement>,
57 },
58 ForIn {
60 left: ForLeft,
62 right: Expression,
64 body: Box<Statement>,
66 },
67 ForOf {
69 left: ForLeft,
71 right: Expression,
73 body: Box<Statement>,
75 is_await: bool,
77 },
78 While {
80 test: Expression,
82 body: Box<Statement>,
84 },
85 DoWhile {
87 body: Box<Statement>,
89 test: Expression,
91 },
92 Return {
94 argument: Option<Expression>,
96 },
97 Throw {
99 argument: Expression,
101 },
102 Try {
104 block: Vec<Statement>,
106 handler: Option<CatchClause>,
108 finalizer: Option<Vec<Statement>>,
110 },
111 Break {
113 label: Option<Identifier>,
115 },
116 Continue {
118 label: Option<Identifier>,
120 },
121 Labeled {
123 label: Identifier,
125 body: Box<Statement>,
127 },
128 VariableDeclaration(VariableDeclaration),
130 FunctionDeclaration(Function),
132 ClassDeclaration(Class),
134}
135
136#[derive(Debug, Clone, PartialEq, Eq)]
138pub struct SwitchCase {
139 test: Option<Expression>,
140 consequent: Vec<Statement>,
141}
142
143impl SwitchCase {
144 #[must_use]
146 pub fn new(test: Option<Expression>, consequent: Vec<Statement>) -> Self {
147 Self { test, consequent }
148 }
149
150 #[must_use]
152 pub fn test(&self) -> Option<&Expression> {
153 self.test.as_ref()
154 }
155
156 #[must_use]
158 pub fn consequent(&self) -> &[Statement] {
159 &self.consequent
160 }
161}
162
163#[derive(Debug, Clone, PartialEq, Eq)]
165pub struct CatchClause {
166 param: Option<Pattern>,
167 body: Vec<Statement>,
168}
169
170impl CatchClause {
171 #[must_use]
174 pub fn new(param: Option<Pattern>, body: Vec<Statement>) -> Self {
175 Self { param, body }
176 }
177
178 #[must_use]
180 pub fn param(&self) -> Option<&Pattern> {
181 self.param.as_ref()
182 }
183
184 #[must_use]
186 pub fn body(&self) -> &[Statement] {
187 &self.body
188 }
189}
190
191#[derive(Debug, Clone, PartialEq, Eq)]
193pub enum ForInit {
194 Declaration(VariableDeclaration),
196 Expression(Expression),
198}
199
200#[derive(Debug, Clone, PartialEq, Eq)]
202pub enum ForLeft {
203 Declaration(VariableDeclaration),
205 Pattern(Pattern),
207}
208
209impl std::fmt::Display for StatementKind {
210 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
211 match self {
212 Self::Block { body } => write_block(f, body),
213 Self::Empty => f.write_str(";"),
214 Self::Debugger => f.write_str("debugger;"),
215 Self::Expression { expression } => write!(f, "{expression};"),
216 Self::If {
217 test,
218 consequent,
219 alternate,
220 } => write_if(f, test, consequent, alternate.as_deref()),
221 Self::Switch {
222 discriminant,
223 cases,
224 } => write_switch(f, discriminant, cases),
225 Self::For {
226 init,
227 test,
228 update,
229 body,
230 } => write_for(f, init.as_ref(), test.as_ref(), update.as_ref(), body),
231 Self::ForIn { left, right, body } => write!(f, "for ({left} in {right}) {body}"),
232 Self::ForOf {
233 left,
234 right,
235 body,
236 is_await,
237 } => write_for_of(f, left, right, body, *is_await),
238 Self::While { test, body } => write!(f, "while ({test}) {body}"),
239 Self::DoWhile { body, test } => write!(f, "do {body} while ({test});"),
240 Self::Return { argument } => write_return(f, argument.as_ref()),
241 Self::Throw { argument } => write!(f, "throw {argument};"),
242 Self::Try {
243 block,
244 handler,
245 finalizer,
246 } => write_try(f, block, handler.as_ref(), finalizer.as_ref()),
247 Self::Break { label } => write_break_continue(f, "break", label.as_ref()),
248 Self::Continue { label } => write_break_continue(f, "continue", label.as_ref()),
249 Self::Labeled { label, body } => write!(f, "{label}: {body}"),
250 Self::VariableDeclaration(decl) => write!(f, "{decl};"),
251 Self::FunctionDeclaration(func) => write!(f, "{func}"),
252 Self::ClassDeclaration(class) => write!(f, "{class}"),
253 }
254 }
255}
256
257fn write_block(f: &mut std::fmt::Formatter<'_>, body: &[Statement]) -> std::fmt::Result {
258 let lines = body
259 .iter()
260 .map(|s| format!(" {s}"))
261 .collect::<Vec<_>>()
262 .join("\n");
263 if body.is_empty() {
264 f.write_str("{}")
265 } else {
266 write!(f, "{{\n{lines}\n}}")
267 }
268}
269
270fn write_if(
271 f: &mut std::fmt::Formatter<'_>,
272 test: &Expression,
273 consequent: &Statement,
274 alternate: Option<&Statement>,
275) -> std::fmt::Result {
276 write!(f, "if ({test}) {consequent}")?;
277 match alternate {
278 Some(alt) => write!(f, " else {alt}"),
279 None => Ok(()),
280 }
281}
282
283fn write_switch(
284 f: &mut std::fmt::Formatter<'_>,
285 discriminant: &Expression,
286 cases: &[SwitchCase],
287) -> std::fmt::Result {
288 write!(f, "switch ({discriminant}) {{ ")?;
289 let body = cases
290 .iter()
291 .map(|c| match c.test() {
292 Some(t) => format!("case {t}: ..."),
293 None => "default: ...".to_owned(),
294 })
295 .collect::<Vec<_>>()
296 .join(" ");
297 write!(f, "{body} }}")
298}
299
300fn write_for(
301 f: &mut std::fmt::Formatter<'_>,
302 init: Option<&ForInit>,
303 test: Option<&Expression>,
304 update: Option<&Expression>,
305 body: &Statement,
306) -> std::fmt::Result {
307 let init_str = init.map_or(String::new(), |i| format!("{i}"));
308 let test_str = test.map_or(String::new(), |t| format!("{t}"));
309 let update_str = update.map_or(String::new(), |u| format!("{u}"));
310 write!(f, "for ({init_str}; {test_str}; {update_str}) {body}")
311}
312
313fn write_for_of(
314 f: &mut std::fmt::Formatter<'_>,
315 left: &ForLeft,
316 right: &Expression,
317 body: &Statement,
318 is_await: bool,
319) -> std::fmt::Result {
320 let keyword = if is_await { "for await" } else { "for" };
321 write!(f, "{keyword} ({left} of {right}) {body}")
322}
323
324fn write_return(
325 f: &mut std::fmt::Formatter<'_>,
326 argument: Option<&Expression>,
327) -> std::fmt::Result {
328 match argument {
329 Some(arg) => write!(f, "return {arg};"),
330 None => f.write_str("return;"),
331 }
332}
333
334fn write_try(
335 f: &mut std::fmt::Formatter<'_>,
336 block: &[Statement],
337 handler: Option<&CatchClause>,
338 finalizer: Option<&Vec<Statement>>,
339) -> std::fmt::Result {
340 write!(f, "try {{ {} stmts }}", block.len())?;
341 if let Some(h) = handler {
342 match h.param() {
343 Some(p) => write!(f, " catch ({p}) {{ ... }}")?,
344 None => write!(f, " catch {{ ... }}")?,
345 }
346 }
347 if let Some(fin) = finalizer {
348 write!(f, " finally {{ {} stmts }}", fin.len())?;
349 }
350 Ok(())
351}
352
353fn write_break_continue(
354 f: &mut std::fmt::Formatter<'_>,
355 keyword: &str,
356 label: Option<&Identifier>,
357) -> std::fmt::Result {
358 match label {
359 Some(l) => write!(f, "{keyword} {l};"),
360 None => write!(f, "{keyword};"),
361 }
362}
363
364impl std::fmt::Display for ForInit {
365 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
366 match self {
367 Self::Declaration(decl) => write!(f, "{decl}"),
368 Self::Expression(expr) => write!(f, "{expr}"),
369 }
370 }
371}
372
373impl std::fmt::Display for ForLeft {
374 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
375 match self {
376 Self::Declaration(decl) => write!(f, "{decl}"),
377 Self::Pattern(pat) => write!(f, "{pat}"),
378 }
379 }
380}