Skip to main content

cl_interpret/
typeinfo.rs

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