swc_ecma_parser/parser/
util.rs

1use super::*;
2use crate::token::{IdentLike, Keyword};
3
4impl Context {
5    pub(crate) fn is_reserved(self, word: &Word) -> bool {
6        match *word {
7            Word::Keyword(Keyword::Let) => self.strict,
8            Word::Keyword(Keyword::Await) => self.in_async || self.in_static_block || self.strict,
9            Word::Keyword(Keyword::Yield) => self.in_generator || self.strict,
10
11            Word::Null
12            | Word::True
13            | Word::False
14            | Word::Keyword(Keyword::Break)
15            | Word::Keyword(Keyword::Case)
16            | Word::Keyword(Keyword::Catch)
17            | Word::Keyword(Keyword::Continue)
18            | Word::Keyword(Keyword::Debugger)
19            | Word::Keyword(Keyword::Default_)
20            | Word::Keyword(Keyword::Do)
21            | Word::Keyword(Keyword::Export)
22            | Word::Keyword(Keyword::Else)
23            | Word::Keyword(Keyword::Finally)
24            | Word::Keyword(Keyword::For)
25            | Word::Keyword(Keyword::Function)
26            | Word::Keyword(Keyword::If)
27            | Word::Keyword(Keyword::Return)
28            | Word::Keyword(Keyword::Switch)
29            | Word::Keyword(Keyword::Throw)
30            | Word::Keyword(Keyword::Try)
31            | Word::Keyword(Keyword::Var)
32            | Word::Keyword(Keyword::Const)
33            | Word::Keyword(Keyword::While)
34            | Word::Keyword(Keyword::With)
35            | Word::Keyword(Keyword::New)
36            | Word::Keyword(Keyword::This)
37            | Word::Keyword(Keyword::Super)
38            | Word::Keyword(Keyword::Class)
39            | Word::Keyword(Keyword::Extends)
40            | Word::Keyword(Keyword::Import)
41            | Word::Keyword(Keyword::In)
42            | Word::Keyword(Keyword::InstanceOf)
43            | Word::Keyword(Keyword::TypeOf)
44            | Word::Keyword(Keyword::Void)
45            | Word::Keyword(Keyword::Delete) => true,
46
47            // Future reserved word
48            Word::Ident(IdentLike::Known(known_ident!("enum"))) => true,
49
50            Word::Ident(IdentLike::Known(
51                known_ident!("implements")
52                | known_ident!("package")
53                | known_ident!("protected")
54                | known_ident!("interface")
55                | known_ident!("private")
56                | known_ident!("public"),
57            )) if self.strict => true,
58
59            _ => false,
60        }
61    }
62
63    #[cfg_attr(not(feature = "verify"), inline(always))]
64    pub fn is_reserved_word(self, word: &Atom) -> bool {
65        if !cfg!(feature = "verify") {
66            return false;
67        }
68
69        match &**word {
70            "let" => self.strict,
71            // SyntaxError in the module only, not in the strict.
72            // ```JavaScript
73            // function foo() {
74            //     "use strict";
75            //     let await = 1;
76            // }
77            // ```
78            "await" => self.in_async || self.in_static_block || self.module,
79            "yield" => self.in_generator || self.strict,
80
81            "null" | "true" | "false" | "break" | "case" | "catch" | "continue" | "debugger"
82            | "default" | "do" | "export" | "else" | "finally" | "for" | "function" | "if"
83            | "return" | "switch" | "throw" | "try" | "var" | "const" | "while" | "with"
84            | "new" | "this" | "super" | "class" | "extends" | "import" | "in" | "instanceof"
85            | "typeof" | "void" | "delete" => true,
86
87            // Future reserved word
88            "enum" => true,
89
90            "implements" | "package" | "protected" | "interface" | "private" | "public"
91                if self.strict =>
92            {
93                true
94            }
95
96            _ => false,
97        }
98    }
99}
100
101impl<I: Tokens> Parser<I> {
102    /// Original context is restored when returned guard is dropped.
103    pub(super) fn with_ctx(&mut self, ctx: Context) -> WithCtx<I> {
104        let orig_ctx = self.ctx();
105        self.set_ctx(ctx);
106        WithCtx {
107            orig_ctx,
108            inner: self,
109        }
110    }
111
112    /// Original state is restored when returned guard is dropped.
113    pub(super) fn with_state(&mut self, state: State) -> WithState<I> {
114        let orig_state = std::mem::replace(&mut self.state, state);
115        WithState {
116            orig_state,
117            inner: self,
118        }
119    }
120
121    pub(super) fn set_ctx(&mut self, ctx: Context) {
122        self.input.set_ctx(ctx);
123    }
124
125    pub(super) fn strict_mode(&mut self) -> WithCtx<I> {
126        let ctx = Context {
127            strict: true,
128            ..self.ctx()
129        };
130        self.with_ctx(ctx)
131    }
132
133    /// Original context is restored when returned guard is dropped.
134    pub(super) fn in_type(&mut self) -> WithCtx<I> {
135        let ctx = Context {
136            in_type: true,
137            ..self.ctx()
138        };
139        self.with_ctx(ctx)
140    }
141
142    /// Original context is restored when returned guard is dropped.
143    pub(super) fn include_in_expr(&mut self, include_in_expr: bool) -> WithCtx<I> {
144        let ctx = Context {
145            include_in_expr,
146            ..self.ctx()
147        };
148        self.with_ctx(ctx)
149    }
150
151    /// Parse with given closure
152    #[inline(always)]
153    pub(super) fn parse_with<F, Ret>(&mut self, f: F) -> PResult<Ret>
154    where
155        F: FnOnce(&mut Self) -> PResult<Ret>,
156    {
157        f(self)
158    }
159
160    pub(super) fn syntax(&self) -> Syntax {
161        self.input.syntax()
162    }
163}
164pub trait ParseObject<Obj> {
165    type Prop;
166    fn make_object(
167        &mut self,
168        span: Span,
169        props: Vec<Self::Prop>,
170        trailing_comma: Option<Span>,
171    ) -> PResult<Obj>;
172    fn parse_object_prop(&mut self) -> PResult<Self::Prop>;
173}
174
175pub struct WithState<'w, I: 'w + Tokens> {
176    inner: &'w mut Parser<I>,
177    orig_state: State,
178}
179impl<I: Tokens> Deref for WithState<'_, I> {
180    type Target = Parser<I>;
181
182    fn deref(&self) -> &Parser<I> {
183        self.inner
184    }
185}
186impl<I: Tokens> DerefMut for WithState<'_, I> {
187    fn deref_mut(&mut self) -> &mut Parser<I> {
188        self.inner
189    }
190}
191impl<I: Tokens> Drop for WithState<'_, I> {
192    fn drop(&mut self) {
193        std::mem::swap(&mut self.inner.state, &mut self.orig_state);
194    }
195}
196
197pub struct WithCtx<'w, I: 'w + Tokens> {
198    inner: &'w mut Parser<I>,
199    orig_ctx: Context,
200}
201impl<I: Tokens> Deref for WithCtx<'_, I> {
202    type Target = Parser<I>;
203
204    fn deref(&self) -> &Parser<I> {
205        self.inner
206    }
207}
208impl<I: Tokens> DerefMut for WithCtx<'_, I> {
209    fn deref_mut(&mut self) -> &mut Parser<I> {
210        self.inner
211    }
212}
213
214impl<I: Tokens> Drop for WithCtx<'_, I> {
215    fn drop(&mut self) {
216        self.inner.set_ctx(self.orig_ctx);
217    }
218}
219
220pub(super) trait ExprExt {
221    fn as_expr(&self) -> &Expr;
222
223    /// "IsValidSimpleAssignmentTarget" from spec.
224    fn is_valid_simple_assignment_target(&self, strict: bool) -> bool {
225        match self.as_expr() {
226            Expr::Ident(ident) => {
227                if strict && ident.is_reserved_in_strict_bind() {
228                    return false;
229                }
230                true
231            }
232
233            Expr::This(..)
234            | Expr::Lit(..)
235            | Expr::Array(..)
236            | Expr::Object(..)
237            | Expr::Fn(..)
238            | Expr::Class(..)
239            | Expr::Tpl(..)
240            | Expr::TaggedTpl(..) => false,
241            Expr::Paren(ParenExpr { expr, .. }) => expr.is_valid_simple_assignment_target(strict),
242
243            Expr::Member(MemberExpr { obj, .. }) => match obj.as_ref() {
244                Expr::Member(..) => obj.is_valid_simple_assignment_target(strict),
245                Expr::OptChain(..) => false,
246                _ => true,
247            },
248
249            Expr::SuperProp(..) => true,
250
251            Expr::New(..) | Expr::Call(..) => false,
252            // TODO: Spec only mentions `new.target`
253            Expr::MetaProp(..) => false,
254
255            Expr::Update(..) => false,
256
257            Expr::Unary(..) | Expr::Await(..) => false,
258
259            Expr::Bin(..) => false,
260
261            Expr::Cond(..) => false,
262
263            Expr::Yield(..) | Expr::Arrow(..) | Expr::Assign(..) => false,
264
265            Expr::Seq(..) => false,
266
267            Expr::OptChain(..) => false,
268
269            // MemberExpression is valid assignment target
270            Expr::PrivateName(..) => false,
271
272            // jsx
273            Expr::JSXMember(..)
274            | Expr::JSXNamespacedName(..)
275            | Expr::JSXEmpty(..)
276            | Expr::JSXElement(..)
277            | Expr::JSXFragment(..) => false,
278
279            // typescript
280            Expr::TsNonNull(TsNonNullExpr { ref expr, .. })
281            | Expr::TsTypeAssertion(TsTypeAssertion { ref expr, .. })
282            | Expr::TsAs(TsAsExpr { ref expr, .. })
283            | Expr::TsInstantiation(TsInstantiation { ref expr, .. })
284            | Expr::TsSatisfies(TsSatisfiesExpr { ref expr, .. }) => {
285                expr.is_valid_simple_assignment_target(strict)
286            }
287
288            Expr::TsConstAssertion(..) => false,
289
290            Expr::Invalid(..) => false,
291        }
292    }
293}
294
295impl ExprExt for Box<Expr> {
296    fn as_expr(&self) -> &Expr {
297        self
298    }
299}
300impl ExprExt for Expr {
301    fn as_expr(&self) -> &Expr {
302        self
303    }
304}