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
18pub(crate) static 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    /// Reference to a value of [Type]
35    Ref(Type),
36    /// Slice of a list of [Type]
37    Slice(Type),
38    /// The elements of a tuple
39    Tuple(Box<[Type]>),
40    /// The elements of a struct, and whether they are exhaustive
41    Struct(Box<[(Symbol, Type)]>, bool),
42    /// The variants of an enumeration
43    Enum(Box<[(Symbol, Type)]>),
44}
45
46impl Display for Model {
47    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
48        use std::fmt::Write;
49        match self {
50            Self::Integer { signed, size, .. } => {
51                write!(f, "{}{}", if *signed { "i" } else { "u" }, size * 8)
52            }
53            Self::Float { size } => write!(f, "f{}", size * 8),
54            Self::Bool => "bool".fmt(f),
55            Self::Char => "char".fmt(f),
56            Self::Str => "str".fmt(f),
57            Self::Any => "_".fmt(f),
58            Self::Never => "!".fmt(f),
59            Self::Unit(_) => "()".fmt(f),
60            Self::Ref(t) => write!(f, "&{t}"),
61            Self::Slice(t) => write!(f, "[{t}]"),
62            Self::Tuple(items) => f.delimit("(", ")").list(items, ", "),
63            Self::Struct(items, _) => {
64                let mut f = f.delimit("{", " }");
65                for (idx, (name, ty)) in items.iter().enumerate() {
66                    if idx > 0 {
67                        write!(f, ",")?;
68                    }
69                    write!(f, " {name}: {ty}")?;
70                }
71                Ok(())
72            }
73            Self::Enum(items) => {
74                let mut f = f.delimit_indented("enum {", "\n}");
75                for (name, idx) in items {
76                    write!(f, "\n{name}: {idx},")?;
77                }
78                Ok(())
79            }
80        }
81    }
82}
83
84/// The unabridged information for a type
85#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
86pub struct TypeInfo {
87    pub ident: Option<Symbol>,
88    pub model: Model,
89}
90
91macro make_int($T:ty, $signed: expr) {
92    Model::Integer {
93        signed: $signed,
94        size: size_of::<$T>(),
95        min: <$T>::MIN as _,
96        max: <$T>::MAX as _,
97    }
98}
99
100impl TypeInfo {
101    pub fn new(ident: impl Into<Symbol>, model: Model) -> Self {
102        Self { ident: Some(ident.into()), model }
103    }
104
105    pub fn name(&self) -> &'static str {
106        match self.ident {
107            Some(name) => name.to_ref(),
108            None => "_",
109        }
110    }
111
112    pub fn default_int() -> Type {
113        Self::new("i128", make_int!(i128, true)).intern()
114    }
115
116    #[rustfmt::skip]
117    pub fn defaults() -> Vec<Self> {
118        let unknown = Self::new("_", Model::Any).intern();
119        let types = [
120            Self::new("_", Model::Any),
121            Self::new("unit", Model::Unit(0)),
122            Self::new("bool", Model::Bool),
123            Self::new("char", Model::Char),
124            Self::new("str", Model::Str),
125            Self::new("never", Model::Never),
126            Self::new("f32", Model::Float{size: size_of::<f32>()}),
127            Self::new("f64", Model::Float{size: size_of::<f64>()}),
128            Self::new("i8", make_int!(i8, true)),
129            Self::new("i16", make_int!(i16, true)),
130            Self::new("i32", make_int!(i32, true)),
131            Self::new("i64", make_int!(i64, true)),
132            Self::new("i128", make_int!(i128, true)),
133            Self::new("isize", make_int!(isize, true)),
134            Self::new("int", make_int!(isize, true)),
135            Self::new("u8", make_int!(u8, false)),
136            Self::new("u16", make_int!(u16, false)),
137            Self::new("u32", make_int!(u32, false)),
138            Self::new("u64", make_int!(u64, false)),
139            Self::new("u128", make_int!(u128, false)),
140            Self::new("usize", make_int!(usize, false)),
141            Self::new("uint", make_int!(usize, false)),
142            Self::new("RangeExc", Model::Tuple([unknown, unknown].into())),
143            Self::new("RangeInc", Model::Tuple([unknown, unknown].into())),
144            Self::new("RangeTo", Model::Tuple([unknown].into())),
145            Self::new("RangeToInc", Model::Tuple([unknown].into())),
146        ];
147        types.into()
148    }
149
150    pub fn getattr(&self, attr: Symbol) -> IResult<ConValue> {
151        Ok(match (&self.model, attr.0) {
152            (_, "Self") => ConValue::TypeInfo(self.already_interned()),
153            (&Model::Integer { signed, .. }, "SIGNED") => ConValue::Bool(signed),
154            (&Model::Integer { size, .. }, "SIZE") => ConValue::Int(size as _),
155            (&Model::Integer { size, .. }, "BITS") => ConValue::Int(8 * size as i128),
156            (&Model::Integer { min, .. }, "MIN") => ConValue::Int(min),
157            (&Model::Integer { max, .. }, "MAX") => ConValue::Int(max),
158            (&Model::Float { size }, "SIZE") => ConValue::Int(size as _),
159            (&Model::Float { .. }, "INF") => ConValue::Float(f64::INFINITY),
160            (&Model::Float { .. }, "NAN" | "NaN") => ConValue::Float(f64::NAN),
161            (Model::Bool, "SIZE") => ConValue::Int(size_of::<bool>() as _),
162            (Model::Char, "SIZE") => ConValue::Int(size_of::<char>() as _),
163            (Model::Never, _) => Err(Error::NotDefined(attr))?,
164            (Model::Unit(_), "SIZE") => ConValue::Int(0),
165            (Model::Unit(_), _) => Err(Error::NotDefined(attr))?,
166            (Model::Tuple(items), "ARITY") => ConValue::Int(items.len() as _),
167            (Model::Struct(items, _), "NAMES") => {
168                ConValue::Array(items.iter().map(|(n, _)| ConValue::Str(*n)).collect())
169            }
170            (Model::Struct(items, _), "TYPES") => {
171                ConValue::Array(items.iter().map(|(_, t)| ConValue::TypeInfo(*t)).collect())
172            }
173            (Model::Struct(items, _), "MEMBERS") => ConValue::Array(
174                items
175                    .iter()
176                    .map(|(n, t)| {
177                        ConValue::Tuple([ConValue::Str(*n), ConValue::TypeInfo(*t)].into())
178                    })
179                    .collect(),
180            ),
181            (Model::Struct(items, exhaustive), _) => items
182                .iter()
183                .find_map(|&(name, ty)| (name == attr).then_some(ConValue::TypeInfo(ty)))
184                .ok_or(Error::NotDefined(attr))?,
185            (Model::Enum(items), _) => items
186                .iter()
187                .find_map(|&(name, ty)| (name == attr).then_some(ConValue::TypeInfo(ty)))
188                .ok_or(Error::NotDefined(attr))?,
189            (model, _) => Err(Error::NotDefined(attr))?,
190        })
191    }
192
193    pub fn make_tuple(&self, values: Box<[ConValue]>) -> IResult<ConValue> {
194        let Model::Tuple(typeids) = &self.model else {
195            Err(Error::TypeError(self.name(), "tuple struct"))?
196        };
197        if typeids.len() != values.len() {
198            return Err(Error::ArgNumber(typeids.len(), values.len()));
199        }
200        Ok(ConValue::TupleStruct(self.already_interned(), values))
201    }
202
203    pub fn make_struct(&self, mut values: HashMap<Symbol, ConValue>) -> IResult<ConValue> {
204        let Model::Struct(model, exhaustive) = &self.model else {
205            Err(Error::TypeError(self.name(), "struct"))?
206        };
207
208        let mut members = HashMap::new();
209        if *exhaustive {
210            for (key, _id) in model {
211                let value = values.get_mut(key).ok_or(Error::NotInitialized(*key))?;
212                members.insert(*key, value.take());
213            }
214        } else {
215            members = values;
216        }
217
218        Ok(ConValue::Struct(self.already_interned(), Box::new(members)))
219    }
220
221    pub fn intern(self) -> Type {
222        TYPE_INTERNER
223            .get_or_init(LeakyInterner::new)
224            .get_or_insert(self)
225    }
226    pub fn already_interned(&self) -> Type {
227        TYPE_INTERNER
228            .get_or_init(LeakyInterner::new)
229            .get(self)
230            .unwrap_or_else(|| panic!("{}", self.name()))
231    }
232}
233
234impl Callable for TypeInfo {
235    fn call(&self, env: &mut Environment, args: &[ConValue]) -> IResult<ConValue> {
236        match &self.model {
237            Model::Tuple(_) => self.make_tuple(args.into()),
238            _ => Err(Error::NotCallable(ConValue::TypeInfo(
239                self.already_interned(),
240            )))?,
241        }
242    }
243
244    fn name(&self) -> Option<Symbol> {
245        self.ident
246    }
247}
248
249impl std::fmt::Display for TypeInfo {
250    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
251        let Self { ident, model } = self;
252        let Some(ident) = ident else {
253            return model.fmt(f);
254        };
255        match model {
256            Model::Any | Model::Unit(0) => write!(f, "{ident}"),
257            Model::Unit(n) => write!(f, "{ident} = {n}"),
258            Model::Integer { .. }
259            | Model::Float { .. }
260            | Model::Bool
261            | Model::Char
262            | Model::Str
263            | Model::Never
264            | Model::Ref(_)
265            | Model::Slice(_) => write!(f, "{model}"),
266            Model::Tuple(_) | Model::Struct(_, _) | Model::Enum(_) => {
267                write!(f, "{ident} {model}")
268            }
269        }
270    }
271}