gruel_builtins/
lib.rs

1//! Built-in type definitions for the Gruel compiler.
2//!
3//! This crate provides the registry of built-in types like `String`. These are
4//! types that behave like user-defined structs but have runtime implementations
5//! for their methods rather than generated code.
6//!
7//! # Architecture
8//!
9//! Built-in types are represented as "synthetic structs" — the compiler injects
10//! them as `StructDef` entries before processing user code. This allows them to
11//! flow through the same code paths as user-defined types, eliminating scattered
12//! special-case handling throughout the compiler.
13//!
14//! The injection happens in `Sema::inject_builtin_types()` during the declaration
15//! gathering phase. After injection:
16//!
17//! - The type is accessible by name (e.g., `String`)
18//! - Methods are registered and callable (e.g., `s.len()`)
19//! - Associated functions work (e.g., `String::new()`)
20//! - Operators are supported (e.g., `s1 == s2`)
21//! - Drop glue is automatically generated if `drop_fn` is set
22//!
23//! # Adding a New Built-in Type
24//!
25//! To add a new built-in type (e.g., `Vec<T>` when generics are available):
26//!
27//! ## Step 1: Define the Type
28//!
29//! Create a `BuiltinTypeDef` constant describing the type's structure:
30//!
31//! ```rust,ignore
32//! pub static VEC_TYPE: BuiltinTypeDef = BuiltinTypeDef {
33//!     name: "Vec",  // How users refer to it in source code
34//!     fields: &[
35//!         BuiltinField { name: "ptr", ty: BuiltinFieldType::U64 },
36//!         BuiltinField { name: "len", ty: BuiltinFieldType::U64 },
37//!         BuiltinField { name: "cap", ty: BuiltinFieldType::U64 },
38//!     ],
39//!     is_copy: false,  // Vec owns heap memory, so it's a move type
40//!     drop_fn: Some("__gruel_drop_Vec"),  // Runtime destructor
41//!     operators: &[
42//!         // Vec might support equality if elements do
43//!     ],
44//!     associated_fns: &[
45//!         BuiltinAssociatedFn {
46//!             name: "new",
47//!             params: &[],
48//!             return_ty: BuiltinReturnType::SelfType,
49//!             runtime_fn: "Vec__new",
50//!         },
51//!         BuiltinAssociatedFn {
52//!             name: "with_capacity",
53//!             params: &[BuiltinParam { name: "capacity", ty: BuiltinParamType::U64 }],
54//!             return_ty: BuiltinReturnType::SelfType,
55//!             runtime_fn: "Vec__with_capacity",
56//!         },
57//!     ],
58//!     methods: &[
59//!         BuiltinMethod {
60//!             name: "len",
61//!             receiver_mode: ReceiverMode::ByRef,
62//!             params: &[],
63//!             return_ty: BuiltinReturnType::U64,
64//!             runtime_fn: "Vec__len",
65//!         },
66//!         BuiltinMethod {
67//!             name: "push",
68//!             receiver_mode: ReceiverMode::ByMutRef,
69//!             params: &[BuiltinParam { name: "value", ty: BuiltinParamType::U64 }],
70//!             return_ty: BuiltinReturnType::SelfType,
71//!             runtime_fn: "Vec__push",
72//!         },
73//!         // ... more methods
74//!     ],
75//! };
76//! ```
77//!
78//! ## Step 2: Register the Type
79//!
80//! Add it to the `BUILTIN_TYPES` slice:
81//!
82//! ```rust,ignore
83//! pub static BUILTIN_TYPES: &[&BuiltinTypeDef] = &[
84//!     &STRING_TYPE,
85//!     &VEC_TYPE,  // Add new types here
86//! ];
87//! ```
88//!
89//! ## Step 3: Implement Runtime Functions
90//!
91//! In `gruel-runtime`, implement the functions referenced in the type definition:
92//!
93//! ```rust,ignore
94//! // In gruel-runtime/src/lib.rs or a new module
95//!
96//! #[unsafe(no_mangle)]
97//! pub extern "C" fn Vec__new(out: *mut u64) {
98//!     // Initialize empty Vec at `out` pointer
99//!     unsafe {
100//!         *out = 0;           // ptr = null
101//!         *out.add(1) = 0;    // len = 0
102//!         *out.add(2) = 0;    // cap = 0
103//!     }
104//! }
105//!
106//! #[unsafe(no_mangle)]
107//! pub extern "C" fn __gruel_drop_Vec(ptr: *mut u64) {
108//!     // Free the Vec's heap allocation if any
109//!     unsafe {
110//!         let data_ptr = *ptr as *mut u8;
111//!         let cap = *ptr.add(2);
112//!         if cap > 0 {
113//!             __gruel_free(data_ptr, cap as usize);
114//!         }
115//!     }
116//! }
117//! ```
118//!
119//! ## Naming Conventions
120//!
121//! - **Associated functions**: `TypeName__function_name` (e.g., `String__new`)
122//! - **Methods**: `TypeName__method_name` (e.g., `String__len`)
123//! - **Drop functions**: `__gruel_drop_TypeName` (e.g., `__gruel_drop_String`)
124//! - **Operators**: `__gruel_typename_op` (e.g., `__gruel_str_eq`)
125//!
126//! ## Key Types
127//!
128//! - [`BuiltinTypeDef`]: Complete definition of a built-in type
129//! - [`BuiltinField`]: A field in the struct layout
130//! - [`BuiltinMethod`]: An instance method (takes `self`)
131//! - [`BuiltinAssociatedFn`]: A static function (e.g., `Type::new()`)
132//! - [`BuiltinOperator`]: Operator overload (e.g., `==`, `!=`)
133//! - [`ReceiverMode`]: How `self` is passed to methods
134//!
135//! See [`STRING_TYPE`] for a complete working example.
136
137/// Binary operators that can be overloaded for built-in types.
138#[derive(Debug, Clone, Copy, PartialEq, Eq)]
139pub enum BinOp {
140    /// Equality: `==`
141    Eq,
142    /// Inequality: `!=`
143    Ne,
144    /// Less than: `<`
145    Lt,
146    /// Less than or equal: `<=`
147    Le,
148    /// Greater than: `>`
149    Gt,
150    /// Greater than or equal: `>=`
151    Ge,
152}
153
154/// Field type for built-in struct fields.
155///
156/// This is a simplified type representation for defining builtin struct layouts.
157/// It maps to actual `Type` variants during struct injection.
158#[derive(Debug, Clone, Copy, PartialEq, Eq)]
159pub enum BuiltinFieldType {
160    /// 64-bit unsigned integer (used for pointers, lengths, capacities)
161    U64,
162    /// 8-bit unsigned integer
163    U8,
164    /// Boolean
165    Bool,
166}
167
168/// A field in a built-in struct.
169#[derive(Debug, Clone, Copy)]
170pub struct BuiltinField {
171    /// Field name
172    pub name: &'static str,
173    /// Field type
174    pub ty: BuiltinFieldType,
175}
176
177/// How the receiver is passed to a method.
178#[derive(Debug, Clone, Copy, PartialEq, Eq)]
179pub enum ReceiverMode {
180    /// Method takes ownership: `fn method(self)`
181    ByValue,
182    /// Method borrows: `fn method(&self)`
183    ByRef,
184    /// Method mutably borrows: `fn method(&mut self)`
185    ByMutRef,
186}
187
188/// A parameter to a built-in method or associated function.
189#[derive(Debug, Clone, Copy)]
190pub struct BuiltinParam {
191    /// Parameter name
192    pub name: &'static str,
193    /// Parameter type (simplified)
194    pub ty: BuiltinParamType,
195}
196
197/// Type of a parameter to a built-in function.
198#[derive(Debug, Clone, Copy, PartialEq, Eq)]
199pub enum BuiltinParamType {
200    /// 64-bit unsigned integer
201    U64,
202    /// 8-bit unsigned integer
203    U8,
204    /// Boolean
205    Bool,
206    /// The built-in type itself (e.g., String for String methods)
207    SelfType,
208}
209
210/// Return type of a built-in method.
211#[derive(Debug, Clone, Copy, PartialEq, Eq)]
212pub enum BuiltinReturnType {
213    /// No return value (unit type)
214    Unit,
215    /// 64-bit unsigned integer
216    U64,
217    /// 8-bit unsigned integer
218    U8,
219    /// Boolean (returned as u8: 0 or 1)
220    Bool,
221    /// Returns the built-in type itself
222    SelfType,
223}
224
225/// An operator overload for a built-in type.
226#[derive(Debug, Clone, Copy)]
227pub struct BuiltinOperator {
228    /// The operator being overloaded
229    pub op: BinOp,
230    /// Runtime function to call (e.g., `__gruel_str_eq`)
231    pub runtime_fn: &'static str,
232    /// Whether to invert the result (for `!=` using `==` implementation)
233    pub invert_result: bool,
234}
235
236/// An associated function on a built-in type (e.g., `String::new`).
237#[derive(Debug, Clone, Copy)]
238pub struct BuiltinAssociatedFn {
239    /// Function name (e.g., "new")
240    pub name: &'static str,
241    /// Parameters (excluding any implicit out pointer)
242    pub params: &'static [BuiltinParam],
243    /// Return type
244    pub return_ty: BuiltinReturnType,
245    /// Runtime function name (e.g., "String__new")
246    pub runtime_fn: &'static str,
247}
248
249/// An instance method on a built-in type (e.g., `s.len()`).
250#[derive(Debug, Clone, Copy)]
251pub struct BuiltinMethod {
252    /// Method name (e.g., "len")
253    pub name: &'static str,
254    /// How the receiver is passed
255    pub receiver_mode: ReceiverMode,
256    /// Additional parameters after self
257    pub params: &'static [BuiltinParam],
258    /// Return type
259    pub return_ty: BuiltinReturnType,
260    /// Runtime function name (e.g., "String__len")
261    pub runtime_fn: &'static str,
262}
263
264/// Definition of a built-in type.
265///
266/// This describes everything the compiler needs to know about a built-in type:
267/// its layout (fields), behavior (operators), and available operations (methods).
268#[derive(Debug, Clone)]
269pub struct BuiltinTypeDef {
270    /// Type name as it appears in source code (e.g., "String")
271    pub name: &'static str,
272    /// Fields that make up the struct layout
273    pub fields: &'static [BuiltinField],
274    /// Whether this type is Copy (can be implicitly duplicated)
275    pub is_copy: bool,
276    /// Runtime function to call for drop, if any
277    pub drop_fn: Option<&'static str>,
278    /// Supported operators and their implementations
279    pub operators: &'static [BuiltinOperator],
280    /// Associated functions (e.g., `String::new`)
281    pub associated_fns: &'static [BuiltinAssociatedFn],
282    /// Instance methods (e.g., `s.len()`)
283    pub methods: &'static [BuiltinMethod],
284}
285
286// ============================================================================
287// String Type Definition
288// ============================================================================
289
290/// The built-in String type.
291///
292/// Layout: `{ ptr: u64, len: u64, cap: u64 }` (24 bytes)
293///
294/// - `ptr`: Pointer to heap-allocated byte buffer (or .rodata for literals)
295/// - `len`: Current length in bytes
296/// - `cap`: Capacity of allocated buffer (0 for .rodata literals)
297///
298/// String is a move type (not Copy) because it owns heap-allocated memory.
299/// The drop function checks `cap > 0` before freeing, allowing .rodata
300/// literals (with `cap = 0`) to be safely dropped without freeing.
301pub static STRING_TYPE: BuiltinTypeDef = BuiltinTypeDef {
302    name: "String",
303    fields: &[
304        BuiltinField {
305            name: "ptr",
306            ty: BuiltinFieldType::U64,
307        },
308        BuiltinField {
309            name: "len",
310            ty: BuiltinFieldType::U64,
311        },
312        BuiltinField {
313            name: "cap",
314            ty: BuiltinFieldType::U64,
315        },
316    ],
317    is_copy: false,
318    drop_fn: Some("__gruel_drop_String"),
319    operators: &[
320        BuiltinOperator {
321            op: BinOp::Eq,
322            runtime_fn: "__gruel_str_eq",
323            invert_result: false,
324        },
325        BuiltinOperator {
326            op: BinOp::Ne,
327            runtime_fn: "__gruel_str_eq",
328            invert_result: true,
329        },
330        BuiltinOperator {
331            op: BinOp::Lt,
332            runtime_fn: "__gruel_str_cmp",
333            invert_result: false,
334        },
335        BuiltinOperator {
336            op: BinOp::Le,
337            runtime_fn: "__gruel_str_cmp",
338            invert_result: false,
339        },
340        BuiltinOperator {
341            op: BinOp::Gt,
342            runtime_fn: "__gruel_str_cmp",
343            invert_result: false,
344        },
345        BuiltinOperator {
346            op: BinOp::Ge,
347            runtime_fn: "__gruel_str_cmp",
348            invert_result: false,
349        },
350    ],
351    associated_fns: &[
352        BuiltinAssociatedFn {
353            name: "new",
354            params: &[],
355            return_ty: BuiltinReturnType::SelfType,
356            runtime_fn: "String__new",
357        },
358        BuiltinAssociatedFn {
359            name: "with_capacity",
360            params: &[BuiltinParam {
361                name: "capacity",
362                ty: BuiltinParamType::U64,
363            }],
364            return_ty: BuiltinReturnType::SelfType,
365            runtime_fn: "String__with_capacity",
366        },
367    ],
368    methods: &[
369        // Query methods (take &self)
370        BuiltinMethod {
371            name: "len",
372            receiver_mode: ReceiverMode::ByRef,
373            params: &[],
374            return_ty: BuiltinReturnType::U64,
375            runtime_fn: "String__len",
376        },
377        BuiltinMethod {
378            name: "capacity",
379            receiver_mode: ReceiverMode::ByRef,
380            params: &[],
381            return_ty: BuiltinReturnType::U64,
382            runtime_fn: "String__capacity",
383        },
384        BuiltinMethod {
385            name: "is_empty",
386            receiver_mode: ReceiverMode::ByRef,
387            params: &[],
388            return_ty: BuiltinReturnType::Bool,
389            runtime_fn: "String__is_empty",
390        },
391        BuiltinMethod {
392            name: "clone",
393            receiver_mode: ReceiverMode::ByRef,
394            params: &[],
395            return_ty: BuiltinReturnType::SelfType,
396            runtime_fn: "String__clone",
397        },
398        BuiltinMethod {
399            name: "contains",
400            receiver_mode: ReceiverMode::ByRef,
401            params: &[BuiltinParam {
402                name: "needle",
403                ty: BuiltinParamType::SelfType,
404            }],
405            return_ty: BuiltinReturnType::Bool,
406            runtime_fn: "String__contains",
407        },
408        BuiltinMethod {
409            name: "starts_with",
410            receiver_mode: ReceiverMode::ByRef,
411            params: &[BuiltinParam {
412                name: "prefix",
413                ty: BuiltinParamType::SelfType,
414            }],
415            return_ty: BuiltinReturnType::Bool,
416            runtime_fn: "String__starts_with",
417        },
418        BuiltinMethod {
419            name: "ends_with",
420            receiver_mode: ReceiverMode::ByRef,
421            params: &[BuiltinParam {
422                name: "suffix",
423                ty: BuiltinParamType::SelfType,
424            }],
425            return_ty: BuiltinReturnType::Bool,
426            runtime_fn: "String__ends_with",
427        },
428        BuiltinMethod {
429            name: "concat",
430            receiver_mode: ReceiverMode::ByRef,
431            params: &[BuiltinParam {
432                name: "other",
433                ty: BuiltinParamType::SelfType,
434            }],
435            return_ty: BuiltinReturnType::SelfType,
436            runtime_fn: "String__concat",
437        },
438        // Mutation methods (take &mut self, return modified String)
439        BuiltinMethod {
440            name: "push_str",
441            receiver_mode: ReceiverMode::ByMutRef,
442            params: &[BuiltinParam {
443                name: "other",
444                ty: BuiltinParamType::SelfType,
445            }],
446            return_ty: BuiltinReturnType::SelfType,
447            runtime_fn: "String__push_str",
448        },
449        BuiltinMethod {
450            name: "push",
451            receiver_mode: ReceiverMode::ByMutRef,
452            params: &[BuiltinParam {
453                name: "byte",
454                ty: BuiltinParamType::U8,
455            }],
456            return_ty: BuiltinReturnType::SelfType,
457            runtime_fn: "String__push",
458        },
459        BuiltinMethod {
460            name: "clear",
461            receiver_mode: ReceiverMode::ByMutRef,
462            params: &[],
463            return_ty: BuiltinReturnType::SelfType,
464            runtime_fn: "String__clear",
465        },
466        BuiltinMethod {
467            name: "reserve",
468            receiver_mode: ReceiverMode::ByMutRef,
469            params: &[BuiltinParam {
470                name: "additional",
471                ty: BuiltinParamType::U64,
472            }],
473            return_ty: BuiltinReturnType::SelfType,
474            runtime_fn: "String__reserve",
475        },
476    ],
477};
478
479// ============================================================================
480// Registry
481// ============================================================================
482
483/// All built-in types.
484///
485/// The compiler iterates over this to inject synthetic structs before
486/// processing user code.
487pub static BUILTIN_TYPES: &[&BuiltinTypeDef] = &[&STRING_TYPE];
488
489// ============================================================================
490// Built-in Enums (Target Platform)
491// ============================================================================
492
493/// Definition of a built-in enum type.
494///
495/// These are synthetic enums injected by the compiler before processing user code.
496/// They are used for compile-time platform detection via intrinsics like
497/// `@target_arch()` and `@target_os()`.
498#[derive(Debug, Clone)]
499pub struct BuiltinEnumDef {
500    /// Enum name as it appears in source code (e.g., "Arch")
501    pub name: &'static str,
502    /// Variant names in order (index matches variant_index in EnumVariant)
503    pub variants: &'static [&'static str],
504}
505
506/// The built-in Arch enum for CPU architecture detection.
507///
508/// Variants:
509/// - `X86_64` (index 0): x86-64 / AMD64
510/// - `Aarch64` (index 1): ARM64 / AArch64
511///
512/// Used with `@target_arch()` intrinsic for platform-specific code.
513pub static ARCH_ENUM: BuiltinEnumDef = BuiltinEnumDef {
514    name: "Arch",
515    variants: &["X86_64", "Aarch64"],
516};
517
518/// The built-in Os enum for operating system detection.
519///
520/// Variants:
521/// - `Linux` (index 0): Linux
522/// - `Macos` (index 1): macOS / Darwin
523///
524/// Used with `@target_os()` intrinsic for platform-specific code.
525pub static OS_ENUM: BuiltinEnumDef = BuiltinEnumDef {
526    name: "Os",
527    variants: &["Linux", "Macos"],
528};
529
530/// The built-in TypeKind enum for compile-time type reflection.
531///
532/// Variants represent different type classifications, used by `@typeInfo`.
533///
534/// Variants:
535/// - `Struct` (index 0): Struct types
536/// - `Enum` (index 1): Enum types
537/// - `Int` (index 2): Integer types (i8..i64, u8..u64)
538/// - `Bool` (index 3): Boolean type
539/// - `Unit` (index 4): Unit type
540/// - `Never` (index 5): Never type
541/// - `Array` (index 6): Fixed-size array types
542pub static TYPEKIND_ENUM: BuiltinEnumDef = BuiltinEnumDef {
543    name: "TypeKind",
544    variants: &["Struct", "Enum", "Int", "Bool", "Unit", "Never", "Array"],
545};
546
547/// All built-in enums.
548///
549/// The compiler iterates over this to inject synthetic enums before
550/// processing user code.
551pub static BUILTIN_ENUMS: &[&BuiltinEnumDef] = &[&ARCH_ENUM, &OS_ENUM, &TYPEKIND_ENUM];
552
553/// Look up a built-in enum by name.
554pub fn get_builtin_enum(name: &str) -> Option<&'static BuiltinEnumDef> {
555    BUILTIN_ENUMS.iter().find(|e| e.name == name).copied()
556}
557
558/// Check if a name is reserved for a built-in enum.
559pub fn is_reserved_enum_name(name: &str) -> bool {
560    BUILTIN_ENUMS.iter().any(|e| e.name == name)
561}
562
563/// Look up a built-in type by name.
564pub fn get_builtin_type(name: &str) -> Option<&'static BuiltinTypeDef> {
565    BUILTIN_TYPES.iter().find(|t| t.name == name).copied()
566}
567
568/// Check if a name is reserved for a built-in type.
569pub fn is_reserved_type_name(name: &str) -> bool {
570    BUILTIN_TYPES.iter().any(|t| t.name == name)
571}
572
573// ============================================================================
574// Helper methods
575// ============================================================================
576
577impl BuiltinTypeDef {
578    /// Get the number of slots this type uses in the ABI.
579    ///
580    /// Each field uses one slot (all fields are currently scalar types).
581    pub fn slot_count(&self) -> u32 {
582        self.fields.len() as u32
583    }
584
585    /// Find an associated function by name.
586    pub fn find_associated_fn(&self, name: &str) -> Option<&BuiltinAssociatedFn> {
587        self.associated_fns.iter().find(|f| f.name == name)
588    }
589
590    /// Find a method by name.
591    pub fn find_method(&self, name: &str) -> Option<&BuiltinMethod> {
592        self.methods.iter().find(|m| m.name == name)
593    }
594
595    /// Find an operator implementation.
596    pub fn find_operator(&self, op: BinOp) -> Option<&BuiltinOperator> {
597        self.operators.iter().find(|o| o.op == op)
598    }
599
600    /// Check if this type supports a given operator.
601    pub fn supports_operator(&self, op: BinOp) -> bool {
602        self.operators.iter().any(|o| o.op == op)
603    }
604}
605
606#[cfg(test)]
607mod tests {
608    use super::*;
609
610    #[test]
611    fn test_string_type_exists() {
612        assert_eq!(STRING_TYPE.name, "String");
613        assert_eq!(STRING_TYPE.fields.len(), 3);
614        assert!(!STRING_TYPE.is_copy);
615        assert_eq!(STRING_TYPE.drop_fn, Some("__gruel_drop_String"));
616    }
617
618    #[test]
619    fn test_string_slot_count() {
620        assert_eq!(STRING_TYPE.slot_count(), 3);
621    }
622
623    #[test]
624    fn test_string_associated_fns() {
625        let new_fn = STRING_TYPE.find_associated_fn("new").unwrap();
626        assert_eq!(new_fn.runtime_fn, "String__new");
627        assert!(new_fn.params.is_empty());
628
629        let with_cap = STRING_TYPE.find_associated_fn("with_capacity").unwrap();
630        assert_eq!(with_cap.runtime_fn, "String__with_capacity");
631        assert_eq!(with_cap.params.len(), 1);
632    }
633
634    #[test]
635    fn test_string_methods() {
636        let len = STRING_TYPE.find_method("len").unwrap();
637        assert_eq!(len.runtime_fn, "String__len");
638        assert_eq!(len.receiver_mode, ReceiverMode::ByRef);
639
640        let push_str = STRING_TYPE.find_method("push_str").unwrap();
641        assert_eq!(push_str.runtime_fn, "String__push_str");
642        assert_eq!(push_str.receiver_mode, ReceiverMode::ByMutRef);
643    }
644
645    #[test]
646    fn test_string_operators() {
647        assert!(STRING_TYPE.supports_operator(BinOp::Eq));
648        assert!(STRING_TYPE.supports_operator(BinOp::Ne));
649        assert!(STRING_TYPE.supports_operator(BinOp::Lt));
650        assert!(STRING_TYPE.supports_operator(BinOp::Gt));
651
652        let eq = STRING_TYPE.find_operator(BinOp::Eq).unwrap();
653        assert_eq!(eq.runtime_fn, "__gruel_str_eq");
654        assert!(!eq.invert_result);
655
656        let ne = STRING_TYPE.find_operator(BinOp::Ne).unwrap();
657        assert_eq!(ne.runtime_fn, "__gruel_str_eq");
658        assert!(ne.invert_result);
659    }
660
661    #[test]
662    fn test_get_builtin_type() {
663        assert!(get_builtin_type("String").is_some());
664        assert!(get_builtin_type("Vec").is_none());
665    }
666
667    #[test]
668    fn test_is_reserved_type_name() {
669        assert!(is_reserved_type_name("String"));
670        assert!(!is_reserved_type_name("MyStruct"));
671    }
672
673    #[test]
674    fn test_all_string_methods_present() {
675        // Verify all expected methods are defined
676        let expected_methods = [
677            "len",
678            "capacity",
679            "is_empty",
680            "clone",
681            "contains",
682            "starts_with",
683            "ends_with",
684            "concat",
685            "push_str",
686            "push",
687            "clear",
688            "reserve",
689        ];
690        for name in expected_methods {
691            assert!(
692                STRING_TYPE.find_method(name).is_some(),
693                "missing method: {}",
694                name
695            );
696        }
697    }
698
699    // ========================================================================
700    // Built-in Enum Tests
701    // ========================================================================
702
703    #[test]
704    fn test_arch_enum() {
705        assert_eq!(ARCH_ENUM.name, "Arch");
706        assert_eq!(ARCH_ENUM.variants.len(), 2);
707        assert_eq!(ARCH_ENUM.variants[0], "X86_64");
708        assert_eq!(ARCH_ENUM.variants[1], "Aarch64");
709    }
710
711    #[test]
712    fn test_os_enum() {
713        assert_eq!(OS_ENUM.name, "Os");
714        assert_eq!(OS_ENUM.variants.len(), 2);
715        assert_eq!(OS_ENUM.variants[0], "Linux");
716        assert_eq!(OS_ENUM.variants[1], "Macos");
717    }
718
719    #[test]
720    fn test_get_builtin_enum() {
721        assert!(get_builtin_enum("Arch").is_some());
722        assert!(get_builtin_enum("Os").is_some());
723        assert!(get_builtin_enum("Target").is_none());
724    }
725
726    #[test]
727    fn test_is_reserved_enum_name() {
728        assert!(is_reserved_enum_name("Arch"));
729        assert!(is_reserved_enum_name("Os"));
730        assert!(is_reserved_enum_name("TypeKind"));
731        assert!(!is_reserved_enum_name("MyEnum"));
732    }
733
734    #[test]
735    fn test_builtin_enums_count() {
736        assert_eq!(BUILTIN_ENUMS.len(), 3);
737    }
738}