swc_ecma_codegen/
util.rs

1use swc_ecma_ast::*;
2
3pub trait EndsWithAlphaNum {
4    fn ends_with_alpha_num(&self) -> bool;
5}
6
7impl EndsWithAlphaNum for ForHead {
8    fn ends_with_alpha_num(&self) -> bool {
9        match self {
10            ForHead::VarDecl(n) => n.ends_with_alpha_num(),
11            ForHead::Pat(n) => n.ends_with_alpha_num(),
12            ForHead::UsingDecl(n) => n.ends_with_alpha_num(),
13            #[cfg(swc_ast_unknown)]
14            _ => false,
15        }
16    }
17}
18
19impl EndsWithAlphaNum for Pat {
20    fn ends_with_alpha_num(&self) -> bool {
21        match self {
22            Pat::Object(_) | Pat::Array(_) => false,
23            Pat::Rest(p) => p.arg.ends_with_alpha_num(),
24            Pat::Assign(p) => p.right.ends_with_alpha_num(),
25            Pat::Expr(p) => p.ends_with_alpha_num(),
26            _ => true,
27        }
28    }
29}
30
31impl EndsWithAlphaNum for VarDecl {
32    fn ends_with_alpha_num(&self) -> bool {
33        match self.decls.last() {
34            None => true,
35            Some(d) => match d.init.as_deref() {
36                Some(e) => e.ends_with_alpha_num(),
37                None => d.name.ends_with_alpha_num(),
38            },
39        }
40    }
41}
42
43impl EndsWithAlphaNum for UsingDecl {
44    fn ends_with_alpha_num(&self) -> bool {
45        match self.decls.last() {
46            None => true,
47            Some(d) => match d.init.as_deref() {
48                Some(e) => e.ends_with_alpha_num(),
49                None => d.name.ends_with_alpha_num(),
50            },
51        }
52    }
53}
54
55impl EndsWithAlphaNum for Expr {
56    fn ends_with_alpha_num(&self) -> bool {
57        match self {
58            Expr::Array(..)
59            | Expr::Object(..)
60            | Expr::Lit(Lit::Str(..))
61            | Expr::Paren(..)
62            | Expr::Member(MemberExpr {
63                prop: MemberProp::Computed(..),
64                ..
65            })
66            | Expr::Tpl(..)
67            | Expr::TaggedTpl(..)
68            | Expr::Call(..) => false,
69
70            Expr::Unary(n) => n.arg.ends_with_alpha_num(),
71
72            Expr::Update(n) => n.prefix && n.arg.ends_with_alpha_num(),
73
74            Expr::OptChain(n) => match n.base.as_ref() {
75                OptChainBase::Member(base) => !base.prop.is_computed(),
76                OptChainBase::Call(_) => false,
77                #[cfg(swc_ast_unknown)]
78                _ => false,
79            },
80
81            Expr::Bin(n) => n.right.ends_with_alpha_num(),
82
83            Expr::New(NewExpr {
84                args: Some(args), ..
85            }) => args.is_empty(),
86
87            _ => true,
88        }
89    }
90}
91
92/// Leftmost recursion
93pub trait StartsWithAlphaNum {
94    fn starts_with_alpha_num(&self) -> bool;
95}
96
97macro_rules! alpha_num_enum {
98    ($T:ty, [$($name:ident),*]) => {
99        impl StartsWithAlphaNum for $T {
100            #[inline]
101            fn starts_with_alpha_num(&self) -> bool {
102                match *self {
103                    $(
104                        Self::$name(ref n) => n.starts_with_alpha_num(),
105                    )*
106                    #[cfg(swc_ast_unknown)]
107                    _ => false,
108                }
109            }
110        }
111    };
112}
113
114macro_rules! alpha_num_const {
115    ($value:tt, $($ty:ident),*) => {
116        $(
117            impl StartsWithAlphaNum for $ty {
118                #[inline]
119                fn starts_with_alpha_num(&self) -> bool {
120                    $value
121                }
122            }
123        )*
124    };
125}
126
127alpha_num_const!(true, BindingIdent, Ident, SuperPropExpr, TsTypeAssertion);
128alpha_num_const!(false, ArrayPat, ObjectPat, Invalid, ParenExpr);
129
130impl StartsWithAlphaNum for MemberExpr {
131    #[inline]
132    fn starts_with_alpha_num(&self) -> bool {
133        self.obj.starts_with_alpha_num()
134    }
135}
136
137impl StartsWithAlphaNum for TsAsExpr {
138    #[inline]
139    fn starts_with_alpha_num(&self) -> bool {
140        self.expr.starts_with_alpha_num()
141    }
142}
143
144impl StartsWithAlphaNum for TsSatisfiesExpr {
145    #[inline]
146    fn starts_with_alpha_num(&self) -> bool {
147        self.expr.starts_with_alpha_num()
148    }
149}
150
151impl StartsWithAlphaNum for TsNonNullExpr {
152    #[inline]
153    fn starts_with_alpha_num(&self) -> bool {
154        self.expr.starts_with_alpha_num()
155    }
156}
157
158impl StartsWithAlphaNum for TsInstantiation {
159    #[inline]
160    fn starts_with_alpha_num(&self) -> bool {
161        self.expr.starts_with_alpha_num()
162    }
163}
164
165impl StartsWithAlphaNum for PropName {
166    #[inline]
167    fn starts_with_alpha_num(&self) -> bool {
168        match self {
169            PropName::Str(_) | PropName::Computed(_) => false,
170            PropName::Ident(_) | PropName::Num(_) | PropName::BigInt(_) => true,
171            #[cfg(swc_ast_unknown)]
172            _ => false,
173        }
174    }
175}
176
177impl StartsWithAlphaNum for Expr {
178    fn starts_with_alpha_num(&self) -> bool {
179        match self {
180            Expr::Ident(_)
181            | Expr::Lit(Lit::Bool(_))
182            | Expr::Lit(Lit::Num(_))
183            | Expr::Lit(Lit::Null(_))
184            | Expr::Lit(Lit::BigInt(_))
185            | Expr::Await(_)
186            | Expr::Fn(_)
187            | Expr::Class(_)
188            | Expr::This(_)
189            | Expr::Yield(_)
190            | Expr::New(_)
191            | Expr::MetaProp(_)
192            | Expr::SuperProp(_) => true,
193
194            Expr::PrivateName(_) => false,
195
196            // Handle other literals.
197            Expr::Lit(_) => false,
198
199            Expr::Seq(SeqExpr { ref exprs, .. }) => exprs
200                .first()
201                .map(|e| e.starts_with_alpha_num())
202                .unwrap_or(false),
203
204            //
205            Expr::Assign(AssignExpr { ref left, .. }) => left.starts_with_alpha_num(),
206
207            Expr::Bin(BinExpr { ref left, .. }) | Expr::Cond(CondExpr { test: ref left, .. }) => {
208                left.starts_with_alpha_num()
209            }
210            Expr::Call(CallExpr { callee: left, .. }) => left.starts_with_alpha_num(),
211            Expr::Member(MemberExpr { obj: ref left, .. }) => left.starts_with_alpha_num(),
212
213            Expr::Unary(UnaryExpr { op, .. }) => {
214                matches!(op, op!("void") | op!("delete") | op!("typeof"))
215            }
216
217            Expr::Arrow(ref expr) => {
218                if expr.is_async {
219                    true
220                } else {
221                    match expr.params.as_slice() {
222                        [p] => p.starts_with_alpha_num(),
223                        _ => false,
224                    }
225                }
226            }
227
228            Expr::Update(ref expr) => {
229                if expr.prefix {
230                    false
231                } else {
232                    expr.arg.starts_with_alpha_num()
233                }
234            }
235
236            Expr::Tpl(_) | Expr::Array(_) | Expr::Object(_) | Expr::Paren(_) => false,
237
238            Expr::TaggedTpl(TaggedTpl { ref tag, .. }) => tag.starts_with_alpha_num(),
239
240            // it's empty
241            Expr::JSXEmpty(..) => false,
242            // start with `<`
243            Expr::JSXFragment(..) | Expr::JSXElement(..) => false,
244            Expr::JSXNamespacedName(..) => true,
245            Expr::JSXMember(..) => true,
246
247            Expr::TsTypeAssertion(..) => false,
248            Expr::TsNonNull(TsNonNullExpr { ref expr, .. })
249            | Expr::TsAs(TsAsExpr { ref expr, .. })
250            | Expr::TsConstAssertion(TsConstAssertion { ref expr, .. })
251            | Expr::TsInstantiation(TsInstantiation { ref expr, .. })
252            | Expr::TsSatisfies(TsSatisfiesExpr { ref expr, .. }) => expr.starts_with_alpha_num(),
253
254            Expr::OptChain(e) => e.starts_with_alpha_num(),
255
256            Expr::Invalid(..) => true,
257            #[cfg(swc_ast_unknown)]
258            _ => false,
259        }
260    }
261}
262
263impl StartsWithAlphaNum for OptChainExpr {
264    fn starts_with_alpha_num(&self) -> bool {
265        match &*self.base {
266            OptChainBase::Member(base) => base.obj.starts_with_alpha_num(),
267            OptChainBase::Call(base) => base.callee.starts_with_alpha_num(),
268            #[cfg(swc_ast_unknown)]
269            _ => false,
270        }
271    }
272}
273
274impl StartsWithAlphaNum for Pat {
275    fn starts_with_alpha_num(&self) -> bool {
276        match *self {
277            Pat::Ident(..) => true,
278            Pat::Assign(AssignPat { ref left, .. }) => left.starts_with_alpha_num(),
279            Pat::Object(..) | Pat::Array(..) | Pat::Rest(..) => false,
280            Pat::Expr(ref expr) => expr.starts_with_alpha_num(),
281            Pat::Invalid(..) => true,
282            #[cfg(swc_ast_unknown)]
283            _ => false,
284        }
285    }
286}
287
288alpha_num_enum!(AssignTarget, [Pat, Simple]);
289alpha_num_enum!(
290    SimpleAssignTarget,
291    [
292        Ident,
293        Member,
294        SuperProp,
295        OptChain,
296        Paren,
297        TsAs,
298        TsSatisfies,
299        TsNonNull,
300        TsTypeAssertion,
301        TsInstantiation,
302        Invalid
303    ]
304);
305alpha_num_enum!(AssignTargetPat, [Array, Object, Invalid]);
306
307impl StartsWithAlphaNum for ExprOrSpread {
308    fn starts_with_alpha_num(&self) -> bool {
309        match *self {
310            ExprOrSpread {
311                spread: Some(_), ..
312            } => false,
313            ExprOrSpread {
314                spread: None,
315                ref expr,
316            } => expr.starts_with_alpha_num(),
317        }
318    }
319}
320impl StartsWithAlphaNum for Callee {
321    fn starts_with_alpha_num(&self) -> bool {
322        match *self {
323            Callee::Super(_) | Callee::Import(_) => true,
324            Callee::Expr(ref e) => e.starts_with_alpha_num(),
325            #[cfg(swc_ast_unknown)]
326            _ => false,
327        }
328    }
329}
330impl StartsWithAlphaNum for Stmt {
331    fn starts_with_alpha_num(&self) -> bool {
332        match *self {
333            Stmt::Expr(ref expr) => expr.expr.starts_with_alpha_num(),
334            Stmt::Decl(ref decl) => decl.starts_with_alpha_num(),
335            Stmt::Debugger(..)
336            | Stmt::With(..)
337            | Stmt::While(..)
338            | Stmt::DoWhile(..)
339            | Stmt::Return(..)
340            | Stmt::Labeled(..)
341            | Stmt::Break(..)
342            | Stmt::Continue(..)
343            | Stmt::Switch(..)
344            | Stmt::Throw(..)
345            | Stmt::Try(..)
346            | Stmt::For(..)
347            | Stmt::ForIn(..)
348            | Stmt::ForOf(..)
349            | Stmt::If(..) => true,
350            Stmt::Block(..) | Stmt::Empty(..) => false,
351            #[cfg(swc_ast_unknown)]
352            _ => false,
353        }
354    }
355}
356
357impl StartsWithAlphaNum for Decl {
358    fn starts_with_alpha_num(&self) -> bool {
359        match *self {
360            Decl::Class(..)
361            | Decl::Fn(..)
362            | Decl::Var(..)
363            | Decl::TsEnum(..)
364            | Decl::TsInterface(..)
365            | Decl::TsModule(..)
366            | Decl::TsTypeAlias(..)
367            | Decl::Using(..) => true,
368            #[cfg(swc_ast_unknown)]
369            _ => false,
370        }
371    }
372}