logicaffeine_language/analysis/
registry.rs

1//! Type registry for tracking user-defined types during parsing.
2//!
3//! The registry stores type definitions discovered during the discovery pass
4//! and provides lookup during parsing and code generation. It supports:
5//!
6//! - **Primitives**: Nat, Int, Text, Bool (built-in)
7//! - **Structs**: Named records with typed fields
8//! - **Enums**: Sum types with variants (unit or tuple)
9//! - **Generics**: Parameterized types (List of T, Pair of T and U)
10//!
11//! The registry is populated by [`super::DiscoveryPass`] before main parsing begins.
12
13use std::collections::HashMap;
14use logicaffeine_base::{Interner, Symbol};
15
16/// Type reference for struct fields (avoids circular deps with ast::TypeExpr)
17#[derive(Debug, Clone, PartialEq, Eq)]
18pub enum FieldType {
19    /// Primitive type name (Int, Nat, Text, Bool, etc.)
20    Primitive(Symbol),
21    /// User-defined type name
22    Named(Symbol),
23    /// Generic type with parameters (List of Int, Seq of Text)
24    Generic { base: Symbol, params: Vec<FieldType> },
25    /// Phase 34: Type parameter reference (T, U, etc.)
26    TypeParam(Symbol),
27}
28
29/// Field definition within a struct
30#[derive(Debug, Clone, PartialEq, Eq)]
31pub struct FieldDef {
32    pub name: Symbol,
33    pub ty: FieldType,
34    pub is_public: bool,
35}
36
37/// Phase 33: Variant definition for sum types
38#[derive(Debug, Clone, PartialEq, Eq)]
39pub struct VariantDef {
40    pub name: Symbol,
41    pub fields: Vec<FieldDef>,  // Empty for unit variants
42}
43
44#[derive(Debug, Clone, PartialEq, Eq)]
45pub enum TypeDef {
46    /// Primitive type (Nat, Int, Text, Bool)
47    Primitive,
48    /// Struct with named fields and visibility
49    /// Phase 34: Now includes optional type parameters
50    /// Phase 47: Added is_portable for serde derives
51    /// Phase 49: Added is_shared for CRDT Merge impl
52    Struct {
53        fields: Vec<FieldDef>,
54        generics: Vec<Symbol>,  // [T, U] for "A Pair of [T] and [U] has:"
55        is_portable: bool,       // Phase 47: Derives Serialize/Deserialize
56        is_shared: bool,         // Phase 49: Generates impl Merge
57    },
58    /// Phase 33: Enum with variants (unit or with payload)
59    /// Phase 34: Now includes optional type parameters
60    /// Phase 47: Added is_portable for serde derives
61    /// Phase 49: Added is_shared for CRDT Merge impl
62    Enum {
63        variants: Vec<VariantDef>,
64        generics: Vec<Symbol>,  // [T] for "A Maybe of [T] is either:"
65        is_portable: bool,       // Phase 47: Derives Serialize/Deserialize
66        is_shared: bool,         // Phase 49: Generates impl Merge
67    },
68    /// Built-in generic type (List, Option, Result)
69    Generic { param_count: usize },
70    /// Type alias
71    Alias { target: Symbol },
72}
73
74#[derive(Debug, Default, Clone)]
75pub struct TypeRegistry {
76    types: HashMap<Symbol, TypeDef>,
77}
78
79impl TypeRegistry {
80    pub fn new() -> Self {
81        Self::default()
82    }
83
84    /// Register a type definition
85    pub fn register(&mut self, name: Symbol, def: TypeDef) {
86        self.types.insert(name, def);
87    }
88
89    /// Check if a symbol is a known type
90    pub fn is_type(&self, name: Symbol) -> bool {
91        self.types.contains_key(&name)
92    }
93
94    /// Check if a symbol is a generic type (takes parameters)
95    pub fn is_generic(&self, name: Symbol) -> bool {
96        match self.types.get(&name) {
97            Some(TypeDef::Generic { .. }) => true,
98            Some(TypeDef::Struct { generics, .. }) => !generics.is_empty(),
99            Some(TypeDef::Enum { generics, .. }) => !generics.is_empty(),
100            _ => false,
101        }
102    }
103
104    /// Phase 34: Get type parameters for a user-defined generic type
105    pub fn get_generics(&self, name: Symbol) -> Option<&[Symbol]> {
106        match self.types.get(&name)? {
107            TypeDef::Struct { generics, .. } => Some(generics),
108            TypeDef::Enum { generics, .. } => Some(generics),
109            _ => None,
110        }
111    }
112
113    /// Get type definition
114    pub fn get(&self, name: Symbol) -> Option<&TypeDef> {
115        self.types.get(&name)
116    }
117
118    /// Iterate over all registered types (for codegen)
119    pub fn iter_types(&self) -> impl Iterator<Item = (&Symbol, &TypeDef)> {
120        self.types.iter()
121    }
122
123    /// Phase 33: Check if a symbol is a known enum variant
124    /// Returns Some((enum_name, variant_def)) if found
125    pub fn find_variant(&self, variant_name: Symbol) -> Option<(Symbol, &VariantDef)> {
126        for (enum_name, type_def) in &self.types {
127            if let TypeDef::Enum { variants, .. } = type_def {
128                for variant in variants {
129                    if variant.name == variant_name {
130                        return Some((*enum_name, variant));
131                    }
132                }
133            }
134        }
135        None
136    }
137
138    /// Phase 33: Check if a symbol is an enum variant
139    pub fn is_variant(&self, name: Symbol) -> bool {
140        self.find_variant(name).is_some()
141    }
142
143    /// Pre-register primitives and intrinsic generics
144    pub fn with_primitives(interner: &mut Interner) -> Self {
145        let mut reg = Self::new();
146
147        // LOGOS Core Primitives
148        reg.register(interner.intern("Nat"), TypeDef::Primitive);
149        reg.register(interner.intern("Int"), TypeDef::Primitive);
150        reg.register(interner.intern("Text"), TypeDef::Primitive);
151        reg.register(interner.intern("Bool"), TypeDef::Primitive);
152        reg.register(interner.intern("Boolean"), TypeDef::Primitive);
153        reg.register(interner.intern("Unit"), TypeDef::Primitive);
154        reg.register(interner.intern("Real"), TypeDef::Primitive);  // Floating point
155        reg.register(interner.intern("Char"), TypeDef::Primitive);  // Character
156        reg.register(interner.intern("Byte"), TypeDef::Primitive);  // 8-bit unsigned (0-255)
157
158        // Intrinsic Generics
159        reg.register(interner.intern("List"), TypeDef::Generic { param_count: 1 });
160        reg.register(interner.intern("Seq"), TypeDef::Generic { param_count: 1 });  // Phase 30: Sequences
161        reg.register(interner.intern("Map"), TypeDef::Generic { param_count: 2 });  // Phase 43D: Key-value maps
162        reg.register(interner.intern("Set"), TypeDef::Generic { param_count: 1 });  // Set collection (HashSet)
163        reg.register(interner.intern("Option"), TypeDef::Generic { param_count: 1 });
164        reg.register(interner.intern("Result"), TypeDef::Generic { param_count: 2 });
165
166        reg
167    }
168}
169
170#[cfg(test)]
171mod tests {
172    use super::*;
173
174    #[test]
175    fn registry_stores_and_retrieves() {
176        let mut interner = Interner::new();
177        let mut registry = TypeRegistry::new();
178        let foo = interner.intern("Foo");
179        registry.register(foo, TypeDef::Primitive);
180        assert!(registry.is_type(foo));
181        assert!(!registry.is_generic(foo));
182    }
183}