Skip to main content

boa_ast/expression/
identifier.rs

1//! Local identifier Expression.
2
3use crate::{
4    Span, Spanned, ToStringEscaped,
5    visitor::{VisitWith, Visitor, VisitorMut},
6};
7use boa_interner::{Interner, Sym, ToInternedString};
8use core::ops::ControlFlow;
9
10use super::Expression;
11
12/// List of reserved keywords exclusive to strict mode.
13pub const RESERVED_IDENTIFIERS_STRICT: [Sym; 9] = [
14    Sym::IMPLEMENTS,
15    Sym::INTERFACE,
16    Sym::LET,
17    Sym::PACKAGE,
18    Sym::PRIVATE,
19    Sym::PROTECTED,
20    Sym::PUBLIC,
21    Sym::STATIC,
22    Sym::YIELD,
23];
24
25/// An `identifier` is a sequence of characters in the code that identifies a variable,
26/// function, or property.
27///
28/// In ECMAScript, identifiers are case-sensitive and can contain Unicode letters, $, _, and
29/// digits (0-9), but may not start with a digit.
30///
31/// An identifier differs from a string in that a string is data, while an identifier is part
32/// of the code. In JavaScript, there is no way to convert identifiers to strings, but
33/// sometimes it is possible to parse strings into identifiers.
34///
35/// More information:
36///  - [ECMAScript reference][spec]
37///  - [MDN documentation][mdn]
38///
39/// [spec]: https://tc39.es/ecma262/#prod-Identifier
40/// [mdn]: https://developer.mozilla.org/en-US/docs/Glossary/Identifier
41#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
42#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
43#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
44pub struct Identifier {
45    ident: Sym,
46    span: Span,
47}
48
49impl PartialEq<Sym> for Identifier {
50    #[inline]
51    fn eq(&self, other: &Sym) -> bool {
52        self.ident == *other
53    }
54}
55
56impl PartialEq<Identifier> for Sym {
57    #[inline]
58    fn eq(&self, other: &Identifier) -> bool {
59        *self == other.ident
60    }
61}
62
63impl Identifier {
64    /// Creates a new identifier AST Expression.
65    #[inline]
66    #[must_use]
67    pub const fn new(ident: Sym, span: Span) -> Self {
68        Self { ident, span }
69    }
70
71    /// Retrieves the identifier's string symbol in the interner.
72    #[inline]
73    #[must_use]
74    pub const fn sym(self) -> Sym {
75        self.ident
76    }
77
78    /// Retrieves the identifier's string symbol in the interner.
79    #[inline]
80    #[must_use]
81    pub const fn sym_ref(&self) -> &Sym {
82        &self.ident
83    }
84
85    /// Retrieves the identifier's string symbol in the interner.
86    #[inline]
87    #[must_use]
88    pub const fn sym_mut(&mut self) -> &mut Sym {
89        &mut self.ident
90    }
91}
92
93impl Spanned for Identifier {
94    #[inline]
95    fn span(&self) -> Span {
96        self.span
97    }
98}
99
100impl ToInternedString for Identifier {
101    #[inline]
102    fn to_interned_string(&self, interner: &Interner) -> String {
103        interner.resolve_expect(self.ident).join(
104            String::from,
105            ToStringEscaped::to_string_escaped,
106            true,
107        )
108    }
109}
110
111impl From<Identifier> for Expression {
112    #[inline]
113    fn from(local: Identifier) -> Self {
114        Self::Identifier(local)
115    }
116}
117
118impl VisitWith for Identifier {
119    fn visit_with<'a, V>(&'a self, visitor: &mut V) -> ControlFlow<V::BreakTy>
120    where
121        V: Visitor<'a>,
122    {
123        visitor.visit_sym(&self.ident)
124    }
125
126    fn visit_with_mut<'a, V>(&'a mut self, visitor: &mut V) -> ControlFlow<V::BreakTy>
127    where
128        V: VisitorMut<'a>,
129    {
130        visitor.visit_sym_mut(&mut self.ident)
131    }
132}