Skip to main content

cl_interpret/
typeinfo.rs

1use std::{collections::HashMap, fmt::Display, sync::OnceLock};
2
3use cl_ast::{Pat, PatOp, fmt::FmtAdapter, types::Symbol};
4use cl_structures::intern::{
5    interned::Interned, leaky_interner::LeakyInterner, string_interner::StringInterner,
6};
7
8use crate::{
9    Callable,
10    convalue::ConValue,
11    env::Environment,
12    error::{Error, IResult},
13};
14
15pub type TypeId = usize;
16pub type Type = Interned<'static, TypeInfo>;
17
18static TYPE_INTERNER: OnceLock<LeakyInterner<TypeInfo>> = OnceLock::new();
19
20/// The elements of a type's value
21#[rustfmt::skip]
22#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
23pub enum Model {
24    Integer { signed: bool, size: usize, min: i128, max: i128 },
25    Float { size: usize },
26    Bool,
27    Char,
28    Str,
29    Any,
30    /// The "never" type (no variants)
31    Never,
32    /// The unit type (no elements)
33    Unit(usize),
34    /// The elements of a tuple
35    Tuple(Box<[Type]>),
36    /// The elements of a struct, and whether they are exhaustive
37    Struct(Box<[(Symbol, Type)]>, bool),
38    /// The variants of an enumeration
39    Enum(Box<[(Symbol, Type)]>),
40}
41
42impl Display for Model {
43    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
44        use std::fmt::Write;
45        match self {
46            Self::Integer { signed, size, .. } => {
47                write!(f, "{}{}", if *signed { "i" } else { "u" }, size * 8)
48            }
49            Self::Float { size } => write!(f, "f{}", size * 8),
50            Self::Bool => "bool".fmt(f),
51            Self::Char => "char".fmt(f),
52            Self::Str => "str".fmt(f),
53            Self::Any => "_".fmt(f),
54            Self::Never => "!".fmt(f),
55            Self::Unit(_) => "()".fmt(f),
56            Self::Tuple(items) => f.delimit("struct (", ")").list(items, ", "),
57            Self::Struct(items, _) => {
58                let mut f = f.delimit("struct { ", "}");
59                for (name, idx) in items {
60                    write!(f, "{name}: {idx}, ")?;
61                }
62                Ok(())
63            }
64            Self::Enum(items) => {
65                let mut f = f.delimit_indented("enum {", "\n}");
66                for (name, idx) in items {
67                    write!(f, "\n{name}: {idx},")?;
68                }
69                Ok(())
70            }
71        }
72    }
73}
74
75/// The unabridged information for a type
76#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
77pub struct TypeInfo {
78    pub ident: Symbol,
79    pub model: Model,
80}
81
82macro make_int($T:ty, $signed: expr) {
83    Model::Integer {
84        signed: $signed,
85        size: size_of::<$T>(),
86        min: <$T>::MIN as _,
87        max: <$T>::MAX as _,
88    }
89}
90
91impl TypeInfo {
92    pub fn new(ident: impl Into<Symbol>, model: Model) -> Self {
93        Self { ident: ident.into(), model }
94    }
95
96    pub fn default_int() -> Type {
97        Self::new("i128", make_int!(i128, true)).intern()
98    }
99
100    #[rustfmt::skip]
101    pub fn defaults() -> Vec<Self> {
102        let unknown = Self::new("_", Model::Any).intern();
103        let types = [
104            Self::new("_", Model::Any),
105            Self::new("unit", Model::Unit(0)),
106            Self::new("bool", Model::Bool),
107            Self::new("char", Model::Char),
108            Self::new("str", Model::Str),
109            Self::new("never", Model::Never),
110            Self::new("f32", Model::Float{size: size_of::<f32>()}),
111            Self::new("f64", Model::Float{size: size_of::<f64>()}),
112            Self::new("i8", make_int!(i8, true)),
113            Self::new("i16", make_int!(i16, true)),
114            Self::new("i32", make_int!(i32, true)),
115            Self::new("i64", make_int!(i64, true)),
116            Self::new("i128", make_int!(i128, true)),
117            Self::new("isize", make_int!(isize, true)),
118            Self::new("int", make_int!(isize, true)),
119            Self::new("u8", make_int!(u8, false)),
120            Self::new("u16", make_int!(u16, false)),
121            Self::new("u32", make_int!(u32, false)),
122            Self::new("u64", make_int!(u64, false)),
123            Self::new("u128", make_int!(u128, false)),
124            Self::new("usize", make_int!(usize, false)),
125            Self::new("uint", make_int!(usize, false)),
126            Self::new("RangeExc", Model::Tuple([unknown, unknown].into())),
127            Self::new("RangeInc", Model::Tuple([unknown, unknown].into())),
128            Self::new("RangeTo", Model::Tuple([unknown].into())),
129            Self::new("RangeToInc", Model::Tuple([unknown].into())),
130        ];
131        types.into()
132    }
133
134    pub fn getattr(&self, attr: Symbol) -> IResult<ConValue> {
135        Ok(match (&self.model, attr.0) {
136            (_, "Self") => ConValue::TypeInfo(self.already_interned()),
137            (&Model::Integer { signed, .. }, "SIGNED") => ConValue::Bool(signed),
138            (&Model::Integer { size, .. }, "SIZE") => ConValue::Int(size as _),
139            (&Model::Integer { size, .. }, "BITS") => ConValue::Int(8 * size as i128),
140            (&Model::Integer { min, .. }, "MIN") => ConValue::Int(min),
141            (&Model::Integer { max, .. }, "MAX") => ConValue::Int(max),
142            (&Model::Float { size }, "SIZE") => ConValue::Int(size as _),
143            (Model::Bool, "SIZE") => ConValue::Int(size_of::<bool>() as _),
144            (Model::Char, "SIZE") => ConValue::Int(size_of::<char>() as _),
145            (Model::Never, _) => Err(Error::NotDefined(attr))?,
146            (Model::Unit(_), "SIZE") => ConValue::Int(0),
147            (Model::Unit(_), _) => Err(Error::NotDefined(attr))?,
148            (Model::Tuple(items), "ARITY") => ConValue::Int(items.len() as _),
149            (Model::Struct(items, _), "NAMES") => {
150                ConValue::Array(items.iter().map(|(n, _)| ConValue::Str(*n)).collect())
151            }
152            (Model::Struct(items, _), "TYPES") => {
153                ConValue::Array(items.iter().map(|(_, t)| ConValue::TypeInfo(*t)).collect())
154            }
155            (Model::Struct(items, exhaustive), _) => items
156                .iter()
157                .find_map(|&(name, ty)| (name == attr).then_some(ConValue::TypeInfo(ty)))
158                .ok_or(Error::NotDefined(attr))?,
159            (Model::Enum(items), _) => items
160                .iter()
161                .find_map(|&(name, ty)| (name == attr).then_some(ConValue::TypeInfo(ty)))
162                .ok_or(Error::NotDefined(attr))?,
163            (model, _) => Err(Error::NotDefined(attr))?,
164        })
165    }
166
167    pub fn make_tuple(&self, values: Box<[ConValue]>) -> IResult<ConValue> {
168        let typeids = match &self.model {
169            Model::Tuple(typeids) => typeids,
170            _ => return Err(Error::TypeError(self.ident.to_ref(), "not that")),
171        };
172        if typeids.len() != values.len() {
173            return Err(Error::ArgNumber(typeids.len(), values.len()));
174        }
175        Ok(ConValue::TupleStruct(self.already_interned(), values))
176    }
177
178    pub fn make_struct(&self, mut values: HashMap<Symbol, ConValue>) -> IResult<ConValue> {
179        let (model, exhaustive) = match &self.model {
180            Model::Struct(model, exhaustive) => (model, exhaustive),
181            _ => Err(Error::TypeError(self.ident.to_ref(), "not that"))?,
182        };
183
184        let mut members = HashMap::new();
185        if *exhaustive {
186            for (key, _id) in model {
187                let value = values.get_mut(key).ok_or(Error::NotInitialized(*key))?;
188                members.insert(*key, value.take());
189            }
190        } else {
191            members = values;
192        }
193
194        Ok(ConValue::Struct(self.already_interned(), Box::new(members)))
195    }
196
197    pub fn intern(self) -> Type {
198        TYPE_INTERNER
199            .get_or_init(LeakyInterner::new)
200            .get_or_insert(self)
201    }
202    pub fn already_interned(&self) -> Type {
203        TYPE_INTERNER
204            .get_or_init(LeakyInterner::new)
205            .get(self)
206            .expect(&self.ident)
207    }
208}
209
210impl Callable for TypeInfo {
211    fn call(&self, env: &mut Environment, args: &[ConValue]) -> IResult<ConValue> {
212        match &self.model {
213            Model::Tuple(_) => self.make_tuple(args.into()),
214            _ => Err(Error::NotCallable(ConValue::TypeInfo(
215                self.already_interned(),
216            )))?,
217        }
218    }
219
220    fn name(&self) -> Option<Symbol> {
221        Some(self.ident)
222    }
223}
224
225impl std::fmt::Display for TypeInfo {
226    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
227        let Self { ident: _, model } = self;
228        write!(f, "{model}")
229    }
230}