Skip to main content

cl_interpret/
typeinfo.rs

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