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
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
use bitflags::bitflags;
use nonmax::NonMaxU32;
#[cfg(feature = "serialize")]
use serde::{Serialize, Serializer};

use oxc_index::Idx;

#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct SymbolId(NonMaxU32);

impl Idx for SymbolId {
    #[allow(clippy::cast_possible_truncation)]
    fn from_usize(idx: usize) -> Self {
        assert!(idx < u32::MAX as usize);
        // SAFETY: We just checked `idx` is valid for `NonMaxU32`
        Self(unsafe { NonMaxU32::new_unchecked(idx as u32) })
    }

    fn index(self) -> usize {
        self.0.get() as usize
    }
}

#[cfg(feature = "serialize")]
impl Serialize for SymbolId {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: Serializer,
    {
        serializer.serialize_u32(self.0.get())
    }
}

#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct RedeclarationId(NonMaxU32);

impl Idx for RedeclarationId {
    #[allow(clippy::cast_possible_truncation)]
    fn from_usize(idx: usize) -> Self {
        Self(NonMaxU32::new(idx as u32).unwrap())
    }

    fn index(self) -> usize {
        self.0.get() as usize
    }
}

#[cfg(feature = "serialize")]
impl Serialize for RedeclarationId {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: Serializer,
    {
        serializer.serialize_u32(self.0.get())
    }
}

#[cfg(feature = "serialize")]
#[wasm_bindgen::prelude::wasm_bindgen(typescript_custom_section)]
const TS_APPEND_CONTENT: &'static str = r#"
export type SymbolId = number;
export type SymbolFlags = unknown;
export type RedeclarationId = unknown;
"#;

bitflags! {
    #[derive(Debug, Clone, Copy, PartialEq, Eq)]
    #[cfg_attr(feature = "serialize", derive(Serialize))]
    pub struct SymbolFlags: u32 {
        const None                    = 0;
        /// Variable (var) or parameter
        const FunctionScopedVariable  = 1 << 0;
        /// A block-scoped variable (let or const)
        const BlockScopedVariable     = 1 << 1;
        /// A const variable (const)
        const ConstVariable           = 1 << 2;
        /// Is this symbol inside an export declaration
        const Export                  = 1 << 4;
        const Class                   = 1 << 5;
        const CatchVariable           = 1 << 6; // try {} catch(catch_variable) {}
        const Function                = 1 << 7;
        const Import             = 1 << 8; // Imported ESM binding
        const TypeImport              = 1 << 9; // Imported ESM type-only binding
        // Type specific symbol flags
        const TypeAlias               = 1 << 10;
        const Interface               = 1 << 11;
        const RegularEnum             = 1 << 12;
        const ConstEnum               = 1 << 13;
        const EnumMember              = 1 << 14;
        const TypeLiteral             = 1 << 15;
        const TypeParameter           = 1 << 16;
        const NameSpaceModule         = 1 << 17;
        const ValueModule             = 1 << 18;
        // In a dts file or there is a declare flag
        const Ambient                 = 1 << 19;

        const Enum = Self::ConstEnum.bits() | Self::RegularEnum.bits();

        const Variable = Self::FunctionScopedVariable.bits() | Self::BlockScopedVariable.bits();
        const Value = Self::Variable.bits() | Self::Class.bits() | Self::Enum.bits() | Self::EnumMember.bits() | Self::ValueModule.bits();
        const Type =  Self::Class.bits() | Self::Interface.bits() | Self::Enum.bits() | Self::EnumMember.bits() | Self::TypeLiteral.bits() | Self::TypeParameter.bits()  |  Self::TypeAlias.bits();

        /// Variables can be redeclared, but can not redeclare a block-scoped declaration with the
        /// same name, or any other value that is not a variable, e.g. ValueModule or Class
        const FunctionScopedVariableExcludes = Self::Value.bits() - Self::FunctionScopedVariable.bits();

        /// Block-scoped declarations are not allowed to be re-declared
        /// they can not merge with anything in the value space
        const BlockScopedVariableExcludes = Self::Value.bits();

        const ClassExcludes = (Self::Value.bits() | Self::TypeAlias.bits()) & !Self::ValueModule.bits() ;
        const ImportBindingExcludes = Self::Import.bits() | Self::TypeImport.bits();
        // Type specific excludes
        const TypeAliasExcludes = Self::Type.bits();
        const InterfaceExcludes = Self::Type.bits() & !(Self::Interface.bits() | Self::Class.bits());
        const TypeParameterExcludes = Self::Type.bits() & !Self::TypeParameter.bits();
        const ConstEnumExcludes = (Self::Type.bits() | Self::Value.bits()) & !Self::ConstEnum.bits();
        // TODO: include value module in regular enum excludes
        const RegularEnumExcludes = (Self::Value.bits() | Self::Type.bits()) & !(Self::RegularEnum.bits() | Self::ValueModule.bits() );
        const EnumMemberExcludes = Self::EnumMember.bits();

    }
}

impl SymbolFlags {
    pub fn is_variable(&self) -> bool {
        self.intersects(Self::Variable)
    }

    pub fn is_type_parameter(&self) -> bool {
        self.contains(Self::TypeParameter)
    }

    /// If true, then the symbol is a type, such as a TypeAlias, Interface, or Enum
    pub fn is_type(&self) -> bool {
        self.intersects((Self::TypeImport | Self::Type) - Self::Value)
    }

    /// If true, then the symbol is a value, such as a Variable, Function, or Class
    pub fn is_value(&self) -> bool {
        self.intersects(Self::Value | Self::Import | Self::Function)
    }

    pub fn is_const_variable(&self) -> bool {
        self.contains(Self::ConstVariable)
    }

    pub fn is_function(&self) -> bool {
        self.contains(Self::Function)
    }

    pub fn is_class(&self) -> bool {
        self.contains(Self::Class)
    }

    pub fn is_interface(&self) -> bool {
        self.contains(Self::Interface)
    }

    pub fn is_type_alias(&self) -> bool {
        self.contains(Self::TypeAlias)
    }

    pub fn is_enum(&self) -> bool {
        self.intersects(Self::Enum)
    }

    pub fn is_enum_member(&self) -> bool {
        self.contains(Self::EnumMember)
    }

    pub fn is_catch_variable(&self) -> bool {
        self.contains(Self::CatchVariable)
    }

    pub fn is_function_scoped_declaration(&self) -> bool {
        self.contains(Self::FunctionScopedVariable)
    }

    pub fn is_export(&self) -> bool {
        self.contains(Self::Export)
    }

    pub fn is_import(&self) -> bool {
        self.intersects(Self::Import | Self::TypeImport)
    }

    pub fn is_type_import(&self) -> bool {
        self.contains(Self::TypeImport)
    }

    /// If true, then the symbol can be referenced by a type
    pub fn can_be_referenced_by_type(&self) -> bool {
        self.intersects(Self::Type | Self::TypeImport | Self::Import)
    }

    /// If true, then the symbol can be referenced by a value
    pub fn can_be_referenced_by_value(&self) -> bool {
        self.intersects(Self::Value | Self::Import | Self::Function)
    }
}