swc_ecma_ast/
ident.rs

1use std::{
2    borrow::Cow,
3    fmt::Display,
4    ops::{Deref, DerefMut},
5};
6
7use once_cell::sync::Lazy;
8use phf::phf_set;
9use rustc_hash::FxHashSet;
10use swc_atoms::{atom, Atom, UnsafeAtom};
11use swc_common::{
12    ast_node, util::take::Take, BytePos, EqIgnoreSpan, Mark, Span, Spanned, SyntaxContext, DUMMY_SP,
13};
14
15use crate::{typescript::TsTypeAnn, Expr};
16
17/// Identifier used as a pattern.
18#[derive(Clone, Debug, PartialEq, Eq, Hash, EqIgnoreSpan, Default)]
19#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
20#[cfg_attr(
21    any(feature = "rkyv-impl"),
22    derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)
23)]
24#[cfg_attr(
25    feature = "rkyv-impl",
26    rkyv(serialize_bounds(__S: rkyv::ser::Writer + rkyv::ser::Allocator,
27        __S::Error: rkyv::rancor::Source))
28)]
29#[cfg_attr(
30    feature = "rkyv-impl",
31    rkyv(deserialize_bounds(__D::Error: rkyv::rancor::Source))
32)]
33#[cfg_attr(
34    feature = "rkyv-impl",
35    rkyv(bytecheck(bounds(
36        __C: rkyv::validation::ArchiveContext,
37        __C::Error: rkyv::rancor::Source
38    )))
39)]
40#[cfg_attr(feature = "rkyv-impl", repr(C))]
41#[cfg_attr(feature = "serde-impl", derive(serde::Serialize, serde::Deserialize))]
42#[cfg_attr(feature = "shrink-to-fit", derive(shrink_to_fit::ShrinkToFit))]
43pub struct BindingIdent {
44    #[cfg_attr(feature = "serde-impl", serde(flatten))]
45    #[cfg_attr(feature = "__rkyv", rkyv(omit_bounds))]
46    pub id: Ident,
47
48    #[cfg_attr(feature = "serde-impl", serde(default, rename = "typeAnnotation"))]
49    #[cfg_attr(feature = "__rkyv", rkyv(omit_bounds))]
50    pub type_ann: Option<Box<TsTypeAnn>>,
51}
52
53impl Spanned for BindingIdent {
54    fn span(&self) -> Span {
55        match &self.type_ann {
56            Some(ann) => Span::new(self.id.span.lo(), ann.span().hi()),
57            None => self.id.span,
58        }
59    }
60}
61
62impl Deref for BindingIdent {
63    type Target = Ident;
64
65    fn deref(&self) -> &Self::Target {
66        &self.id
67    }
68}
69
70impl DerefMut for BindingIdent {
71    fn deref_mut(&mut self) -> &mut Self::Target {
72        &mut self.id
73    }
74}
75
76impl AsRef<str> for BindingIdent {
77    fn as_ref(&self) -> &str {
78        &self.sym
79    }
80}
81
82impl From<BindingIdent> for Box<Expr> {
83    fn from(bi: BindingIdent) -> Self {
84        Box::new(Expr::Ident(bi.into()))
85    }
86}
87impl From<&'_ BindingIdent> for Ident {
88    fn from(bi: &'_ BindingIdent) -> Self {
89        Ident {
90            span: bi.span,
91            ctxt: bi.ctxt,
92            sym: bi.sym.clone(),
93            optional: bi.optional,
94        }
95    }
96}
97
98impl BindingIdent {
99    /// See [`Ident::to_id`] for documentation.
100    pub fn to_id(&self) -> Id {
101        (self.sym.clone(), self.ctxt)
102    }
103}
104
105impl Take for BindingIdent {
106    fn dummy() -> Self {
107        Default::default()
108    }
109}
110
111impl From<Ident> for BindingIdent {
112    fn from(id: Ident) -> Self {
113        BindingIdent {
114            id,
115            ..Default::default()
116        }
117    }
118}
119
120bridge_from!(BindingIdent, Ident, Id);
121
122/// A complete identifier with span.
123///
124/// Identifier of swc consists of two parts. The first one is symbol, which is
125/// stored using an interned string, [Atom] . The second
126/// one is [SyntaxContext][swc_common::SyntaxContext], which can be
127/// used to distinguish identifier with same symbol.
128///
129/// Let me explain this with an example.
130///
131/// ```ts
132/// let a = 5
133/// {
134///     let a = 3;
135/// }
136/// ```
137/// In the code above, there are two variables with the symbol a.
138///
139///
140/// Other compilers typically uses type like `Scope`, and store them nested, but
141/// in rust, type like `Scope`  requires [Arc<Mutex<Scope>>] so swc uses
142/// different approach. Instead of passing scopes, swc annotates two variables
143/// with different tag, which is named
144/// [SyntaxContext]. The notation for the syntax
145/// context is #n where n is a number. e.g. `foo#1`
146///
147/// For the example above, after applying resolver pass, it becomes.
148///
149/// ```ts
150/// let a#1 = 5
151/// {
152///     let a#2 = 3;
153/// }
154/// ```
155///
156/// Thanks to the `tag` we attached, we can now distinguish them.
157///
158/// ([Atom], [SyntaxContext])
159///
160/// See [Id], which is a type alias for this.
161///
162/// This can be used to store all variables in a module to single hash map.
163///
164/// # Comparison
165///
166/// While comparing two identifiers, you can use `.to_id()`.
167///
168/// # HashMap
169///
170/// There's a type named [Id] which only contains minimal information to
171/// distinguish identifiers.
172#[ast_node("Identifier")]
173#[derive(Eq, Hash, Default)]
174#[cfg_attr(feature = "shrink-to-fit", derive(shrink_to_fit::ShrinkToFit))]
175pub struct Ident {
176    #[cfg_attr(feature = "__rkyv", rkyv(omit_bounds))]
177    pub span: Span,
178
179    #[cfg_attr(feature = "__rkyv", rkyv(omit_bounds))]
180    pub ctxt: SyntaxContext,
181
182    #[cfg_attr(feature = "serde-impl", serde(rename = "value"))]
183    pub sym: Atom,
184
185    /// TypeScript only. Used in case of an optional parameter.
186    #[cfg_attr(feature = "serde-impl", serde(default))]
187    pub optional: bool,
188}
189
190impl From<BindingIdent> for Ident {
191    fn from(bi: BindingIdent) -> Self {
192        bi.id
193    }
194}
195
196impl From<Atom> for Ident {
197    fn from(bi: Atom) -> Self {
198        Ident::new_no_ctxt(bi, DUMMY_SP)
199    }
200}
201bridge_from!(Ident, Atom, &'_ str);
202bridge_from!(Ident, Atom, Cow<'_, str>);
203bridge_from!(Ident, Atom, String);
204
205impl From<(Atom, Span)> for Ident {
206    fn from((sym, span): (Atom, Span)) -> Self {
207        Ident {
208            span,
209            sym,
210            ..Default::default()
211        }
212    }
213}
214
215impl EqIgnoreSpan for Ident {
216    fn eq_ignore_span(&self, other: &Self) -> bool {
217        if self.sym != other.sym {
218            return false;
219        }
220
221        self.ctxt.eq_ignore_span(&other.ctxt)
222    }
223}
224
225impl From<Id> for Ident {
226    fn from(id: Id) -> Self {
227        Ident::new(id.0, DUMMY_SP, id.1)
228    }
229}
230
231impl From<Ident> for Id {
232    fn from(i: Ident) -> Self {
233        (i.sym, i.ctxt)
234    }
235}
236
237#[repr(C, align(64))]
238struct Align64<T>(pub(crate) T);
239
240const T: bool = true;
241const F: bool = false;
242
243impl Ident {
244    /// In `op`, [EqIgnoreSpan] of [Ident] will ignore the syntax context.
245    pub fn within_ignored_ctxt<F, Ret>(op: F) -> Ret
246    where
247        F: FnOnce() -> Ret,
248    {
249        SyntaxContext::within_ignored_ctxt(op)
250    }
251
252    /// Preserve syntax context while drop `span.lo` and `span.hi`.
253    pub fn without_loc(mut self) -> Ident {
254        self.span.lo = BytePos::DUMMY;
255        self.span.hi = BytePos::DUMMY;
256        self
257    }
258
259    /// Creates `Id` using `Atom` and `SyntaxContext` of `self`.
260    pub fn to_id(&self) -> Id {
261        (self.sym.clone(), self.ctxt)
262    }
263
264    #[inline]
265    pub fn is_valid_ascii_start(c: u8) -> bool {
266        debug_assert!(c.is_ascii());
267        // This contains `$` (36) and `_` (95)
268        const ASCII_START: Align64<[bool; 128]> = Align64([
269            F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F,
270            F, F, F, F, F, F, F, T, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F,
271            F, F, F, F, F, F, F, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T,
272            T, T, T, T, F, F, F, F, T, F, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T,
273            T, T, T, T, T, T, T, F, F, F, F, F,
274        ]);
275        ASCII_START.0[c as usize]
276    }
277
278    pub fn is_valid_non_ascii_start(c: char) -> bool {
279        debug_assert!(!c.is_ascii());
280        unicode_id_start::is_id_start_unicode(c)
281    }
282
283    /// Returns true if `c` is a valid character for an identifier start.
284    #[inline]
285    pub fn is_valid_start(c: char) -> bool {
286        if c.is_ascii() {
287            Self::is_valid_ascii_start(c as u8)
288        } else {
289            Self::is_valid_non_ascii_start(c)
290        }
291    }
292
293    #[inline]
294    pub fn is_valid_non_ascii_continue(c: char) -> bool {
295        debug_assert!(!c.is_ascii());
296        unicode_id_start::is_id_continue_unicode(c)
297    }
298
299    #[inline]
300    pub fn is_valid_ascii_continue(c: u8) -> bool {
301        debug_assert!(c.is_ascii());
302        // This contains `$` (36)
303        const ASCII_CONTINUE: Align64<[bool; 128]> = Align64([
304            F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F,
305            F, F, F, F, F, F, F, T, F, F, F, F, F, F, F, F, F, F, F, T, T, T, T, T, T, T, T, T, T,
306            F, F, F, F, F, F, F, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T,
307            T, T, T, T, F, F, F, F, T, F, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T,
308            T, T, T, T, T, T, T, F, F, F, F, F,
309        ]);
310        ASCII_CONTINUE.0[c as usize]
311    }
312
313    /// Returns true if `c` is a valid character for an identifier part after
314    /// start.
315    #[inline]
316    pub fn is_valid_continue(c: char) -> bool {
317        if c.is_ascii() {
318            Self::is_valid_ascii_continue(c as u8)
319        } else {
320            Self::is_valid_non_ascii_continue(c)
321        }
322    }
323
324    /// Alternative for `toIdentifier` of babel.
325    ///
326    /// Returns [Ok] if it's a valid identifier and [Err] if it's not valid.
327    /// The returned [Err] contains the valid symbol.
328    pub fn verify_symbol(s: &str) -> Result<(), String> {
329        fn is_reserved_symbol(s: &str) -> bool {
330            s.is_reserved() || s.is_reserved_in_strict_mode(true) || s.is_reserved_in_strict_bind()
331        }
332
333        if is_reserved_symbol(s) {
334            let mut buf = String::with_capacity(s.len() + 1);
335            buf.push('_');
336            buf.push_str(s);
337            return Err(buf);
338        }
339
340        {
341            let mut chars = s.chars();
342
343            if let Some(first) = chars.next() {
344                if Self::is_valid_start(first) && chars.all(Self::is_valid_continue) {
345                    return Ok(());
346                }
347            }
348        }
349
350        let mut buf = String::with_capacity(s.len() + 2);
351        let mut has_start = false;
352
353        for c in s.chars() {
354            if !has_start && Self::is_valid_start(c) {
355                has_start = true;
356                buf.push(c);
357                continue;
358            }
359
360            if Self::is_valid_continue(c) {
361                buf.push(c);
362            }
363        }
364
365        if buf.is_empty() {
366            buf.push('_');
367        }
368
369        if is_reserved_symbol(&buf) {
370            let mut new_buf = String::with_capacity(buf.len() + 1);
371            new_buf.push('_');
372            new_buf.push_str(&buf);
373            buf = new_buf;
374        }
375
376        Err(buf)
377    }
378
379    /// Create a new identifier with the given prefix.
380    pub fn with_prefix(&self, prefix: &str) -> Ident {
381        Ident::new(
382            format!("{}{}", prefix, self.sym).into(),
383            self.span,
384            self.ctxt,
385        )
386    }
387
388    /// Create a private identifier that is unique in the file, but with the
389    /// same symbol.
390    pub fn into_private(self) -> Ident {
391        Self::new(
392            self.sym,
393            self.span,
394            SyntaxContext::empty().apply_mark(Mark::new()),
395        )
396    }
397
398    #[inline]
399    pub fn is_dummy(&self) -> bool {
400        self.sym == atom!("") && self.span.is_dummy()
401    }
402
403    /// Create a new identifier with the given position.
404    pub fn with_pos(mut self, lo: BytePos, hi: BytePos) -> Ident {
405        self.span = Span::new(lo, hi);
406        self
407    }
408}
409
410#[ast_node("Identifier")]
411#[derive(Eq, Hash, Default, EqIgnoreSpan)]
412#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
413#[cfg_attr(feature = "shrink-to-fit", derive(shrink_to_fit::ShrinkToFit))]
414pub struct IdentName {
415    #[cfg_attr(feature = "__rkyv", rkyv(omit_bounds))]
416    pub span: Span,
417
418    #[cfg_attr(feature = "serde-impl", serde(rename = "value"))]
419    pub sym: Atom,
420}
421
422impl From<Atom> for IdentName {
423    fn from(sym: Atom) -> Self {
424        IdentName {
425            span: DUMMY_SP,
426            sym,
427        }
428    }
429}
430
431impl From<(Atom, Span)> for IdentName {
432    fn from((sym, span): (Atom, Span)) -> Self {
433        IdentName { span, sym }
434    }
435}
436
437bridge_from!(IdentName, Atom, &'_ str);
438bridge_from!(IdentName, Atom, Cow<'_, str>);
439bridge_from!(IdentName, Atom, String);
440bridge_from!(IdentName, Ident, &'_ BindingIdent);
441bridge_from!(IdentName, Ident, BindingIdent);
442
443impl AsRef<str> for IdentName {
444    fn as_ref(&self) -> &str {
445        &self.sym
446    }
447}
448
449impl IdentName {
450    pub const fn new(sym: Atom, span: Span) -> Self {
451        Self { span, sym }
452    }
453}
454
455impl Take for IdentName {
456    fn dummy() -> Self {
457        Default::default()
458    }
459}
460
461impl From<Ident> for IdentName {
462    fn from(i: Ident) -> Self {
463        IdentName {
464            span: i.span,
465            sym: i.sym,
466        }
467    }
468}
469
470impl From<IdentName> for Ident {
471    fn from(i: IdentName) -> Self {
472        Ident {
473            span: i.span,
474            sym: i.sym,
475            ..Default::default()
476        }
477    }
478}
479
480bridge_from!(BindingIdent, Ident, Atom);
481bridge_from!(BindingIdent, Atom, &'_ str);
482bridge_from!(BindingIdent, Atom, Cow<'_, str>);
483bridge_from!(BindingIdent, Atom, String);
484
485impl From<IdentName> for BindingIdent {
486    fn from(i: IdentName) -> Self {
487        BindingIdent {
488            id: i.into(),
489            ..Default::default()
490        }
491    }
492}
493
494/// UnsafeId is a wrapper around [Id] that does not allocate, but extremely
495/// unsafe.
496///
497/// Do not use this unless you know what you are doing.
498///
499/// **Currently, it's considered as a unstable API and may be changed in the
500/// future without a semver bump.**
501pub type UnsafeId = (UnsafeAtom, SyntaxContext);
502
503/// This is extremely unsafe so don't use it unless you know what you are doing.
504///
505/// # Safety
506///
507/// See [`UnsafeAtom::new`] for constraints.
508///
509/// **Currently, it's considered as a unstable API and may be changed in the
510/// future without a semver bump.**
511pub unsafe fn unsafe_id(id: &Id) -> UnsafeId {
512    (UnsafeAtom::new(&id.0), id.1)
513}
514
515/// This is extremely unsafe so don't use it unless you know what you are doing.
516///
517/// # Safety
518///
519/// See [`UnsafeAtom::new`] for constraints.
520///
521/// **Currently, it's considered as a unstable API and may be changed in the
522/// future without a semver bump.**
523pub unsafe fn unsafe_id_from_ident(id: &Ident) -> UnsafeId {
524    (UnsafeAtom::new(&id.sym), id.ctxt)
525}
526
527/// See [Ident] for documentation.
528pub type Id = (Atom, SyntaxContext);
529
530impl Take for Ident {
531    fn dummy() -> Self {
532        Ident::new_no_ctxt(atom!(""), DUMMY_SP)
533    }
534}
535
536impl Display for Ident {
537    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
538        write!(f, "{}{:?}", self.sym, self.ctxt)
539    }
540}
541
542impl Display for IdentName {
543    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
544        write!(f, "{}", self.sym)
545    }
546}
547
548impl Display for BindingIdent {
549    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
550        write!(f, "{}{:?}", self.sym, self.ctxt)
551    }
552}
553
554#[cfg(feature = "arbitrary")]
555#[cfg_attr(docsrs, doc(cfg(feature = "arbitrary")))]
556impl<'a> arbitrary::Arbitrary<'a> for Ident {
557    fn arbitrary(u: &mut arbitrary::Unstructured<'_>) -> arbitrary::Result<Self> {
558        let span = u.arbitrary()?;
559        let sym = u.arbitrary::<Atom>()?;
560
561        let optional = u.arbitrary()?;
562
563        Ok(Self {
564            span,
565            sym,
566            optional,
567            ctxt: Default::default(),
568        })
569    }
570}
571
572#[ast_node("PrivateName")]
573#[derive(Eq, Hash, EqIgnoreSpan, Default)]
574#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
575#[cfg_attr(feature = "shrink-to-fit", derive(shrink_to_fit::ShrinkToFit))]
576pub struct PrivateName {
577    pub span: Span,
578    #[cfg_attr(feature = "serde-impl", serde(rename = "value"))]
579    pub name: Atom,
580}
581
582impl AsRef<str> for Ident {
583    fn as_ref(&self) -> &str {
584        &self.sym
585    }
586}
587
588impl Ident {
589    pub const fn new(sym: Atom, span: Span, ctxt: SyntaxContext) -> Self {
590        Ident {
591            span,
592            ctxt,
593            sym,
594            optional: false,
595        }
596    }
597
598    /// Creates a new private identifier. A private identifier is an identifier
599    /// that is guaranteed to be unique.
600    ///
601    /// See https://swc.rs/docs/contributing/es-commons/variable-management for more details.
602    ///
603    /// Note: This method requires configuring
604    /// [GLOBALS](`swc_common::GLOBALS`) because this method use [`Mark::new`]
605    /// internally.
606    #[inline(never)]
607    pub fn new_private(sym: Atom, span: Span) -> Self {
608        Self::new(sym, span, SyntaxContext::empty().apply_mark(Mark::new()))
609    }
610
611    pub const fn new_no_ctxt(sym: Atom, span: Span) -> Self {
612        Self::new(sym, span, SyntaxContext::empty())
613    }
614}
615
616macro_rules! gen_reserved_set {
617    ($set: ident, $set_atoms: ident, [$($item: expr),*]) => {
618        static $set: phf::Set<&str> = phf_set!($($item),*);
619        static $set_atoms: Lazy<FxHashSet<Atom>> = Lazy::new(|| {
620            let mut set = FxHashSet::with_capacity_and_hasher($set.len(), rustc_hash::FxBuildHasher);
621            $(
622                set.insert(atom!($item));
623            )*
624            set
625        });
626    };
627}
628
629gen_reserved_set!(
630    RESERVED,
631    RESERVED_ATOMS,
632    [
633        "break",
634        "case",
635        "catch",
636        "class",
637        "const",
638        "continue",
639        "debugger",
640        "default",
641        "delete",
642        "do",
643        "else",
644        "enum",
645        "export",
646        "extends",
647        "false",
648        "finally",
649        "for",
650        "function",
651        "if",
652        "import",
653        "in",
654        "instanceof",
655        "new",
656        "null",
657        "package",
658        "return",
659        "super",
660        "switch",
661        "this",
662        "throw",
663        "true",
664        "try",
665        "typeof",
666        "var",
667        "void",
668        "while",
669        "with"
670    ]
671);
672
673gen_reserved_set!(
674    RESSERVED_IN_STRICT_MODE,
675    RESSERVED_IN_STRICT_MODE_ATOMS,
676    [
677        "implements",
678        "interface",
679        "let",
680        "package",
681        "private",
682        "protected",
683        "public",
684        "static",
685        "yield"
686    ]
687);
688
689gen_reserved_set!(
690    RESSERVED_IN_STRICT_BIND,
691    RESSERVED_IN_STRICT_BIND_ATOMS,
692    ["eval", "arguments"]
693);
694
695gen_reserved_set!(
696    RESERVED_IN_ES3,
697    RESERVED_IN_ES3_ATOMS,
698    [
699        "abstract",
700        "boolean",
701        "byte",
702        "char",
703        "double",
704        "final",
705        "float",
706        "goto",
707        "int",
708        "long",
709        "native",
710        "short",
711        "synchronized",
712        "throws",
713        "transient",
714        "volatile"
715    ]
716);
717
718pub trait EsReserved {
719    fn is_reserved(&self) -> bool;
720    fn is_reserved_in_strict_mode(&self, is_module: bool) -> bool;
721    fn is_reserved_in_strict_bind(&self) -> bool;
722    fn is_reserved_in_es3(&self) -> bool;
723    fn is_reserved_in_any(&self) -> bool;
724}
725
726impl EsReserved for Atom {
727    fn is_reserved(&self) -> bool {
728        is_reserved_for_atom(self)
729    }
730
731    fn is_reserved_in_strict_mode(&self, is_module: bool) -> bool {
732        is_reserved_in_strict_mode_for_atom(self, is_module)
733    }
734
735    fn is_reserved_in_strict_bind(&self) -> bool {
736        is_reserved_in_strict_bind_for_atom(self)
737    }
738
739    fn is_reserved_in_es3(&self) -> bool {
740        is_reserved_in_es3_for_atom(self)
741    }
742
743    fn is_reserved_in_any(&self) -> bool {
744        is_reserved_in_any_for_atom(self)
745    }
746}
747impl EsReserved for IdentName {
748    fn is_reserved(&self) -> bool {
749        is_reserved_for_atom(&self.sym)
750    }
751
752    fn is_reserved_in_strict_mode(&self, is_module: bool) -> bool {
753        is_reserved_in_strict_mode_for_atom(&self.sym, is_module)
754    }
755
756    fn is_reserved_in_strict_bind(&self) -> bool {
757        is_reserved_in_strict_bind_for_atom(&self.sym)
758    }
759
760    fn is_reserved_in_es3(&self) -> bool {
761        is_reserved_in_es3_for_atom(&self.sym)
762    }
763
764    fn is_reserved_in_any(&self) -> bool {
765        is_reserved_in_any_for_atom(&self.sym)
766    }
767}
768impl EsReserved for Ident {
769    fn is_reserved(&self) -> bool {
770        is_reserved_for_atom(&self.sym)
771    }
772
773    fn is_reserved_in_strict_mode(&self, is_module: bool) -> bool {
774        is_reserved_in_strict_mode_for_atom(&self.sym, is_module)
775    }
776
777    fn is_reserved_in_strict_bind(&self) -> bool {
778        is_reserved_in_strict_bind_for_atom(&self.sym)
779    }
780
781    fn is_reserved_in_es3(&self) -> bool {
782        is_reserved_in_es3_for_atom(&self.sym)
783    }
784
785    fn is_reserved_in_any(&self) -> bool {
786        is_reserved_in_any_for_atom(&self.sym)
787    }
788}
789impl EsReserved for BindingIdent {
790    fn is_reserved(&self) -> bool {
791        is_reserved_for_atom(&self.sym)
792    }
793
794    fn is_reserved_in_strict_mode(&self, is_module: bool) -> bool {
795        is_reserved_in_strict_mode_for_atom(&self.sym, is_module)
796    }
797
798    fn is_reserved_in_strict_bind(&self) -> bool {
799        is_reserved_in_strict_bind_for_atom(&self.sym)
800    }
801
802    fn is_reserved_in_es3(&self) -> bool {
803        is_reserved_in_es3_for_atom(&self.sym)
804    }
805
806    fn is_reserved_in_any(&self) -> bool {
807        is_reserved_in_any_for_atom(&self.sym)
808    }
809}
810impl EsReserved for &'_ str {
811    fn is_reserved(&self) -> bool {
812        is_reserved_for_str(self)
813    }
814
815    fn is_reserved_in_strict_mode(&self, is_module: bool) -> bool {
816        is_reserved_in_strict_mode_for_str(self, is_module)
817    }
818
819    fn is_reserved_in_strict_bind(&self) -> bool {
820        is_reserved_in_strict_bind_for_str(self)
821    }
822
823    fn is_reserved_in_es3(&self) -> bool {
824        is_reserved_in_es3_for_str(self)
825    }
826
827    fn is_reserved_in_any(&self) -> bool {
828        is_reserved_in_any_for_str(self)
829    }
830}
831impl EsReserved for String {
832    fn is_reserved(&self) -> bool {
833        is_reserved_for_str(self)
834    }
835
836    fn is_reserved_in_strict_mode(&self, is_module: bool) -> bool {
837        is_reserved_in_strict_mode_for_str(self, is_module)
838    }
839
840    fn is_reserved_in_strict_bind(&self) -> bool {
841        is_reserved_in_strict_bind_for_str(self)
842    }
843
844    fn is_reserved_in_es3(&self) -> bool {
845        is_reserved_in_es3_for_str(self)
846    }
847
848    fn is_reserved_in_any(&self) -> bool {
849        is_reserved_in_any_for_str(self)
850    }
851}
852
853fn is_reserved_for_str(n: impl AsRef<str>) -> bool {
854    RESERVED.contains(n.as_ref())
855}
856
857fn is_reserved_in_strict_mode_for_str(n: impl AsRef<str>, is_module: bool) -> bool {
858    if is_module && n.as_ref() == "await" {
859        return true;
860    }
861    RESSERVED_IN_STRICT_MODE.contains(n.as_ref())
862}
863
864fn is_reserved_in_strict_bind_for_str(n: impl AsRef<str>) -> bool {
865    RESSERVED_IN_STRICT_BIND.contains(n.as_ref())
866}
867
868fn is_reserved_in_es3_for_str(n: impl AsRef<str>) -> bool {
869    RESERVED_IN_ES3.contains(n.as_ref())
870}
871
872fn is_reserved_in_any_for_str(n: impl AsRef<str>) -> bool {
873    RESERVED.contains(n.as_ref())
874        || RESSERVED_IN_STRICT_MODE.contains(n.as_ref())
875        || RESSERVED_IN_STRICT_BIND.contains(n.as_ref())
876        || RESERVED_IN_ES3.contains(n.as_ref())
877}
878
879fn is_reserved_for_atom(n: &Atom) -> bool {
880    RESERVED_ATOMS.contains(n)
881}
882
883fn is_reserved_in_strict_mode_for_atom(n: &Atom, is_module: bool) -> bool {
884    if is_module && *n == atom!("await") {
885        return true;
886    }
887    RESSERVED_IN_STRICT_MODE_ATOMS.contains(n)
888}
889
890fn is_reserved_in_strict_bind_for_atom(n: &Atom) -> bool {
891    RESSERVED_IN_STRICT_BIND_ATOMS.contains(n)
892}
893
894fn is_reserved_in_es3_for_atom(n: &Atom) -> bool {
895    RESERVED_IN_ES3_ATOMS.contains(n)
896}
897
898fn is_reserved_in_any_for_atom(n: &Atom) -> bool {
899    RESERVED_ATOMS.contains(n)
900        || RESSERVED_IN_STRICT_MODE_ATOMS.contains(n)
901        || RESSERVED_IN_STRICT_BIND_ATOMS.contains(n)
902        || RESERVED_IN_ES3_ATOMS.contains(n)
903}