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 Block(s) => Block(s.clone()),
180 Empty(s) => Empty(s.clone()),
181 Debugger(s) => Debugger(s.clone()),
182 With(s) => With(s.clone()),
183 Return(s) => Return(s.clone()),
184 Labeled(s) => Labeled(s.clone()),
185 Break(s) => Break(s.clone()),
186 Continue(s) => Continue(s.clone()),
187 If(s) => If(s.clone()),
188 Switch(s) => Switch(s.clone()),
189 Throw(s) => Throw(s.clone()),
190 Try(s) => Try(s.clone()),
191 While(s) => While(s.clone()),
192 DoWhile(s) => DoWhile(s.clone()),
193 For(s) => For(s.clone()),
194 ForIn(s) => ForIn(s.clone()),
195 ForOf(s) => ForOf(s.clone()),
196 Decl(s) => Decl(s.clone()),
197 Expr(s) => Expr(s.clone()),
198 }
199 }
200}
201
202impl Default for Stmt {
203 fn default() -> Self {
204 Self::Empty(EmptyStmt { span: DUMMY_SP })
205 }
206}
207
208impl Take for Stmt {
209 fn dummy() -> Self {
210 Default::default()
211 }
212}
213
214#[ast_node("ExpressionStatement")]
215#[derive(Eq, Hash, EqIgnoreSpan, Default)]
216#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
217#[cfg_attr(feature = "shrink-to-fit", derive(shrink_to_fit::ShrinkToFit))]
218pub struct ExprStmt {
219 pub span: Span,
220 #[cfg_attr(feature = "serde-impl", serde(rename = "expression"))]
221 pub expr: Box<Expr>,
222}
223
224#[ast_node("EmptyStatement")]
225#[derive(Eq, Hash, Copy, EqIgnoreSpan)]
226#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
227#[cfg_attr(feature = "shrink-to-fit", derive(shrink_to_fit::ShrinkToFit))]
228pub struct EmptyStmt {
229 pub span: Span,
231}
232
233#[ast_node("DebuggerStatement")]
234#[derive(Eq, Hash, Copy, EqIgnoreSpan)]
235#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
236#[cfg_attr(feature = "shrink-to-fit", derive(shrink_to_fit::ShrinkToFit))]
237pub struct DebuggerStmt {
238 pub span: Span,
239}
240
241#[ast_node("WithStatement")]
242#[derive(Eq, Hash, EqIgnoreSpan, Default)]
243#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
244#[cfg_attr(feature = "shrink-to-fit", derive(shrink_to_fit::ShrinkToFit))]
245pub struct WithStmt {
246 pub span: Span,
247 #[cfg_attr(feature = "serde-impl", serde(rename = "object"))]
248 pub obj: Box<Expr>,
249 pub body: Box<Stmt>,
250}
251
252#[ast_node("ReturnStatement")]
253#[derive(Eq, Hash, EqIgnoreSpan, Default)]
254#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
255#[cfg_attr(feature = "shrink-to-fit", derive(shrink_to_fit::ShrinkToFit))]
256pub struct ReturnStmt {
257 pub span: Span,
258 #[cfg_attr(feature = "serde-impl", serde(default, rename = "argument"))]
259 pub arg: Option<Box<Expr>>,
260}
261
262#[ast_node("LabeledStatement")]
263#[derive(Eq, Hash, EqIgnoreSpan, Default)]
264#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
265#[cfg_attr(feature = "shrink-to-fit", derive(shrink_to_fit::ShrinkToFit))]
266pub struct LabeledStmt {
267 pub span: Span,
268 pub label: Ident,
269 pub body: Box<Stmt>,
270}
271
272#[ast_node("BreakStatement")]
273#[derive(Eq, Hash, EqIgnoreSpan, Default)]
274#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
275#[cfg_attr(feature = "shrink-to-fit", derive(shrink_to_fit::ShrinkToFit))]
276pub struct BreakStmt {
277 pub span: Span,
278 #[cfg_attr(feature = "serde-impl", serde(default))]
279 pub label: Option<Ident>,
280}
281
282#[ast_node("ContinueStatement")]
283#[derive(Eq, Hash, EqIgnoreSpan, Default)]
284#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
285#[cfg_attr(feature = "shrink-to-fit", derive(shrink_to_fit::ShrinkToFit))]
286pub struct ContinueStmt {
287 pub span: Span,
288 #[cfg_attr(feature = "serde-impl", serde(default))]
289 pub label: Option<Ident>,
290}
291
292#[ast_node("IfStatement")]
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 IfStmt {
297 pub span: Span,
298 pub test: Box<Expr>,
299
300 #[cfg_attr(feature = "serde-impl", serde(rename = "consequent"))]
301 pub cons: Box<Stmt>,
302
303 #[cfg_attr(feature = "serde-impl", serde(default, rename = "alternate"))]
304 pub alt: Option<Box<Stmt>>,
305}
306
307#[ast_node("SwitchStatement")]
308#[derive(Eq, Hash, EqIgnoreSpan, Default)]
309#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
310#[cfg_attr(feature = "shrink-to-fit", derive(shrink_to_fit::ShrinkToFit))]
311pub struct SwitchStmt {
312 pub span: Span,
313 pub discriminant: Box<Expr>,
314 pub cases: Vec<SwitchCase>,
315}
316
317#[ast_node("ThrowStatement")]
318#[derive(Eq, Hash, EqIgnoreSpan, Default)]
319#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
320#[cfg_attr(feature = "shrink-to-fit", derive(shrink_to_fit::ShrinkToFit))]
321pub struct ThrowStmt {
322 pub span: Span,
323 #[cfg_attr(feature = "serde-impl", serde(rename = "argument"))]
324 pub arg: Box<Expr>,
325}
326
327#[ast_node("TryStatement")]
328#[derive(Eq, Hash, EqIgnoreSpan, Default)]
329#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
330#[cfg_attr(feature = "shrink-to-fit", derive(shrink_to_fit::ShrinkToFit))]
331pub struct TryStmt {
332 pub span: Span,
333
334 pub block: BlockStmt,
335
336 #[cfg_attr(feature = "serde-impl", serde(default))]
337 pub handler: Option<CatchClause>,
338
339 #[cfg_attr(feature = "serde-impl", serde(default))]
340 pub finalizer: Option<BlockStmt>,
341}
342
343#[ast_node("WhileStatement")]
344#[derive(Eq, Hash, EqIgnoreSpan, Default)]
345#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
346#[cfg_attr(feature = "shrink-to-fit", derive(shrink_to_fit::ShrinkToFit))]
347pub struct WhileStmt {
348 pub span: Span,
349 pub test: Box<Expr>,
350 pub body: Box<Stmt>,
351}
352
353#[ast_node("DoWhileStatement")]
354#[derive(Eq, Hash, EqIgnoreSpan, Default)]
355#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
356#[cfg_attr(feature = "shrink-to-fit", derive(shrink_to_fit::ShrinkToFit))]
357pub struct DoWhileStmt {
358 pub span: Span,
359 pub test: Box<Expr>,
360 pub body: Box<Stmt>,
361}
362
363#[ast_node("ForStatement")]
364#[derive(Eq, Hash, EqIgnoreSpan, Default)]
365#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
366#[cfg_attr(feature = "shrink-to-fit", derive(shrink_to_fit::ShrinkToFit))]
367pub struct ForStmt {
368 pub span: Span,
369
370 #[cfg_attr(feature = "serde-impl", serde(default))]
371 pub init: Option<VarDeclOrExpr>,
372
373 #[cfg_attr(feature = "serde-impl", serde(default))]
374 pub test: Option<Box<Expr>>,
375
376 #[cfg_attr(feature = "serde-impl", serde(default))]
377 pub update: Option<Box<Expr>>,
378
379 pub body: Box<Stmt>,
380}
381
382#[ast_node("ForInStatement")]
383#[derive(Eq, Hash, EqIgnoreSpan, Default)]
384#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
385#[cfg_attr(feature = "shrink-to-fit", derive(shrink_to_fit::ShrinkToFit))]
386pub struct ForInStmt {
387 pub span: Span,
388 pub left: ForHead,
389 pub right: Box<Expr>,
390 pub body: Box<Stmt>,
391}
392
393#[ast_node("ForOfStatement")]
394#[derive(Eq, Hash, EqIgnoreSpan, Default)]
395#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
396#[cfg_attr(feature = "shrink-to-fit", derive(shrink_to_fit::ShrinkToFit))]
397pub struct ForOfStmt {
398 pub span: Span,
399 #[cfg_attr(feature = "serde-impl", serde(default, rename = "await"))]
405 pub is_await: bool,
406 pub left: ForHead,
407 pub right: Box<Expr>,
408 pub body: Box<Stmt>,
409}
410
411impl Take for ForOfStmt {
412 fn dummy() -> Self {
413 Default::default()
414 }
415}
416
417#[ast_node("SwitchCase")]
418#[derive(Eq, Hash, EqIgnoreSpan, Default)]
419#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
420#[cfg_attr(feature = "shrink-to-fit", derive(shrink_to_fit::ShrinkToFit))]
421pub struct SwitchCase {
422 pub span: Span,
423
424 #[cfg_attr(feature = "serde-impl", serde(default))]
426 pub test: Option<Box<Expr>>,
427
428 #[cfg_attr(feature = "serde-impl", serde(rename = "consequent"))]
429 pub cons: Vec<Stmt>,
430}
431
432impl Take for SwitchCase {
433 fn dummy() -> Self {
434 Self {
435 span: DUMMY_SP,
436 test: None,
437 cons: Vec::new(),
438 }
439 }
440}
441
442#[ast_node("CatchClause")]
443#[derive(Eq, Hash, EqIgnoreSpan, Default)]
444#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
445#[cfg_attr(feature = "shrink-to-fit", derive(shrink_to_fit::ShrinkToFit))]
446pub struct CatchClause {
447 pub span: Span,
448 #[cfg_attr(feature = "serde-impl", serde(default))]
453 pub param: Option<Pat>,
454
455 pub body: BlockStmt,
456}
457
458#[ast_node]
460#[derive(Eq, Hash, Is, EqIgnoreSpan)]
461#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
462#[cfg_attr(feature = "shrink-to-fit", derive(shrink_to_fit::ShrinkToFit))]
463pub enum ForHead {
464 #[tag("VariableDeclaration")]
465 VarDecl(Box<VarDecl>),
466
467 #[tag("UsingDeclaration")]
468 UsingDecl(Box<UsingDecl>),
469
470 #[tag("*")]
471 Pat(Box<Pat>),
472}
473
474bridge_from!(ForHead, Box<VarDecl>, VarDecl);
475bridge_from!(ForHead, Box<Pat>, Pat);
476
477impl Take for ForHead {
478 fn dummy() -> Self {
479 Default::default()
480 }
481}
482
483impl Default for ForHead {
484 fn default() -> Self {
485 ForHead::Pat(Take::dummy())
486 }
487}
488
489#[ast_node]
490#[derive(Eq, Hash, Is, EqIgnoreSpan)]
491#[allow(variant_size_differences)]
492#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
493#[cfg_attr(feature = "shrink-to-fit", derive(shrink_to_fit::ShrinkToFit))]
494pub enum VarDeclOrExpr {
495 #[tag("VariableDeclaration")]
496 VarDecl(Box<VarDecl>),
497
498 #[tag("*")]
499 Expr(Box<Expr>),
500}
501
502bridge_from!(VarDeclOrExpr, Box<VarDecl>, VarDecl);
503bridge_from!(VarDeclOrExpr, Box<Expr>, Expr);
504
505impl Take for VarDeclOrExpr {
506 fn dummy() -> Self {
507 VarDeclOrExpr::Expr(Take::dummy())
508 }
509}