1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
use boa_gc::{empty_trace, Finalize, Trace};
use boa_macros::static_syms;
use core::num::NonZeroUsize;

/// The string symbol type for Boa.
///
/// This symbol type is internally a `NonZeroUsize`, which makes it pointer-width in size and it's
/// optimized so that it can occupy 1 pointer width even in an `Option` type.
#[cfg_attr(
    feature = "serde",
    derive(serde::Serialize, serde::Deserialize),
    serde(transparent)
)]
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
#[allow(clippy::unsafe_derive_deserialize)]
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Finalize)]
pub struct Sym {
    value: NonZeroUsize,
}

// SAFETY: `NonZeroUsize` is a constrained `usize`, and all primitive types don't need to be traced
// by the garbage collector.
unsafe impl Trace for Sym {
    empty_trace!();
}

impl Sym {
    /// Creates a new [`Sym`] from the provided `value`, or returns `None` if `index` is zero.
    pub(super) fn new(value: usize) -> Option<Self> {
        NonZeroUsize::new(value).map(|value| Self { value })
    }

    /// Creates a new [`Sym`] from the provided `value`, without checking if `value` is not zero
    ///
    /// # Safety
    ///
    /// `value` must not be zero.
    pub(super) const unsafe fn new_unchecked(value: usize) -> Self {
        Self {
            value:
            // SAFETY: The caller must ensure the invariants of the function.
            unsafe {
                NonZeroUsize::new_unchecked(value)
            },
        }
    }

    /// Checks if this symbol is one of the [reserved identifiers][spec] of the ECMAScript
    /// specification, excluding `await` and `yield`
    ///
    /// [spec]: https://tc39.es/ecma262/#prod-ReservedWord
    #[inline]
    #[must_use]
    pub fn is_reserved_identifier(self) -> bool {
        (Self::BREAK..=Self::WITH).contains(&self)
    }

    /// Checks if this symbol is one of the [strict reserved identifiers][spec] of the ECMAScript
    /// specification.
    ///
    /// [spec]: https://tc39.es/ecma262/#prod-ReservedWord
    #[inline]
    #[must_use]
    pub fn is_strict_reserved_identifier(self) -> bool {
        (Self::IMPLEMENTS..=Self::YIELD).contains(&self)
    }

    /// Returns the internal value of the [`Sym`]
    #[inline]
    #[must_use]
    pub const fn get(self) -> usize {
        self.value.get()
    }
}

static_syms! {
    // Reserved identifiers
    // See: <https://tc39.es/ecma262/#prod-ReservedWord>
    // Note, they must all be together.
    "break",
    "case",
    "catch",
    "class",
    "const",
    "continue",
    "debugger",
    "default",
    "delete",
    "do",
    "else",
    "enum",
    "export",
    "extends",
    "false",
    "finally",
    "for",
    "function",
    "if",
    "import",
    "in",
    "instanceof",
    "new",
    "null",
    "return",
    "super",
    "switch",
    "this",
    "throw",
    "true",
    "try",
    "typeof",
    "var",
    "void",
    "while",
    "with",
    // End reserved identifier

    // strict reserved identifiers.
    // See: <https://tc39.es/ecma262/#prod-Identifier>
    // Note, they must all be together.
    "implements",
    "interface",
    "let",
    "package",
    "private",
    "protected",
    "public",
    "static",
    "yield",
    // End strict reserved identifiers

    ("", EMPTY_STRING),
    "prototype",
    "constructor",
    "arguments",
    "eval",
    "RegExp",
    "get",
    "set",
    ("<main>", MAIN),
    "raw",
    "anonymous",
    "async",
    "of",
    "target",
    "as",
    "from",
    "__proto__",
    "name",
    "await",
    ("*default*", DEFAULT_EXPORT),
    "meta"
}