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, Model>;
19
20pub(crate) static TYPE_INTERNER: OnceLock<LeakyInterner<Model>> = 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 },
28 Float { size: usize },
30 Bool,
32 Char,
34 Str,
36 Any,
38 Never,
40 Unit(usize),
42 Ref(Type),
44 Slice(Type),
46 Tuple(Option<Symbol>, Box<[Type]>),
48 Struct(Option<Symbol>, Box<[(Symbol, Type)]>, bool),
50 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}