diff --git a/crates/prometeu-compiler/src/analysis/mod.rs b/crates/prometeu-compiler/src/analysis/mod.rs index 3f159a96..9b29490a 100644 --- a/crates/prometeu-compiler/src/analysis/mod.rs +++ b/crates/prometeu-compiler/src/analysis/mod.rs @@ -1 +1,2 @@ -pub mod symbols; \ No newline at end of file +pub mod symbols; +pub mod types; \ No newline at end of file diff --git a/crates/prometeu-compiler/src/analysis/types.rs b/crates/prometeu-compiler/src/analysis/types.rs new file mode 100644 index 00000000..73a1eca2 --- /dev/null +++ b/crates/prometeu-compiler/src/analysis/types.rs @@ -0,0 +1,74 @@ +use crate::analysis::symbols::SymbolId; +use prometeu_analysis::interner::NameId; +use serde::{Deserialize, Serialize}; + +#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, Serialize, Deserialize)] +pub struct TypeId(pub u32); + +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +pub enum TypeKind { + Primitive { name: NameId }, + Optional { inner: TypeId }, + Result { ok: TypeId, err: TypeId }, + Array { inner: TypeId, len: Option }, + Struct { sym: SymbolId }, +} + +#[derive(Debug, Default, Serialize, Deserialize)] +pub struct TypeArena { + pub types: Vec, +} + +impl TypeArena { + pub fn new() -> Self { + Self { types: Vec::new() } + } + + /// Interna um tipo na arena. Atualmente apenas adiciona ao final (append-only), + /// sem realizar de-duplicação. + pub fn intern_type(&mut self, kind: TypeKind) -> TypeId { + let id = TypeId(self.types.len() as u32); + self.types.push(kind); + id + } + + pub fn kind(&self, id: TypeId) -> &TypeKind { + &self.types[id.0 as usize] + } +} + +#[cfg(test)] +mod tests { + use super::*; + // Mock de NameId e SymbolId para testes simplificados se necessário, + // ou usar valores reais. + + #[test] + fn type_arena_push_is_append_only() { + let mut arena = TypeArena::new(); + let name = NameId(0); + let t1 = arena.intern_type(TypeKind::Primitive { name }); + let t2 = arena.intern_type(TypeKind::Optional { inner: t1 }); + + assert_eq!(t1.0, 0); + assert_eq!(t2.0, 1); + assert_eq!(arena.types.len(), 2); + } + + #[test] + fn type_arena_index_is_stable() { + let mut arena = TypeArena::new(); + let name = NameId(0); + let t1 = arena.intern_type(TypeKind::Primitive { name }); + let t2 = arena.intern_type(TypeKind::Optional { inner: t1 }); + + assert!(matches!(arena.kind(t1), TypeKind::Primitive { .. })); + assert!(matches!(arena.kind(t2), TypeKind::Optional { .. })); + + // Adicionar mais tipos não deve mudar os anteriores + let t3 = arena.intern_type(TypeKind::Array { inner: t1, len: None }); + assert!(matches!(arena.kind(t1), TypeKind::Primitive { .. })); + assert!(matches!(arena.kind(t2), TypeKind::Optional { .. })); + assert!(matches!(arena.kind(t3), TypeKind::Array { .. })); + } +}