1use is_macro::Is;
2use swc_common::{ast_node, util::take::Take, EqIgnoreSpan, Span, SyntaxContext, DUMMY_SP};
3
4use crate::{
5 decl::{Decl, VarDecl},
6 expr::Expr,
7 pat::Pat,
8 Ident, Lit, Str, UsingDecl,
9};
10
11#[ast_node("BlockStatement")]
13#[derive(Eq, Hash, EqIgnoreSpan, Default)]
14#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
15#[cfg_attr(feature = "shrink-to-fit", derive(shrink_to_fit::ShrinkToFit))]
16pub struct BlockStmt {
17 pub span: Span,
19
20 pub ctxt: SyntaxContext,
21
22 pub stmts: Vec<Stmt>,
23}
24
25impl Take for BlockStmt {
26 fn dummy() -> Self {
27 BlockStmt {
28 span: DUMMY_SP,
29 stmts: Vec::new(),
30 ctxt: Default::default(),
31 }
32 }
33}
34
35#[ast_node(no_clone)]
36#[derive(Eq, Hash, Is, EqIgnoreSpan)]
37#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
38#[cfg_attr(feature = "shrink-to-fit", derive(shrink_to_fit::ShrinkToFit))]
39pub enum Stmt {
40 #[tag("BlockStatement")]
41 Block(BlockStmt),
42
43 #[tag("EmptyStatement")]
44 Empty(EmptyStmt),
45
46 #[tag("DebuggerStatement")]
47 Debugger(DebuggerStmt),
48
49 #[tag("WithStatement")]
50 With(WithStmt),
51
52 #[tag("ReturnStatement")]
53 #[is(name = "return_stmt")]
54 Return(ReturnStmt),
55
56 #[tag("LabeledStatement")]
57 Labeled(LabeledStmt),
58
59 #[tag("BreakStatement")]
60 #[is(name = "break_stmt")]
61 Break(BreakStmt),
62
63 #[tag("ContinueStatement")]
64 #[is(name = "continue_stmt")]
65 Continue(ContinueStmt),
66
67 #[tag("IfStatement")]
68 #[is(name = "if_stmt")]
69 If(IfStmt),
70
71 #[tag("SwitchStatement")]
72 Switch(SwitchStmt),
73
74 #[tag("ThrowStatement")]
75 Throw(ThrowStmt),
76
77 #[tag("TryStatement")]
79 #[is(name = "try_stmt")]
80 Try(Box<TryStmt>),
81
82 #[tag("WhileStatement")]
83 #[is(name = "while_stmt")]
84 While(WhileStmt),
85
86 #[tag("DoWhileStatement")]
87 DoWhile(DoWhileStmt),
88
89 #[tag("ForStatement")]
90 #[is(name = "for_stmt")]
91 For(ForStmt),
92
93 #[tag("ForInStatement")]
94 ForIn(ForInStmt),
95
96 #[tag("ForOfStatement")]
97 ForOf(ForOfStmt),
98
99 #[tag("ClassDeclaration")]
100 #[tag("FunctionDeclaration")]
101 #[tag("VariableDeclaration")]
102 #[tag("TsInterfaceDeclaration")]
103 #[tag("TsTypeAliasDeclaration")]
104 #[tag("TsEnumDeclaration")]
105 #[tag("TsModuleDeclaration")]
106 #[tag("UsingDeclaration")]
107 Decl(Decl),
108
109 #[tag("ExpressionStatement")]
110 Expr(ExprStmt),
111}
112
113boxed!(Stmt, [TryStmt]);
114
115macro_rules! stmt_from {
116 ($($varant_ty:ty),*) => {
117 $(
118 bridge_from!(Box<crate::Stmt>, crate::Stmt, $varant_ty);
119 bridge_from!(crate::ModuleItem, crate::Stmt, $varant_ty);
120 )*
121 };
122}
123
124stmt_from!(
125 ExprStmt,
126 BlockStmt,
127 EmptyStmt,
128 DebuggerStmt,
129 WithStmt,
130 ReturnStmt,
131 LabeledStmt,
132 BreakStmt,
133 ContinueStmt,
134 IfStmt,
135 SwitchStmt,
136 ThrowStmt,
137 TryStmt,
138 WhileStmt,
139 DoWhileStmt,
140 ForStmt,
141 ForInStmt,
142 ForOfStmt,
143 Decl
144);
145
146impl Stmt {
147 pub fn is_use_strict(&self) -> bool {
148 match self {
149 Stmt::Expr(expr) => match *expr.expr {
150 Expr::Lit(Lit::Str(Str { ref raw, .. })) => {
151 matches!(raw, Some(value) if value == "\"use strict\"" || value == "'use strict'")
152 }
153 _ => false,
154 },
155 _ => false,
156 }
157 }
158
159 pub fn can_precede_directive(&self) -> bool {
162 match self {
163 Stmt::Expr(expr) => matches!(*expr.expr, Expr::Lit(Lit::Str(_))),
164 _ => false,
165 }
166 }
167}
168
169impl Clone for Stmt {
176 fn clone(&self) -> Self {
177 use Stmt::*;
178 match self {
179 #[cfg(all(swc_ast_unknown, feature = "encoding-impl"))]
180 Unknown(tag, v) => Unknown(*tag, v.clone()),
181 Block(s) => Block(s.clone()),
182 Empty(s) => Empty(s.clone()),
183 Debugger(s) => Debugger(s.clone()),
184 With(s) => With(s.clone()),
185 Return(s) => Return(s.clone()),
186 Labeled(s) => Labeled(s.clone()),
187 Break(s) => Break(s.clone()),
188 Continue(s) => Continue(s.clone()),
189 If(s) => If(s.clone()),
190 Switch(s) => Switch(s.clone()),
191 Throw(s) => Throw(s.clone()),
192 Try(s) => Try(s.clone()),
193 While(s) => While(s.clone()),
194 DoWhile(s) => DoWhile(s.clone()),
195 For(s) => For(s.clone()),
196 ForIn(s) => ForIn(s.clone()),
197 ForOf(s) => ForOf(s.clone()),
198 Decl(s) => Decl(s.clone()),
199 Expr(s) => Expr(s.clone()),
200 }
201 }
202}
203
204impl Default for Stmt {
205 fn default() -> Self {
206 Self::Empty(EmptyStmt { span: DUMMY_SP })
207 }
208}
209
210impl Take for Stmt {
211 fn dummy() -> Self {
212 Default::default()
213 }
214}
215
216#[ast_node("ExpressionStatement")]
217#[derive(Eq, Hash, EqIgnoreSpan, Default)]
218#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
219#[cfg_attr(feature = "shrink-to-fit", derive(shrink_to_fit::ShrinkToFit))]
220pub struct ExprStmt {
221 pub span: Span,
222 #[cfg_attr(feature = "serde-impl", serde(rename = "expression"))]
223 pub expr: Box<Expr>,
224}
225
226#[ast_node("EmptyStatement")]
227#[derive(Eq, Hash, Copy, EqIgnoreSpan)]
228#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
229#[cfg_attr(feature = "shrink-to-fit", derive(shrink_to_fit::ShrinkToFit))]
230pub struct EmptyStmt {
231 pub span: Span,
233}
234
235#[ast_node("DebuggerStatement")]
236#[derive(Eq, Hash, Copy, EqIgnoreSpan)]
237#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
238#[cfg_attr(feature = "shrink-to-fit", derive(shrink_to_fit::ShrinkToFit))]
239pub struct DebuggerStmt {
240 pub span: Span,
241}
242
243#[ast_node("WithStatement")]
244#[derive(Eq, Hash, EqIgnoreSpan, Default)]
245#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
246#[cfg_attr(feature = "shrink-to-fit", derive(shrink_to_fit::ShrinkToFit))]
247pub struct WithStmt {
248 pub span: Span,
249 #[cfg_attr(feature = "serde-impl", serde(rename = "object"))]
250 pub obj: Box<Expr>,
251 pub body: Box<Stmt>,
252}
253
254#[ast_node("ReturnStatement")]
255#[derive(Eq, Hash, EqIgnoreSpan, Default)]
256#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
257#[cfg_attr(feature = "shrink-to-fit", derive(shrink_to_fit::ShrinkToFit))]
258pub struct ReturnStmt {
259 pub span: Span,
260 #[cfg_attr(feature = "serde-impl", serde(default, rename = "argument"))]
261 #[cfg_attr(
262 feature = "encoding-impl",
263 encoding(with = "cbor4ii::core::types::Maybe")
264 )]
265 pub arg: Option<Box<Expr>>,
266}
267
268#[ast_node("LabeledStatement")]
269#[derive(Eq, Hash, EqIgnoreSpan, Default)]
270#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
271#[cfg_attr(feature = "shrink-to-fit", derive(shrink_to_fit::ShrinkToFit))]
272pub struct LabeledStmt {
273 pub span: Span,
274 pub label: Ident,
275 pub body: Box<Stmt>,
276}
277
278#[ast_node("BreakStatement")]
279#[derive(Eq, Hash, EqIgnoreSpan, Default)]
280#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
281#[cfg_attr(feature = "shrink-to-fit", derive(shrink_to_fit::ShrinkToFit))]
282pub struct BreakStmt {
283 pub span: Span,
284 #[cfg_attr(feature = "serde-impl", serde(default))]
285 #[cfg_attr(
286 feature = "encoding-impl",
287 encoding(with = "cbor4ii::core::types::Maybe")
288 )]
289 pub label: Option<Ident>,
290}
291
292#[ast_node("ContinueStatement")]
293#[derive(Eq, Hash, EqIgnoreSpan, Default)]
294#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
295#[cfg_attr(feature = "shrink-to-fit", derive(shrink_to_fit::ShrinkToFit))]
296pub struct ContinueStmt {
297 pub span: Span,
298 #[cfg_attr(feature = "serde-impl", serde(default))]
299 #[cfg_attr(
300 feature = "encoding-impl",
301 encoding(with = "cbor4ii::core::types::Maybe")
302 )]
303 pub label: Option<Ident>,
304}
305
306#[ast_node("IfStatement")]
307#[derive(Eq, Hash, EqIgnoreSpan, Default)]
308#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
309#[cfg_attr(feature = "shrink-to-fit", derive(shrink_to_fit::ShrinkToFit))]
310pub struct IfStmt {
311 pub span: Span,
312 pub test: Box<Expr>,
313
314 #[cfg_attr(feature = "serde-impl", serde(rename = "consequent"))]
315 pub cons: Box<Stmt>,
316
317 #[cfg_attr(feature = "serde-impl", serde(default, rename = "alternate"))]
318 #[cfg_attr(
319 feature = "encoding-impl",
320 encoding(with = "cbor4ii::core::types::Maybe")
321 )]
322 pub alt: Option<Box<Stmt>>,
323}
324
325#[ast_node("SwitchStatement")]
326#[derive(Eq, Hash, EqIgnoreSpan, Default)]
327#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
328#[cfg_attr(feature = "shrink-to-fit", derive(shrink_to_fit::ShrinkToFit))]
329pub struct SwitchStmt {
330 pub span: Span,
331 pub discriminant: Box<Expr>,
332 pub cases: Vec<SwitchCase>,
333}
334
335#[ast_node("ThrowStatement")]
336#[derive(Eq, Hash, EqIgnoreSpan, Default)]
337#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
338#[cfg_attr(feature = "shrink-to-fit", derive(shrink_to_fit::ShrinkToFit))]
339pub struct ThrowStmt {
340 pub span: Span,
341 #[cfg_attr(feature = "serde-impl", serde(rename = "argument"))]
342 pub arg: Box<Expr>,
343}
344
345#[ast_node("TryStatement")]
346#[derive(Eq, Hash, EqIgnoreSpan, Default)]
347#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
348#[cfg_attr(feature = "shrink-to-fit", derive(shrink_to_fit::ShrinkToFit))]
349pub struct TryStmt {
350 pub span: Span,
351
352 pub block: BlockStmt,
353
354 #[cfg_attr(feature = "serde-impl", serde(default))]
355 #[cfg_attr(
356 feature = "encoding-impl",
357 encoding(with = "cbor4ii::core::types::Maybe")
358 )]
359 pub handler: Option<CatchClause>,
360
361 #[cfg_attr(feature = "serde-impl", serde(default))]
362 #[cfg_attr(
363 feature = "encoding-impl",
364 encoding(with = "cbor4ii::core::types::Maybe")
365 )]
366 pub finalizer: Option<BlockStmt>,
367}
368
369#[ast_node("WhileStatement")]
370#[derive(Eq, Hash, EqIgnoreSpan, Default)]
371#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
372#[cfg_attr(feature = "shrink-to-fit", derive(shrink_to_fit::ShrinkToFit))]
373pub struct WhileStmt {
374 pub span: Span,
375 pub test: Box<Expr>,
376 pub body: Box<Stmt>,
377}
378
379#[ast_node("DoWhileStatement")]
380#[derive(Eq, Hash, EqIgnoreSpan, Default)]
381#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
382#[cfg_attr(feature = "shrink-to-fit", derive(shrink_to_fit::ShrinkToFit))]
383pub struct DoWhileStmt {
384 pub span: Span,
385 pub test: Box<Expr>,
386 pub body: Box<Stmt>,
387}
388
389#[ast_node("ForStatement")]
390#[derive(Eq, Hash, EqIgnoreSpan, Default)]
391#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
392#[cfg_attr(feature = "shrink-to-fit", derive(shrink_to_fit::ShrinkToFit))]
393pub struct ForStmt {
394 pub span: Span,
395
396 #[cfg_attr(feature = "serde-impl", serde(default))]
397 #[cfg_attr(
398 feature = "encoding-impl",
399 encoding(with = "cbor4ii::core::types::Maybe")
400 )]
401 pub init: Option<VarDeclOrExpr>,
402
403 #[cfg_attr(feature = "serde-impl", serde(default))]
404 #[cfg_attr(
405 feature = "encoding-impl",
406 encoding(with = "cbor4ii::core::types::Maybe")
407 )]
408 pub test: Option<Box<Expr>>,
409
410 #[cfg_attr(feature = "serde-impl", serde(default))]
411 #[cfg_attr(
412 feature = "encoding-impl",
413 encoding(with = "cbor4ii::core::types::Maybe")
414 )]
415 pub update: Option<Box<Expr>>,
416
417 pub body: Box<Stmt>,
418}
419
420#[ast_node("ForInStatement")]
421#[derive(Eq, Hash, EqIgnoreSpan, Default)]
422#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
423#[cfg_attr(feature = "shrink-to-fit", derive(shrink_to_fit::ShrinkToFit))]
424pub struct ForInStmt {
425 pub span: Span,
426 pub left: ForHead,
427 pub right: Box<Expr>,
428 pub body: Box<Stmt>,
429}
430
431#[ast_node("ForOfStatement")]
432#[derive(Eq, Hash, EqIgnoreSpan, Default)]
433#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
434#[cfg_attr(feature = "shrink-to-fit", derive(shrink_to_fit::ShrinkToFit))]
435pub struct ForOfStmt {
436 pub span: Span,
437 #[cfg_attr(feature = "serde-impl", serde(default, rename = "await"))]
443 pub is_await: bool,
444 pub left: ForHead,
445 pub right: Box<Expr>,
446 pub body: Box<Stmt>,
447}
448
449impl Take for ForOfStmt {
450 fn dummy() -> Self {
451 Default::default()
452 }
453}
454
455#[ast_node("SwitchCase")]
456#[derive(Eq, Hash, EqIgnoreSpan, Default)]
457#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
458#[cfg_attr(feature = "shrink-to-fit", derive(shrink_to_fit::ShrinkToFit))]
459pub struct SwitchCase {
460 pub span: Span,
461
462 #[cfg_attr(feature = "serde-impl", serde(default))]
464 #[cfg_attr(
465 feature = "encoding-impl",
466 encoding(with = "cbor4ii::core::types::Maybe")
467 )]
468 pub test: Option<Box<Expr>>,
469
470 #[cfg_attr(feature = "serde-impl", serde(rename = "consequent"))]
471 pub cons: Vec<Stmt>,
472}
473
474impl Take for SwitchCase {
475 fn dummy() -> Self {
476 Self {
477 span: DUMMY_SP,
478 test: None,
479 cons: Vec::new(),
480 }
481 }
482}
483
484#[ast_node("CatchClause")]
485#[derive(Eq, Hash, EqIgnoreSpan, Default)]
486#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
487#[cfg_attr(feature = "shrink-to-fit", derive(shrink_to_fit::ShrinkToFit))]
488pub struct CatchClause {
489 pub span: Span,
490 #[cfg_attr(feature = "serde-impl", serde(default))]
495 #[cfg_attr(
496 feature = "encoding-impl",
497 encoding(with = "cbor4ii::core::types::Maybe")
498 )]
499 pub param: Option<Pat>,
500
501 pub body: BlockStmt,
502}
503
504#[ast_node]
506#[derive(Eq, Hash, Is, EqIgnoreSpan)]
507#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
508#[cfg_attr(feature = "shrink-to-fit", derive(shrink_to_fit::ShrinkToFit))]
509pub enum ForHead {
510 #[tag("VariableDeclaration")]
511 VarDecl(Box<VarDecl>),
512
513 #[tag("UsingDeclaration")]
514 UsingDecl(Box<UsingDecl>),
515
516 #[tag("*")]
517 Pat(Box<Pat>),
518}
519
520bridge_from!(ForHead, Box<VarDecl>, VarDecl);
521bridge_from!(ForHead, Box<Pat>, Pat);
522
523impl Take for ForHead {
524 fn dummy() -> Self {
525 Default::default()
526 }
527}
528
529impl Default for ForHead {
530 fn default() -> Self {
531 ForHead::Pat(Take::dummy())
532 }
533}
534
535#[ast_node]
536#[derive(Eq, Hash, Is, EqIgnoreSpan)]
537#[allow(variant_size_differences)]
538#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
539#[cfg_attr(feature = "shrink-to-fit", derive(shrink_to_fit::ShrinkToFit))]
540pub enum VarDeclOrExpr {
541 #[tag("VariableDeclaration")]
542 VarDecl(Box<VarDecl>),
543
544 #[tag("*")]
545 Expr(Box<Expr>),
546}
547
548bridge_from!(VarDeclOrExpr, Box<VarDecl>, VarDecl);
549bridge_from!(VarDeclOrExpr, Box<Expr>, Expr);
550
551impl Take for VarDeclOrExpr {
552 fn dummy() -> Self {
553 VarDeclOrExpr::Expr(Take::dummy())
554 }
555}