Skip to main content

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