slang_types/
types.rs

1use slang_derive::{IterableEnum, NamedEnum, NumericEnum};
2
3// Type name constants
4pub const TYPE_NAME_I32: &str = PrimitiveType::I32.name();
5pub const TYPE_NAME_I64: &str = PrimitiveType::I64.name();
6pub const TYPE_NAME_U32: &str = PrimitiveType::U32.name();
7pub const TYPE_NAME_U64: &str = PrimitiveType::U64.name();
8pub const TYPE_NAME_F32: &str = PrimitiveType::F32.name();
9pub const TYPE_NAME_F64: &str = PrimitiveType::F64.name();
10pub const TYPE_NAME_BOOL: &str = PrimitiveType::Bool.name();
11pub const TYPE_NAME_STRING: &str = PrimitiveType::String.name();
12pub const TYPE_NAME_INT: &str = PrimitiveType::UnspecifiedInt.name();
13pub const TYPE_NAME_FLOAT: &str = PrimitiveType::UnspecifiedFloat.name();
14pub const TYPE_NAME_UNIT: &str = PrimitiveType::Unit.name();
15pub const TYPE_NAME_UNKNOWN: &str = PrimitiveType::Unknown.name();
16
17/// Represents all primitive types in the language
18#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, NamedEnum, IterableEnum, NumericEnum)]
19pub enum PrimitiveType {
20    /// 32-bit signed integer
21    I32,
22    /// 64-bit signed integer
23    I64,
24    /// 32-bit unsigned integer
25    U32,
26    /// 64-bit unsigned integer
27    U64,
28    /// 32-bit floating point
29    F32,
30    /// 64-bit floating point
31    F64,
32    /// Boolean type
33    Bool,
34    /// String type
35    String,
36    /// Unspecified integer type (for literals)
37    #[name = "int"]
38    UnspecifiedInt,
39    /// Unspecified float type (for literals)
40    #[name = "float"]
41    UnspecifiedFloat,
42    /// Unit type (similar to Rust's ())
43    #[name = "()"]
44    Unit,
45    /// Unknown type
46    Unknown,
47}
48
49impl PrimitiveType {
50    /// Check if this is a numeric type (integer or float)
51    pub fn is_numeric(&self) -> bool {
52        self.is_integer() || self.is_float()
53    }
54
55    /// Check if this is an integer type
56    pub fn is_integer(&self) -> bool {
57        matches!(
58            self,
59            PrimitiveType::I32
60                | PrimitiveType::I64
61                | PrimitiveType::U32
62                | PrimitiveType::U64
63                | PrimitiveType::UnspecifiedInt
64        )
65    }
66
67    /// Check if this is a float type
68    pub fn is_float(&self) -> bool {
69        matches!(
70            self,
71            PrimitiveType::F32 | PrimitiveType::F64 | PrimitiveType::UnspecifiedFloat
72        )
73    }
74
75    /// Check if this is a signed integer type
76    pub fn is_signed_integer(&self) -> bool {
77        matches!(
78            self,
79            PrimitiveType::I32 | PrimitiveType::I64 | PrimitiveType::UnspecifiedInt
80        )
81    }
82
83    /// Check if this is an unsigned integer type
84    pub fn is_unsigned_integer(&self) -> bool {
85        matches!(self, PrimitiveType::U32 | PrimitiveType::U64)
86    }
87
88    /// Get the bit width of this type (0 for unspecified types)
89    pub fn bit_width(&self) -> u8 {
90        match self {
91            PrimitiveType::I32 | PrimitiveType::U32 | PrimitiveType::F32 => 32,
92            PrimitiveType::I64 | PrimitiveType::U64 | PrimitiveType::F64 => 64,
93            PrimitiveType::Bool => 1,
94            PrimitiveType::Unit => 0,
95            _ => 0,
96        }
97    }
98
99    /// Get the TypeKind for this primitive type
100    ///
101    /// This method defines the actual type characteristics for each primitive type,
102    /// separating type definition from type registration logic.
103    pub fn to_type_kind(&self) -> TypeKind {
104        match self {
105            PrimitiveType::I32 => TypeKind::Integer(IntegerType {
106                signed: true,
107                bits: 32,
108                is_unspecified: false,
109            }),
110            PrimitiveType::I64 => TypeKind::Integer(IntegerType {
111                signed: true,
112                bits: 64,
113                is_unspecified: false,
114            }),
115            PrimitiveType::U32 => TypeKind::Integer(IntegerType {
116                signed: false,
117                bits: 32,
118                is_unspecified: false,
119            }),
120            PrimitiveType::U64 => TypeKind::Integer(IntegerType {
121                signed: false,
122                bits: 64,
123                is_unspecified: false,
124            }),
125            PrimitiveType::UnspecifiedInt => TypeKind::Integer(IntegerType {
126                signed: true,
127                bits: 0,
128                is_unspecified: true,
129            }),
130            PrimitiveType::F32 => TypeKind::Float(FloatType {
131                bits: 32,
132                is_unspecified: false,
133            }),
134            PrimitiveType::F64 => TypeKind::Float(FloatType {
135                bits: 64,
136                is_unspecified: false,
137            }),
138            PrimitiveType::UnspecifiedFloat => TypeKind::Float(FloatType {
139                bits: 0,
140                is_unspecified: true,
141            }),
142            PrimitiveType::String => TypeKind::String,
143            PrimitiveType::Bool => TypeKind::Boolean,
144            PrimitiveType::Unit => TypeKind::Unit,
145            PrimitiveType::Unknown => TypeKind::Unknown,
146        }
147    }
148}
149
150impl From<PrimitiveType> for usize {
151    fn from(primitive: PrimitiveType) -> usize {
152        primitive as usize
153    }
154}
155
156impl From<PrimitiveType> for TypeId {
157    fn from(primitive: PrimitiveType) -> Self {
158        TypeId::from_primitive(primitive)
159    }
160}
161
162/// A unique identifier for a type in the type system
163#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
164pub struct TypeId(pub usize);
165
166impl Default for TypeId {
167    fn default() -> Self {
168        TypeId::unknown()
169    }
170}
171
172impl TypeId {
173    /// Creates a new unique type identifier for custom types
174    pub fn new() -> Self {
175        static NEXT_ID: std::sync::atomic::AtomicUsize = std::sync::atomic::AtomicUsize::new(1000); // above primitive type range
176        TypeId(NEXT_ID.fetch_add(1, std::sync::atomic::Ordering::Relaxed))
177    }
178
179    /// Creates a TypeId for a primitive type - PREFERRED METHOD
180    ///
181    /// This ensures consistent TypeId assignment for primitive types
182    /// and is more robust than direct casting.
183    ///
184    /// ### Arguments
185    /// * `primitive` - The primitive type to create a TypeId for
186    ///
187    /// ### Returns
188    /// A TypeId that is guaranteed to be unique and consistent for the primitive type
189    pub fn from_primitive(primitive: PrimitiveType) -> Self {
190        use std::collections::HashMap;
191        use std::sync::LazyLock;
192
193        static PRIMITIVE_IDS: LazyLock<HashMap<PrimitiveType, TypeId>> = LazyLock::new(|| {
194            let mut map = HashMap::new();
195
196            for primitive in PrimitiveType::iter() {
197                map.insert(primitive, TypeId(primitive as usize));
198            }
199            map
200        });
201
202        PRIMITIVE_IDS
203            .get(&primitive)
204            .cloned()
205            .unwrap_or_else(|| panic!("Unknown primitive type: {:?}", primitive))
206    }
207
208    /// Returns the TypeId for bool type
209    #[inline]
210    pub fn bool() -> Self {
211        Self::from_primitive(PrimitiveType::Bool)
212    }
213
214    /// Returns the TypeId for i32 type
215    #[inline]
216    pub fn i32() -> Self {
217        Self::from_primitive(PrimitiveType::I32)
218    }
219
220    /// Returns the TypeId for i64 type
221    #[inline]
222    pub fn i64() -> Self {
223        Self::from_primitive(PrimitiveType::I64)
224    }
225
226    /// Returns the TypeId for u32 type
227    #[inline]
228    pub fn u32() -> Self {
229        Self::from_primitive(PrimitiveType::U32)
230    }
231
232    /// Returns the TypeId for u64 type
233    #[inline]
234    pub fn u64() -> Self {
235        Self::from_primitive(PrimitiveType::U64)
236    }
237
238    /// Returns the TypeId for f32 type
239    #[inline]
240    pub fn f32() -> Self {
241        Self::from_primitive(PrimitiveType::F32)
242    }
243
244    /// Returns the TypeId for f64 type
245    #[inline]
246    pub fn f64() -> Self {
247        Self::from_primitive(PrimitiveType::F64)
248    }
249
250    /// Returns the TypeId for string type
251    #[inline]
252    pub fn string() -> Self {
253        Self::from_primitive(PrimitiveType::String)
254    }
255
256    /// Returns the TypeId for unit type
257    #[inline]
258    pub fn unit() -> Self {
259        Self::from_primitive(PrimitiveType::Unit)
260    }
261
262    /// Returns the TypeId for unspecified integer type
263    #[inline]
264    pub fn unspecified_int() -> Self {
265        Self::from_primitive(PrimitiveType::UnspecifiedInt)
266    }
267
268    /// Returns the TypeId for unspecified float type
269    #[inline]
270    pub fn unspecified_float() -> Self {
271        Self::from_primitive(PrimitiveType::UnspecifiedFloat)
272    }
273
274    /// Returns the TypeId for unknown type
275    #[inline]
276    pub fn unknown() -> Self {
277        Self::from_primitive(PrimitiveType::Unknown)
278    }
279}
280
281/// Represents the different kinds of types in the language
282#[derive(Debug, Clone, PartialEq, Eq, Hash)]
283pub enum TypeKind {
284    /// Integer types (signed/unsigned, different bit widths)
285    Integer(IntegerType),
286    /// Floating point types
287    Float(FloatType),
288    /// String type
289    String,
290    /// Boolean type
291    Boolean,
292    /// Unit type (similar to Rust's ())
293    Unit,
294    /// Struct type with fields
295    Struct(StructType),
296    /// Function type with parameters and return type
297    Function(FunctionType),
298    /// Unknown or not yet determined type
299    Unknown,
300}
301
302impl TypeKind {
303    /// Returns the function type if this is a function, None otherwise
304    pub fn as_function(&self) -> Option<&FunctionType> {
305        match self {
306            TypeKind::Function(func_type) => Some(func_type),
307            _ => None,
308        }
309    }
310}
311
312/// Represents an integer type with its properties
313#[derive(Debug, Clone, PartialEq, Eq, Hash)]
314pub struct IntegerType {
315    /// Whether the integer is signed or unsigned
316    pub signed: bool,
317    /// The number of bits (e.g., 32 for i32)
318    pub bits: u8,
319    /// Whether this is an unspecified integer (used for literals without explicit type)
320    pub is_unspecified: bool,
321}
322
323/// Represents a floating point type with its properties
324#[derive(Debug, Clone, PartialEq, Eq, Hash)]
325pub struct FloatType {
326    /// The number of bits (e.g., 64 for f64)
327    pub bits: u8,
328    /// Whether this is an unspecified float (used for literals without explicit type)
329    pub is_unspecified: bool,
330}
331
332/// Represents a struct type with its fields
333#[derive(Debug, Clone, PartialEq, Eq, Hash)]
334pub struct StructType {
335    /// Name of the struct
336    pub name: String,
337    /// Fields of the struct with their names and types
338    pub fields: Vec<(String, TypeId)>,
339}
340
341impl StructType {
342    /// Creates a new StructType.
343    pub fn new(name: String, fields: Vec<(String, TypeId)>) -> Self {
344        StructType { name, fields }
345    }
346}
347
348/// Represents a function type with its parameters and return type
349#[derive(Debug, Clone, PartialEq, Eq, Hash)]
350pub struct FunctionType {
351    /// Parameter types of the function
352    pub param_types: Vec<TypeId>,
353    /// Return type of the function
354    pub return_type: TypeId,
355}
356
357impl FunctionType {
358    /// Creates a new FunctionType.
359    pub fn new(param_types: Vec<TypeId>, return_type: TypeId) -> Self {
360        FunctionType {
361            param_types,
362            return_type,
363        }
364    }
365}
366
367/// Contains all information about a specific type
368#[derive(Debug)]
369pub struct TypeInfo {
370    /// Unique identifier for this type
371    pub id: TypeId,
372    /// Name of the type
373    pub name: String,
374    /// The kind of type (integer, float, string, etc.)
375    pub kind: TypeKind,
376}