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