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"
}