1use 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#[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 Never,
34 Unit(usize),
36 Ref(Type),
38 Slice(Type),
40 Tuple(Box<[Type]>),
42 Struct(Box<[(Symbol, Type)]>, bool),
44 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#[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}