1#![expect(missing_docs)] use bitflags::bitflags;
3use nonmax::NonMaxU32;
4use oxc_allocator::{Allocator, CloneIn};
5use oxc_index::Idx;
6#[cfg(feature = "serialize")]
7use serde::{Serialize, Serializer};
8
9use oxc_ast_macros::ast;
10
11#[ast]
12#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash)]
13#[builder(default)]
14#[clone_in(default)]
15#[content_eq(skip)]
16#[estree(skip)]
17pub struct SymbolId(NonMaxU32);
18
19impl SymbolId {
20 pub const fn new(idx: u32) -> Self {
25 if let Some(idx) = NonMaxU32::new(idx) {
26 return Self(idx);
27 }
28 panic!();
29 }
30
31 pub const unsafe fn new_unchecked(idx: u32) -> Self {
36 unsafe { Self(NonMaxU32::new_unchecked(idx)) }
38 }
39}
40
41impl Idx for SymbolId {
42 #[expect(clippy::cast_possible_truncation)]
43 fn from_usize(idx: usize) -> Self {
44 assert!(idx < u32::MAX as usize);
45 Self(unsafe { NonMaxU32::new_unchecked(idx as u32) })
47 }
48
49 fn index(self) -> usize {
50 self.0.get() as usize
51 }
52}
53
54impl<'alloc> CloneIn<'alloc> for SymbolId {
55 type Cloned = Self;
56
57 fn clone_in(&self, _: &'alloc Allocator) -> Self {
58 unreachable!();
60 }
61
62 #[expect(clippy::inline_always)]
63 #[inline(always)]
64 fn clone_in_with_semantic_ids(&self, _: &'alloc Allocator) -> Self {
65 *self
66 }
67}
68
69#[cfg(feature = "serialize")]
70impl Serialize for SymbolId {
71 fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
72 serializer.serialize_u32(self.0.get())
73 }
74}
75
76#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash)]
77pub struct RedeclarationId(NonMaxU32);
78
79impl Idx for RedeclarationId {
80 #[expect(clippy::cast_possible_truncation)]
81 fn from_usize(idx: usize) -> Self {
82 assert!(idx < u32::MAX as usize);
83 Self(unsafe { NonMaxU32::new_unchecked(idx as u32) })
85 }
86
87 fn index(self) -> usize {
88 self.0.get() as usize
89 }
90}
91
92#[cfg(feature = "serialize")]
93impl Serialize for RedeclarationId {
94 fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
95 serializer.serialize_u32(self.0.get())
96 }
97}
98
99bitflags! {
100 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
101 #[cfg_attr(feature = "serialize", derive(Serialize))]
102 pub struct SymbolFlags: u32 {
103 const None = 0;
104 const FunctionScopedVariable = 1 << 0;
106 const BlockScopedVariable = 1 << 1;
108 const ConstVariable = 1 << 2;
110 const Class = 1 << 3;
111 const CatchVariable = 1 << 4;
113 const Function = 1 << 5;
115 const Import = 1 << 6;
117 const TypeImport = 1 << 7;
119 const TypeAlias = 1 << 8;
121 const Interface = 1 << 9;
122 const RegularEnum = 1 << 10;
123 const ConstEnum = 1 << 11;
124 const EnumMember = 1 << 12;
125 const TypeParameter = 1 << 13;
126 const NamespaceModule = 1 << 14;
128 const ValueModule = 1 << 15;
130 const Ambient = 1 << 16;
137
138 const Enum = Self::ConstEnum.bits() | Self::RegularEnum.bits();
139 const Variable = Self::FunctionScopedVariable.bits() | Self::BlockScopedVariable.bits();
140
141 const BlockScoped = Self::BlockScopedVariable.bits() | Self::Enum.bits() | Self::Class.bits();
142
143 const Value = Self::Variable.bits() | Self::Class.bits() | Self::Function.bits() | Self::Enum.bits() | Self::EnumMember.bits() | Self::ValueModule.bits();
144 const Type = Self::Class.bits() | Self::Interface.bits() | Self::Enum.bits() | Self::EnumMember.bits() | Self::TypeParameter.bits() | Self::TypeAlias.bits();
145 const Namespace = Self::ValueModule.bits() | Self::NamespaceModule.bits() | Self::Enum.bits();
146
147
148 const FunctionScopedVariableExcludes = Self::Value.bits() - Self::FunctionScopedVariable.bits() - Self::Function.bits();
151
152 const BlockScopedVariableExcludes = Self::Value.bits();
155 const FunctionExcludes = Self::Value.bits() & !(Self::Function.bits() | Self::ValueModule.bits() | Self::Class.bits());
156 const ClassExcludes = (Self::Value.bits() | Self::Type.bits()) & !(Self::ValueModule.bits() | Self::Function.bits() | Self::Interface.bits());
157
158 const ImportBindingExcludes = Self::Import.bits() | Self::TypeImport.bits();
159 const TypeAliasExcludes = Self::Type.bits();
161 const InterfaceExcludes = Self::Type.bits() & !(Self::Interface.bits() | Self::Class.bits());
162 const TypeParameterExcludes = Self::Type.bits() & !Self::TypeParameter.bits();
163 const ConstEnumExcludes = (Self::Type.bits() | Self::Value.bits()) & !Self::ConstEnum.bits();
164 const ValueModuleExcludes = Self::Value.bits() & !(Self::Function.bits() | Self::Class.bits() | Self::RegularEnum.bits() | Self::ValueModule.bits());
165 const NamespaceModuleExcludes = 0;
166 const RegularEnumExcludes = (Self::Value.bits() | Self::Type.bits()) & !(Self::RegularEnum.bits() | Self::ValueModule.bits() );
168 const EnumMemberExcludes = Self::EnumMember.bits();
169
170 }
171}
172
173impl SymbolFlags {
174 #[inline]
175 pub fn is_variable(self) -> bool {
176 self.intersects(Self::Variable)
177 }
178
179 #[inline]
180 pub fn is_type_parameter(self) -> bool {
181 self.contains(Self::TypeParameter)
182 }
183
184 #[inline]
186 pub fn is_type(self) -> bool {
187 self.intersects((Self::TypeImport | Self::Type) - Self::Value)
188 }
189
190 #[inline]
192 pub fn is_value(self) -> bool {
193 self.intersects(Self::Value | Self::Import)
194 }
195
196 #[inline]
197 pub fn is_const_variable(self) -> bool {
198 self.contains(Self::ConstVariable)
199 }
200
201 #[inline]
203 pub fn is_function(self) -> bool {
204 self.contains(Self::Function)
205 }
206
207 #[inline]
208 pub fn is_class(self) -> bool {
209 self.contains(Self::Class)
210 }
211
212 #[inline]
213 pub fn is_interface(self) -> bool {
214 self.contains(Self::Interface)
215 }
216
217 #[inline]
218 pub fn is_type_alias(self) -> bool {
219 self.contains(Self::TypeAlias)
220 }
221
222 #[inline]
223 pub fn is_enum(self) -> bool {
224 self.intersects(Self::Enum)
225 }
226
227 #[inline]
228 pub fn is_const_enum(self) -> bool {
229 self.intersects(Self::ConstEnum)
230 }
231
232 #[inline]
233 pub fn is_enum_member(self) -> bool {
234 self.contains(Self::EnumMember)
235 }
236
237 #[inline]
238 pub fn is_catch_variable(self) -> bool {
239 self.contains(Self::CatchVariable)
240 }
241
242 #[inline]
243 pub fn is_function_scoped_declaration(self) -> bool {
244 self.contains(Self::FunctionScopedVariable)
245 }
246
247 #[inline]
248 pub fn is_import(self) -> bool {
249 self.intersects(Self::Import | Self::TypeImport)
250 }
251
252 #[inline]
253 pub fn is_type_import(self) -> bool {
254 self.contains(Self::TypeImport)
255 }
256
257 #[inline]
258 pub fn is_ambient(self) -> bool {
259 self.contains(Self::Ambient)
260 }
261
262 #[inline]
263 pub fn is_namespace_module(self) -> bool {
264 self.contains(Self::NamespaceModule)
265 }
266
267 #[inline]
268 pub fn is_value_module(self) -> bool {
269 self.contains(Self::ValueModule)
270 }
271
272 #[inline]
274 pub fn can_be_referenced_by_type(self) -> bool {
275 self.intersects(Self::Type | Self::TypeImport | Self::Import | Self::Namespace)
276 }
277
278 #[inline]
280 pub fn can_be_referenced_by_value(self) -> bool {
281 self.is_value()
282 }
283
284 #[inline]
286 pub fn can_be_referenced_by_value_as_type(self) -> bool {
287 self.intersects(Self::Value | Self::Import | Self::Function | Self::TypeImport)
288 }
289}