use std::collections::HashMap;
use logicaffeine_base::{Interner, Symbol};
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum FieldType {
Primitive(Symbol),
Named(Symbol),
Generic { base: Symbol, params: Vec<FieldType> },
TypeParam(Symbol),
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct FieldDef {
pub name: Symbol,
pub ty: FieldType,
pub is_public: bool,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct VariantDef {
pub name: Symbol,
pub fields: Vec<FieldDef>, }
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum TypeDef {
Primitive,
Struct {
fields: Vec<FieldDef>,
generics: Vec<Symbol>, is_portable: bool, is_shared: bool, },
Enum {
variants: Vec<VariantDef>,
generics: Vec<Symbol>, is_portable: bool, is_shared: bool, },
Generic { param_count: usize },
Alias { target: Symbol },
}
#[derive(Debug, Default, Clone)]
pub struct TypeRegistry {
types: HashMap<Symbol, TypeDef>,
}
impl TypeRegistry {
pub fn new() -> Self {
Self::default()
}
pub fn register(&mut self, name: Symbol, def: TypeDef) {
self.types.insert(name, def);
}
pub fn is_type(&self, name: Symbol) -> bool {
self.types.contains_key(&name)
}
pub fn is_generic(&self, name: Symbol) -> bool {
match self.types.get(&name) {
Some(TypeDef::Generic { .. }) => true,
Some(TypeDef::Struct { generics, .. }) => !generics.is_empty(),
Some(TypeDef::Enum { generics, .. }) => !generics.is_empty(),
_ => false,
}
}
pub fn get_generics(&self, name: Symbol) -> Option<&[Symbol]> {
match self.types.get(&name)? {
TypeDef::Struct { generics, .. } => Some(generics),
TypeDef::Enum { generics, .. } => Some(generics),
_ => None,
}
}
pub fn get(&self, name: Symbol) -> Option<&TypeDef> {
self.types.get(&name)
}
pub fn iter_types(&self) -> impl Iterator<Item = (&Symbol, &TypeDef)> {
self.types.iter()
}
pub fn find_variant(&self, variant_name: Symbol) -> Option<(Symbol, &VariantDef)> {
for (enum_name, type_def) in &self.types {
if let TypeDef::Enum { variants, .. } = type_def {
for variant in variants {
if variant.name == variant_name {
return Some((*enum_name, variant));
}
}
}
}
None
}
pub fn is_variant(&self, name: Symbol) -> bool {
self.find_variant(name).is_some()
}
pub fn with_primitives(interner: &mut Interner) -> Self {
let mut reg = Self::new();
reg.register(interner.intern("Nat"), TypeDef::Primitive);
reg.register(interner.intern("Int"), TypeDef::Primitive);
reg.register(interner.intern("Text"), TypeDef::Primitive);
reg.register(interner.intern("Bool"), TypeDef::Primitive);
reg.register(interner.intern("Boolean"), TypeDef::Primitive);
reg.register(interner.intern("Unit"), TypeDef::Primitive);
reg.register(interner.intern("Real"), TypeDef::Primitive); reg.register(interner.intern("Char"), TypeDef::Primitive); reg.register(interner.intern("Byte"), TypeDef::Primitive); reg.register(interner.intern("Word8"), TypeDef::Primitive);
reg.register(interner.intern("Word16"), TypeDef::Primitive);
reg.register(interner.intern("Word32"), TypeDef::Primitive);
reg.register(interner.intern("Word64"), TypeDef::Primitive);
reg.register(interner.intern("Lanes8Word32"), TypeDef::Primitive);
reg.register(interner.intern("Lanes4Word32"), TypeDef::Primitive);
reg.register(interner.intern("Lanes16Word8"), TypeDef::Primitive);
reg.register(interner.intern("Lanes4Word64"), TypeDef::Primitive);
reg.register(interner.intern("Lanes16Word16"), TypeDef::Primitive);
reg.register(interner.intern("List"), TypeDef::Generic { param_count: 1 });
reg.register(interner.intern("Seq"), TypeDef::Generic { param_count: 1 }); reg.register(interner.intern("Map"), TypeDef::Generic { param_count: 2 }); reg.register(interner.intern("Set"), TypeDef::Generic { param_count: 1 }); reg.register(interner.intern("Option"), TypeDef::Generic { param_count: 1 });
reg.register(interner.intern("Maybe"), TypeDef::Generic { param_count: 1 });
reg.register(interner.intern("Result"), TypeDef::Generic { param_count: 2 });
reg.register(interner.intern("Quantity"), TypeDef::Generic { param_count: 1 });
reg
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn registry_stores_and_retrieves() {
let mut interner = Interner::new();
let mut registry = TypeRegistry::new();
let foo = interner.intern("Foo");
registry.register(foo, TypeDef::Primitive);
assert!(registry.is_type(foo));
assert!(!registry.is_generic(foo));
}
}