swc_ecma_quote_macros/ast/
mod.rs

1use swc_common::{Span, SyntaxContext};
2use swc_ecma_ast::*;
3use syn::{parse_quote, ExprBlock};
4
5use crate::ctxt::Ctx;
6
7macro_rules! fail_todo {
8    ($T:ty) => {
9        impl crate::ast::ToCode for $T {
10            fn to_code(&self, _: &crate::ctxt::Ctx) -> syn::Expr {
11                todo!("ToCode for {}", stringify!($T))
12            }
13        }
14    };
15}
16
17macro_rules! impl_enum_body {
18    ($E:ident, $s:expr, $cx:expr,[ $($v:ident),* ]) => {
19        match $s {
20            $(
21                $E::$v(inner) => {
22                    let val = crate::ast::ToCode::to_code(inner, $cx);
23                    syn::parse_quote!(
24                        swc_core::ecma::ast::$E::$v(#val)
25                    )
26                },
27            )*
28            #[cfg(swc_ast_unknown)]
29            _ => panic!("unable to access unknown nodes"),
30        }
31    };
32}
33
34macro_rules! impl_enum {
35    ($E:ident, [ $($v:ident),* ]) => {
36        impl crate::ast::ToCode for $E {
37            fn to_code(&self, cx: &crate::ctxt::Ctx) -> syn::Expr {
38                impl_enum_body!($E, self, cx, [ $($v),* ])
39            }
40        }
41    };
42
43
44    ($E:ident, [ $($v:ident),* ], true) => {
45        impl crate::ast::ToCode for $E {
46            fn to_code(&self, cx: &crate::ctxt::Ctx) -> syn::Expr {
47                if let Some(i) = self.as_ident() {
48                    if let Some(var_name) = i.sym.strip_prefix('$') {
49                        if let Some(var) = cx.var(crate::ctxt::VarPos::$E, var_name) {
50                            return var.get_expr();
51                        }
52                    }
53                }
54
55                impl_enum_body!($E, self, cx, [ $($v),* ])
56            }
57        }
58    };
59}
60
61macro_rules! impl_struct {
62    (
63        $name:ident,
64        [ $($v:ident),* ]
65    ) => {
66        impl crate::ast::ToCode for $name {
67            fn to_code(&self, cx: &crate::ctxt::Ctx) -> syn::Expr {
68                let mut builder = crate::builder::Builder::new(stringify!($name));
69
70                let Self { $($v,)* } = self;
71
72                $(
73                    builder.add(
74                        stringify!($v),
75                        crate::ast::ToCode::to_code($v, cx),
76                    );
77                )*
78
79                syn::Expr::Struct(builder.build())
80            }
81        }
82    };
83}
84
85mod class;
86mod decl;
87mod enums;
88mod expr;
89mod id;
90mod lit;
91mod module_decl;
92mod pat;
93mod prop;
94mod stmt;
95mod typescript;
96
97pub(crate) trait ToCode: 'static {
98    fn to_code(&self, cx: &Ctx) -> syn::Expr;
99}
100
101impl<T> ToCode for Box<T>
102where
103    T: ?Sized + ToCode,
104{
105    fn to_code(&self, cx: &Ctx) -> syn::Expr {
106        let inner = (**self).to_code(cx);
107        parse_quote!(Box::new(#inner))
108    }
109}
110
111/// TODO: Optimize
112impl<T> ToCode for Option<T>
113where
114    T: ToCode,
115{
116    fn to_code(&self, cx: &Ctx) -> syn::Expr {
117        match self {
118            Some(inner) => {
119                let inner = inner.to_code(cx);
120
121                parse_quote!(Some(#inner))
122            }
123            None => parse_quote!(None),
124        }
125    }
126}
127
128impl_struct!(Invalid, [span]);
129
130impl ToCode for Span {
131    fn to_code(&self, _: &Ctx) -> syn::Expr {
132        parse_quote!(swc_core::common::DUMMY_SP)
133    }
134}
135
136impl ToCode for SyntaxContext {
137    fn to_code(&self, _: &Ctx) -> syn::Expr {
138        parse_quote!(swc_core::common::SyntaxContext::empty())
139    }
140}
141
142impl_enum!(ModuleItem, [ModuleDecl, Stmt]);
143
144impl_enum!(
145    Pat,
146    [Ident, Array, Rest, Object, Assign, Invalid, Expr],
147    true
148);
149impl_enum!(Lit, [Str, Bool, Null, Num, BigInt, Regex, JSXText]);
150impl_enum!(
151    ClassMember,
152    [
153        Constructor,
154        Method,
155        PrivateMethod,
156        ClassProp,
157        PrivateProp,
158        TsIndexSignature,
159        Empty,
160        StaticBlock,
161        AutoAccessor
162    ]
163);
164impl_enum!(ObjectPatProp, [KeyValue, Assign, Rest]);
165impl_enum!(PropName, [Ident, Str, Num, Computed, BigInt]);
166impl_enum!(ParamOrTsParamProp, [TsParamProp, Param]);
167impl_enum!(PropOrSpread, [Spread, Prop]);
168impl_enum!(BlockStmtOrExpr, [BlockStmt, Expr]);
169impl_enum!(MemberProp, [Ident, PrivateName, Computed]);
170impl_enum!(SuperProp, [Ident, Computed]);
171impl_enum!(JSXObject, [Ident, JSXMemberExpr]);
172impl_enum!(
173    JSXElementChild,
174    [
175        JSXText,
176        JSXElement,
177        JSXExprContainer,
178        JSXFragment,
179        JSXSpreadChild
180    ]
181);
182impl_enum!(OptChainBase, [Member, Call]);
183impl_enum!(JSXElementName, [Ident, JSXMemberExpr, JSXNamespacedName]);
184impl_enum!(JSXAttrOrSpread, [JSXAttr, SpreadElement]);
185
186impl<T> ToCode for Vec<T>
187where
188    T: ToCode,
189{
190    fn to_code(&self, cx: &Ctx) -> syn::Expr {
191        let len = self.len();
192        let var_stmt: syn::Stmt = parse_quote!(let mut items = Vec::with_capacity(#len););
193        let mut stmts = vec![var_stmt];
194
195        for item in self {
196            let item = item.to_code(cx);
197            stmts.push(syn::Stmt::Expr(
198                parse_quote!(items.push(#item)),
199                Some(Default::default()),
200            ));
201        }
202
203        stmts.push(syn::Stmt::Expr(parse_quote!(items), None));
204
205        syn::Expr::Block(ExprBlock {
206            attrs: Default::default(),
207            label: Default::default(),
208            block: syn::Block {
209                brace_token: Default::default(),
210                stmts,
211            },
212        })
213    }
214}