use is_macro::Is;
use swc_common::{ast_node, util::take::Take, EqIgnoreSpan, Span, SyntaxContext, DUMMY_SP};
use crate::{
decl::{Decl, VarDecl},
expr::Expr,
pat::Pat,
Ident, Lit, Str, UsingDecl,
};
#[ast_node("BlockStatement")]
#[derive(Eq, Hash, EqIgnoreSpan, Default)]
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
pub struct BlockStmt {
pub span: Span,
pub ctxt: SyntaxContext,
pub stmts: Vec<Stmt>,
}
impl Take for BlockStmt {
fn dummy() -> Self {
BlockStmt {
span: DUMMY_SP,
stmts: Vec::new(),
ctxt: Default::default(),
}
}
}
#[ast_node(no_clone)]
#[derive(Eq, Hash, Is, EqIgnoreSpan)]
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
pub enum Stmt {
#[tag("BlockStatement")]
Block(BlockStmt),
#[tag("EmptyStatement")]
Empty(EmptyStmt),
#[tag("DebuggerStatement")]
Debugger(DebuggerStmt),
#[tag("WithStatement")]
With(WithStmt),
#[tag("ReturnStatement")]
#[is(name = "return_stmt")]
Return(ReturnStmt),
#[tag("LabeledStatement")]
Labeled(LabeledStmt),
#[tag("BreakStatement")]
#[is(name = "break_stmt")]
Break(BreakStmt),
#[tag("ContinueStatement")]
#[is(name = "continue_stmt")]
Continue(ContinueStmt),
#[tag("IfStatement")]
#[is(name = "if_stmt")]
If(IfStmt),
#[tag("SwitchStatement")]
Switch(SwitchStmt),
#[tag("ThrowStatement")]
Throw(ThrowStmt),
#[tag("TryStatement")]
#[is(name = "try_stmt")]
Try(Box<TryStmt>),
#[tag("WhileStatement")]
#[is(name = "while_stmt")]
While(WhileStmt),
#[tag("DoWhileStatement")]
DoWhile(DoWhileStmt),
#[tag("ForStatement")]
#[is(name = "for_stmt")]
For(ForStmt),
#[tag("ForInStatement")]
ForIn(ForInStmt),
#[tag("ForOfStatement")]
ForOf(ForOfStmt),
#[tag("ClassDeclaration")]
#[tag("FunctionDeclaration")]
#[tag("VariableDeclaration")]
#[tag("TsInterfaceDeclaration")]
#[tag("TsTypeAliasDeclaration")]
#[tag("TsEnumDeclaration")]
#[tag("TsModuleDeclaration")]
#[tag("UsingDeclaration")]
Decl(Decl),
#[tag("ExpressionStatement")]
Expr(ExprStmt),
}
boxed!(Stmt, [TryStmt]);
macro_rules! stmt_from {
($($varant_ty:ty),*) => {
$(
bridge_from!(Box<crate::Stmt>, crate::Stmt, $varant_ty);
bridge_from!(crate::ModuleItem, crate::Stmt, $varant_ty);
)*
};
}
stmt_from!(
ExprStmt,
BlockStmt,
EmptyStmt,
DebuggerStmt,
WithStmt,
ReturnStmt,
LabeledStmt,
BreakStmt,
ContinueStmt,
IfStmt,
SwitchStmt,
ThrowStmt,
TryStmt,
WhileStmt,
DoWhileStmt,
ForStmt,
ForInStmt,
ForOfStmt,
Decl
);
impl Stmt {
pub fn is_use_strict(&self) -> bool {
match self {
Stmt::Expr(expr) => match *expr.expr {
Expr::Lit(Lit::Str(Str { ref raw, .. })) => {
matches!(raw, Some(value) if value == "\"use strict\"" || value == "'use strict'")
}
_ => false,
},
_ => false,
}
}
pub fn can_precede_directive(&self) -> bool {
match self {
Stmt::Expr(expr) => matches!(*expr.expr, Expr::Lit(Lit::Str(_))),
_ => false,
}
}
}
impl Clone for Stmt {
fn clone(&self) -> Self {
use Stmt::*;
match self {
Block(s) => Block(s.clone()),
Empty(s) => Empty(s.clone()),
Debugger(s) => Debugger(s.clone()),
With(s) => With(s.clone()),
Return(s) => Return(s.clone()),
Labeled(s) => Labeled(s.clone()),
Break(s) => Break(s.clone()),
Continue(s) => Continue(s.clone()),
If(s) => If(s.clone()),
Switch(s) => Switch(s.clone()),
Throw(s) => Throw(s.clone()),
Try(s) => Try(s.clone()),
While(s) => While(s.clone()),
DoWhile(s) => DoWhile(s.clone()),
For(s) => For(s.clone()),
ForIn(s) => ForIn(s.clone()),
ForOf(s) => ForOf(s.clone()),
Decl(s) => Decl(s.clone()),
Expr(s) => Expr(s.clone()),
}
}
}
impl Default for Stmt {
fn default() -> Self {
Self::Empty(EmptyStmt { span: DUMMY_SP })
}
}
impl Take for Stmt {
fn dummy() -> Self {
Default::default()
}
}
#[ast_node("ExpressionStatement")]
#[derive(Eq, Hash, EqIgnoreSpan, Default)]
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
pub struct ExprStmt {
pub span: Span,
#[cfg_attr(feature = "serde-impl", serde(rename = "expression"))]
pub expr: Box<Expr>,
}
#[ast_node("EmptyStatement")]
#[derive(Eq, Hash, Copy, EqIgnoreSpan)]
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
pub struct EmptyStmt {
pub span: Span,
}
#[ast_node("DebuggerStatement")]
#[derive(Eq, Hash, Copy, EqIgnoreSpan)]
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
pub struct DebuggerStmt {
pub span: Span,
}
#[ast_node("WithStatement")]
#[derive(Eq, Hash, EqIgnoreSpan, Default)]
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
pub struct WithStmt {
pub span: Span,
#[cfg_attr(feature = "serde-impl", serde(rename = "object"))]
pub obj: Box<Expr>,
pub body: Box<Stmt>,
}
#[ast_node("ReturnStatement")]
#[derive(Eq, Hash, EqIgnoreSpan, Default)]
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
pub struct ReturnStmt {
pub span: Span,
#[cfg_attr(feature = "serde-impl", serde(default, rename = "argument"))]
pub arg: Option<Box<Expr>>,
}
#[ast_node("LabeledStatement")]
#[derive(Eq, Hash, EqIgnoreSpan, Default)]
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
pub struct LabeledStmt {
pub span: Span,
pub label: Ident,
pub body: Box<Stmt>,
}
#[ast_node("BreakStatement")]
#[derive(Eq, Hash, EqIgnoreSpan, Default)]
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
pub struct BreakStmt {
pub span: Span,
#[cfg_attr(feature = "serde-impl", serde(default))]
pub label: Option<Ident>,
}
#[ast_node("ContinueStatement")]
#[derive(Eq, Hash, EqIgnoreSpan, Default)]
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
pub struct ContinueStmt {
pub span: Span,
#[cfg_attr(feature = "serde-impl", serde(default))]
pub label: Option<Ident>,
}
#[ast_node("IfStatement")]
#[derive(Eq, Hash, EqIgnoreSpan, Default)]
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
pub struct IfStmt {
pub span: Span,
pub test: Box<Expr>,
#[cfg_attr(feature = "serde-impl", serde(rename = "consequent"))]
pub cons: Box<Stmt>,
#[cfg_attr(feature = "serde-impl", serde(default, rename = "alternate"))]
pub alt: Option<Box<Stmt>>,
}
#[ast_node("SwitchStatement")]
#[derive(Eq, Hash, EqIgnoreSpan, Default)]
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
pub struct SwitchStmt {
pub span: Span,
pub discriminant: Box<Expr>,
pub cases: Vec<SwitchCase>,
}
#[ast_node("ThrowStatement")]
#[derive(Eq, Hash, EqIgnoreSpan, Default)]
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
pub struct ThrowStmt {
pub span: Span,
#[cfg_attr(feature = "serde-impl", serde(rename = "argument"))]
pub arg: Box<Expr>,
}
#[ast_node("TryStatement")]
#[derive(Eq, Hash, EqIgnoreSpan, Default)]
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
pub struct TryStmt {
pub span: Span,
pub block: BlockStmt,
#[cfg_attr(feature = "serde-impl", serde(default))]
pub handler: Option<CatchClause>,
#[cfg_attr(feature = "serde-impl", serde(default))]
pub finalizer: Option<BlockStmt>,
}
#[ast_node("WhileStatement")]
#[derive(Eq, Hash, EqIgnoreSpan, Default)]
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
pub struct WhileStmt {
pub span: Span,
pub test: Box<Expr>,
pub body: Box<Stmt>,
}
#[ast_node("DoWhileStatement")]
#[derive(Eq, Hash, EqIgnoreSpan, Default)]
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
pub struct DoWhileStmt {
pub span: Span,
pub test: Box<Expr>,
pub body: Box<Stmt>,
}
#[ast_node("ForStatement")]
#[derive(Eq, Hash, EqIgnoreSpan, Default)]
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
pub struct ForStmt {
pub span: Span,
#[cfg_attr(feature = "serde-impl", serde(default))]
pub init: Option<VarDeclOrExpr>,
#[cfg_attr(feature = "serde-impl", serde(default))]
pub test: Option<Box<Expr>>,
#[cfg_attr(feature = "serde-impl", serde(default))]
pub update: Option<Box<Expr>>,
pub body: Box<Stmt>,
}
#[ast_node("ForInStatement")]
#[derive(Eq, Hash, EqIgnoreSpan, Default)]
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
pub struct ForInStmt {
pub span: Span,
pub left: ForHead,
pub right: Box<Expr>,
pub body: Box<Stmt>,
}
#[ast_node("ForOfStatement")]
#[derive(Eq, Hash, EqIgnoreSpan, Default)]
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
pub struct ForOfStmt {
pub span: Span,
#[cfg_attr(feature = "serde-impl", serde(default, rename = "await"))]
pub is_await: bool,
pub left: ForHead,
pub right: Box<Expr>,
pub body: Box<Stmt>,
}
impl Take for ForOfStmt {
fn dummy() -> Self {
Default::default()
}
}
#[ast_node("SwitchCase")]
#[derive(Eq, Hash, EqIgnoreSpan, Default)]
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
pub struct SwitchCase {
pub span: Span,
#[cfg_attr(feature = "serde-impl", serde(default))]
pub test: Option<Box<Expr>>,
#[cfg_attr(feature = "serde-impl", serde(rename = "consequent"))]
pub cons: Vec<Stmt>,
}
impl Take for SwitchCase {
fn dummy() -> Self {
Self {
span: DUMMY_SP,
test: None,
cons: Vec::new(),
}
}
}
#[ast_node("CatchClause")]
#[derive(Eq, Hash, EqIgnoreSpan, Default)]
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
pub struct CatchClause {
pub span: Span,
#[cfg_attr(feature = "serde-impl", serde(default))]
pub param: Option<Pat>,
pub body: BlockStmt,
}
#[ast_node]
#[derive(Eq, Hash, Is, EqIgnoreSpan)]
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
pub enum ForHead {
#[tag("VariableDeclaration")]
VarDecl(Box<VarDecl>),
#[tag("UsingDeclaration")]
UsingDecl(Box<UsingDecl>),
#[tag("*")]
Pat(Box<Pat>),
}
bridge_from!(ForHead, Box<VarDecl>, VarDecl);
bridge_from!(ForHead, Box<Pat>, Pat);
impl Take for ForHead {
fn dummy() -> Self {
Default::default()
}
}
impl Default for ForHead {
fn default() -> Self {
ForHead::Pat(Take::dummy())
}
}
#[ast_node]
#[derive(Eq, Hash, Is, EqIgnoreSpan)]
#[allow(variant_size_differences)]
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
pub enum VarDeclOrExpr {
#[tag("VariableDeclaration")]
VarDecl(Box<VarDecl>),
#[tag("*")]
Expr(Box<Expr>),
}
bridge_from!(VarDeclOrExpr, Box<VarDecl>, VarDecl);
bridge_from!(VarDeclOrExpr, Box<Expr>, Expr);
impl Take for VarDeclOrExpr {
fn dummy() -> Self {
VarDeclOrExpr::Expr(Take::dummy())
}
}