Skip to main content

boa_interner/
sym.rs

1use boa_gc::{Finalize, Trace, empty_trace};
2use boa_macros::static_syms;
3use core::num::NonZeroUsize;
4
5/// The string symbol type for Boa.
6///
7/// This symbol type is internally a `NonZeroUsize`, which makes it pointer-width in size and it's
8/// optimized so that it can occupy 1 pointer width even in an `Option` type.
9#[cfg_attr(
10    feature = "serde",
11    derive(serde::Serialize, serde::Deserialize),
12    serde(transparent)
13)]
14#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
15#[allow(clippy::unsafe_derive_deserialize)]
16#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Finalize)]
17pub struct Sym {
18    value: NonZeroUsize,
19}
20
21// SAFETY: `NonZeroUsize` is a constrained `usize`, and all primitive types don't need to be traced
22// by the garbage collector.
23unsafe impl Trace for Sym {
24    empty_trace!();
25}
26
27impl Sym {
28    /// Creates a new [`Sym`] from the provided `value`, or returns `None` if `index` is zero.
29    pub(super) fn new(value: usize) -> Option<Self> {
30        NonZeroUsize::new(value).map(|value| Self { value })
31    }
32
33    /// Creates a new [`Sym`] from the provided `value`, without checking if `value` is not zero
34    ///
35    /// # Safety
36    ///
37    /// `value` must not be zero.
38    pub(super) const unsafe fn new_unchecked(value: usize) -> Self {
39        Self {
40            value:
41            // SAFETY: The caller must ensure the invariants of the function.
42            unsafe {
43                NonZeroUsize::new_unchecked(value)
44            },
45        }
46    }
47
48    /// Checks if this symbol is one of the [reserved identifiers][spec] of the ECMAScript
49    /// specification, excluding `await` and `yield`
50    ///
51    /// [spec]: https://tc39.es/ecma262/#prod-ReservedWord
52    #[inline]
53    #[must_use]
54    pub fn is_reserved_identifier(self) -> bool {
55        (Self::BREAK..=Self::WITH).contains(&self)
56    }
57
58    /// Checks if this symbol is one of the [strict reserved identifiers][spec] of the ECMAScript
59    /// specification.
60    ///
61    /// [spec]: https://tc39.es/ecma262/#prod-ReservedWord
62    #[inline]
63    #[must_use]
64    pub fn is_strict_reserved_identifier(self) -> bool {
65        (Self::IMPLEMENTS..=Self::YIELD).contains(&self)
66    }
67
68    /// Returns the internal value of the [`Sym`]
69    #[inline]
70    #[must_use]
71    pub const fn get(self) -> usize {
72        self.value.get()
73    }
74}
75
76static_syms! {
77    // Reserved identifiers
78    // See: <https://tc39.es/ecma262/#prod-ReservedWord>
79    // Note, they must all be together.
80    "break",
81    "case",
82    "catch",
83    "class",
84    "const",
85    "continue",
86    "debugger",
87    "default",
88    "delete",
89    "do",
90    "else",
91    "enum",
92    "export",
93    "extends",
94    "false",
95    "finally",
96    "for",
97    "function",
98    "if",
99    "import",
100    "in",
101    "instanceof",
102    "new",
103    "null",
104    "return",
105    "super",
106    "switch",
107    "this",
108    "throw",
109    "true",
110    "try",
111    "typeof",
112    "var",
113    "void",
114    "while",
115    "with",
116    // End reserved identifier
117
118    // strict reserved identifiers.
119    // See: <https://tc39.es/ecma262/#prod-Identifier>
120    // Note, they must all be together.
121    "implements",
122    "interface",
123    "let",
124    "package",
125    "private",
126    "protected",
127    "public",
128    "static",
129    "yield",
130    // End strict reserved identifiers
131
132    ("", EMPTY_STRING),
133    "prototype",
134    "constructor",
135    "arguments",
136    "eval",
137    "RegExp",
138    "get",
139    "set",
140    ("<main>", MAIN),
141    "raw",
142    "anonymous",
143    "async",
144    "of",
145    "target",
146    "as",
147    "from",
148    "__proto__",
149    "name",
150    "await",
151    ("*default*", DEFAULT_EXPORT),
152    "meta",
153    "defer",
154    "source",
155    "using",
156    "dispose",
157    "asyncDispose"
158}