swc_ecma_quote_macros/ast/
mod.rs1use 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
111impl<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}