swc_ecma_ast/
stmt.rs

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/// Use when only block statements are allowed.
12#[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    /// Span including the braces.
18    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    /// A try statement. If handler is null then finalizer must be a BlockStmt.
78    #[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    /// Returns true if the statement does not prevent the directives below
160    /// `self` from being directives.
161    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
169// Memory layout depedns on the version of rustc.
170// #[cfg(target_pointer_width = "64")]
171// assert_eq_size!(Stmt, [u8; 56]);
172
173// Implement Clone without inline to avoid multiple copies of the
174// implementation.
175impl 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    /// Span of semicolon.
230    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    /// Span of the await token.
400    ///
401    /// es2018
402    ///
403    /// for-await-of statements, e.g., `for await (const x of xs) {`
404    #[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    /// None for `default:`
425    #[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    /// es2019
449    ///
450    /// The param is null if the catch binding is omitted. E.g., try { foo() }
451    /// catch { bar() }
452    #[cfg_attr(feature = "serde-impl", serde(default))]
453    pub param: Option<Pat>,
454
455    pub body: BlockStmt,
456}
457
458/// A head for for-in and for-of loop.
459#[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}