1use cl_ast::{At, Expr, fmt::FmtAdapter, types::Symbol};
5use cl_structures::intern::interned::Interned;
6
7use crate::{
8 place::Place,
9 typeinfo::{Model, Type},
10};
11
12use super::{
13 Callable, Environment,
14 builtin::Builtin,
15 error::{Error, IResult},
16 function::Function,
17};
18use std::{collections::HashMap, ops::*, rc::Rc};
19
20type Integer = i128;
43
44#[derive(Clone, Debug, Default)]
46pub enum ConValue {
47 #[default]
49 Empty,
50 Int(Integer),
52 Float(f64),
54 Bool(bool),
56 Char(char),
58 Str(Symbol),
60 String(String),
62 Ref(Place),
64 Slice(Place, usize, usize),
66 Array(Box<[ConValue]>),
68 Tuple(Box<[ConValue]>),
70 Struct(Type, Box<HashMap<Symbol, ConValue>>),
73 TupleStruct(Type, Box<[ConValue]>),
75 Module(Box<HashMap<Symbol, ConValue>>),
77 Quote(Box<At<Expr>>),
79 Function(Rc<Function>),
81 Builtin(&'static Builtin),
83 TypeInfo(Type),
85}
86
87impl ConValue {
88 pub fn truthy(&self) -> IResult<bool> {
90 match self {
91 ConValue::Bool(v) => Ok(*v),
92 ConValue::Int(v) => Ok(*v != 0),
93 _ => Err(Error::TypeError("type implements Truth", self.type_of()))?,
94 }
95 }
96
97 pub fn take(&mut self) -> Self {
98 std::mem::take(self)
99 }
100
101 pub fn is_cheap_to_copy(&self) -> bool {
102 match self {
103 Self::Empty
104 | Self::Int(_)
105 | Self::Float(_)
106 | Self::Bool(_)
107 | Self::Char(_)
108 | Self::Str(_) => true,
109 Self::Ref(_) => true,
110 Self::Slice(_, _, _) => true,
111 Self::Quote(_) => true,
112 Self::Function(_) => true,
113 Self::Builtin(_) => true,
114 Self::TypeInfo(_) => true,
115 Self::Module(_)
116 | Self::String(_)
117 | Self::Array(_)
118 | Self::Tuple(_)
119 | Self::Struct(_, _)
120 | Self::TupleStruct(_, _) => false,
121 }
122 }
123
124 pub fn type_of(&self) -> Type {
125 match self {
126 Self::Empty => Model::Unit(0).already_interned(),
127 Self::Int(_) => Model::default_integer(),
128 Self::Float(_) => Model::default_float(),
129 Self::Bool(_) => Model::Bool.already_interned(),
130 Self::Char(_) => Model::Char.already_interned(),
131 Self::Str(_) => Model::Str.already_interned(),
132 Self::String(_) => Model::Str.already_interned(),
133 Self::Ref(place) => Model::Ref(Model::Any.already_interned()).intern(),
134 Self::Slice(place, _, _) => Model::Slice(Model::Any.already_interned()).intern(),
135 Self::Array(arr) if !arr.is_empty() => Model::Slice(arr[0].type_of()).intern(),
136 Self::Array(_) => Model::Slice(Model::Any.already_interned()).intern(),
137 Self::Tuple(vs) => Model::Tuple(None, vs.iter().map(Self::type_of).collect()).intern(),
138 Self::Struct(ty, _) => *ty,
139 Self::TupleStruct(ty, _) => *ty,
140 Self::Module(_) => todo!("type_of({self})"),
141 Self::Quote(_) => todo!("type_of({self})"),
142 Self::Function(_) => todo!("type_of({self})"),
143 Self::Builtin(_) => todo!("type_of({self})"),
144 Self::TypeInfo(ty) => *ty,
145 }
146 }
147
148 pub fn cast(self, ty: &Model) -> Self {
149 match ty {
150 &Model::Integer { signed, size, min, max } => {
151 let i = match self {
152 Self::Int(v) => v,
153 Self::Float(v) => v as _,
154 Self::Bool(v) => v as _,
155 Self::Char(v) => v as _,
156 Self::TypeInfo(Interned(Model::Unit(d), ..)) => *d as _,
157 _ => return self,
158 };
159 if i == min || i == max {
160 ConValue::Int(i)
161 } else if signed {
162 ConValue::Int(i.wrapping_rem(max))
163 } else {
164 ConValue::Int(i & max)
165 }
166 }
167 Model::Float { size } => {
168 let f = match self {
169 Self::Float(v) => v,
170 Self::Int(v) => v as _,
171 Self::Bool(v) => v as i32 as _,
172 Self::Char(v) => v as i32 as _,
173 Self::TypeInfo(Interned(Model::Unit(d), ..)) => *d as _,
174 _ => return self,
175 };
176 ConValue::Float(f)
177 }
178 Model::Bool => ConValue::Bool(self.truthy().unwrap_or(true)),
179 Model::Char => {
180 let c = match self {
181 Self::Int(v) => v as _,
182 Self::Float(v) => v as _,
183 Self::Bool(v) => v as _,
184 Self::Char(v) => return self,
185 Self::TypeInfo(Interned(Model::Unit(d), ..)) => *d as _,
186 _ => return self,
187 };
188 ConValue::Char(char::from_u32(c).unwrap_or('�'))
189 }
190 Model::Unit(_) => ConValue::Empty,
191 Model::Str => ConValue::String(self.to_string()),
192 _ => self,
193 }
194 }
195
196 pub fn dereference_in<'e>(&'e self, env: &'e Environment) -> IResult<&'e Self> {
197 let mut value = self;
198 while let ConValue::Ref(r) = value {
199 value = r.get(env)?;
200 }
201 Ok(value)
202 }
203
204 #[allow(non_snake_case)]
205 pub fn tuple_struct(id: Type, values: impl Into<Box<[ConValue]>>) -> Self {
206 Self::TupleStruct(id, values.into())
207 }
208 #[allow(non_snake_case)]
209 pub fn Struct(id: Type, values: HashMap<Symbol, ConValue>) -> Self {
210 Self::Struct(id, Box::new(values))
211 }
212
213 pub fn index(self, index: &Self, _env: &Environment) -> IResult<ConValue> {
214 let &Self::Int(index) = index else {
215 Err(Error::TypeError("int", index.type_of()))?
216 };
217 match self {
218 ConValue::Str(string) => string
219 .chars()
220 .nth(index as _)
221 .map(ConValue::Char)
222 .ok_or(Error::OobIndex(index as usize, string.chars().count())),
223 ConValue::String(string) => string
224 .chars()
225 .nth(index as _)
226 .map(ConValue::Char)
227 .ok_or(Error::OobIndex(index as usize, string.chars().count())),
228 ConValue::Array(arr) => arr
229 .get(index as usize)
230 .cloned()
231 .ok_or(Error::OobIndex(index as usize, arr.len())),
232 ConValue::Slice(place, start, len) => {
233 if (index.unsigned_abs() as usize) < len {
234 Ok(ConValue::Ref(place.index(index as _, index < 0)))
235 } else {
236 Err(Error::OobIndex(index.unsigned_abs() as _, len))
237 }
238 }
239 ConValue::Ref(place) => Ok(ConValue::Ref(
240 place.index(index.unsigned_abs() as _, index < 0),
241 )),
242 other => Err(Error::TypeError("type implements Index", other.type_of())),
243 }
244 }
245 cmp! {
246 lt: <;
247 lt_eq: <=;
248 eq: ==;
249 neq: !=;
250 gt_eq: >=;
251 gt: >;
252 }
253 assign! {
254 add_assign: +;
255 bitand_assign: &;
256 bitor_assign: |;
257 bitxor_assign: ^;
258 div_assign: /;
259 mul_assign: *;
260 rem_assign: %;
261 shl_assign: <<;
262 shr_assign: >>;
263 sub_assign: -;
264 }
265}
266
267impl Callable for ConValue {
268 fn name(&self) -> Option<Symbol> {
269 match self {
270 ConValue::Function(func) => func.name(),
271 ConValue::Builtin(func) => func.name(),
273 _ => None,
274 }
275 }
276 fn call(&self, env: &mut Environment, args: &[ConValue]) -> IResult<ConValue> {
277 match self {
278 Self::Function(func) => func.call(env, args),
279 Self::Builtin(func) => func.call(env, args),
280 Self::Module(m) => {
281 if let Some(func) = m.get(&"call".into()) {
282 func.call(env, args)
283 } else {
284 Err(Error::NotCallable(self.clone()))
285 }
286 }
287 Self::Ref(ptr) => {
288 let func = ptr.get(env)?.clone();
290 func.call(env, args)
291 }
292 Self::TypeInfo(idx) => idx.call(env, args),
293 _ => Err(Error::NotCallable(self.clone())),
294 }
295 }
296}
297
298macro into_inner($($fn:ident: $);*$(;)?) {}
299
300macro cmp ($($fn:ident: $op:tt);*$(;)?) {$(
302 pub fn $fn(&self, other: &Self) -> IResult<Self> {
305 match (self, other) {
306 (Self::Empty, Self::Empty) => Ok(Self::Bool(() $op ())),
307 (Self::Int(a), Self::Int(b)) => Ok(Self::Bool(a $op b)),
308 (Self::Float(a), Self::Float(b)) => Ok(Self::Bool(a $op b)),
309 (Self::Bool(a), Self::Bool(b)) => Ok(Self::Bool(a $op b)),
310 (Self::Char(a), Self::Char(b)) => Ok(Self::Bool(a $op b)),
311 (Self::Str(a), Self::Str(b)) => Ok(Self::Bool(&**a $op &**b)),
312 (Self::Str(a), Self::String(b)) => Ok(Self::Bool(&**a $op &**b)),
313 (Self::String(a), Self::Str(b)) => Ok(Self::Bool(&**a $op &**b)),
314 (Self::String(a), Self::String(b)) => Ok(Self::Bool(&**a $op &**b)),
315 (Self::TypeInfo(a), Self::TypeInfo(b)) => Ok(Self::Bool(&*a $op &*b)),
316 (a, _) => Err(Error::TypeError("type implements Cmp", a.type_of()))?,
317 }
318 }
319)*}
320macro assign($( $fn: ident: $op: tt );*$(;)?) {$(
321 pub fn $fn(&mut self, other: Self) -> IResult<()> {
322 *self = (std::mem::take(self) $op other)?;
323 Ok(())
324 }
325)*}
326macro from ($($T:ty => $v:expr),*$(,)?) {
328 $(impl From<$T> for ConValue {
329 fn from(value: $T) -> Self { $v(value.into()) }
330 })*
331}
332impl From<&Symbol> for ConValue {
333 fn from(value: &Symbol) -> Self {
334 ConValue::Str(*value)
335 }
336}
337impl From<Rc<Symbol>> for ConValue {
338 fn from(value: Rc<Symbol>) -> Self {
339 ConValue::Str(value.0.into())
340 }
341}
342from! {
343 Integer => ConValue::Int,
344 f64 => ConValue::Float,
345 bool => ConValue::Bool,
346 char => ConValue::Char,
347 Symbol => ConValue::Str,
348 &str => ConValue::Str,
349 At<Expr> => ConValue::Quote,
350 String => ConValue::String,
351 Function => ConValue::Function,
352 Vec<ConValue> => ConValue::Tuple,
353 &'static Builtin => ConValue::Builtin,
354}
355impl From<()> for ConValue {
356 fn from(_: ()) -> Self {
357 Self::Empty
358 }
359}
360impl From<&[ConValue]> for ConValue {
361 fn from(value: &[ConValue]) -> Self {
362 match value {
363 [] => Self::Empty,
364 [value] => value.clone(),
365 _ => Self::Tuple(value.into()),
366 }
367 }
368}
369
370macro ops($($trait:ty: $fn:ident = [$($match:tt)*])*) {
374 $(impl $trait for ConValue {
375 type Output = IResult<Self>;
376 fn $fn(self, rhs: Self) -> Self::Output {Ok(match (self, rhs) {$($match)*})}
378 })*
379}
380ops! {
381 Add: add = [
382 (ConValue::Empty, ConValue::Empty) => ConValue::Empty,
383 (ConValue::Int(a), ConValue::Int(b)) => ConValue::Int(a.wrapping_add(b)),
384 (ConValue::Float(a), ConValue::Float(b)) => ConValue::Float(a + b),
385 (ConValue::Str(a), ConValue::Str(b)) => (a.to_string() + &*b).into(),
386 (ConValue::Str(a), ConValue::String(b)) => (a.to_string() + &*b).into(),
387 (ConValue::String(a), ConValue::Str(b)) => (a.to_string() + &*b).into(),
388 (ConValue::String(a), ConValue::String(b)) => (a.to_string() + &*b).into(),
389 (ConValue::Str(s), ConValue::Char(c)) => { let mut s = s.to_string(); s.push(c); s.into() }
390 (ConValue::String(s), ConValue::Char(c)) => { let mut s = s.to_string(); s.push(c); s.into() }
391 (ConValue::Char(a), ConValue::Char(b)) => {
392 ConValue::String([a, b].into_iter().collect::<String>())
393 }
394 (a, b) => Err(Error::TypeError(a.type_of(), b.type_of()))?
395 ]
396 BitAnd: bitand = [
397 (ConValue::Empty, ConValue::Empty) => ConValue::Empty,
398 (ConValue::Int(a), ConValue::Int(b)) => ConValue::Int(a & b),
399 (ConValue::Bool(a), ConValue::Bool(b)) => ConValue::Bool(a & b),
400 (a, b) => Err(Error::TypeError(a.type_of(), b.type_of()))?
401 ]
402 BitOr: bitor = [
403 (ConValue::Empty, ConValue::Empty) => ConValue::Empty,
404 (ConValue::Int(a), ConValue::Int(b)) => ConValue::Int(a | b),
405 (ConValue::Bool(a), ConValue::Bool(b)) => ConValue::Bool(a | b),
406 (a, b) => Err(Error::TypeError(a.type_of(), b.type_of()))?
407 ]
408 BitXor: bitxor = [
409 (ConValue::Empty, ConValue::Empty) => ConValue::Empty,
410 (ConValue::Int(a), ConValue::Int(b)) => ConValue::Int(a ^ b),
411 (ConValue::Bool(a), ConValue::Bool(b)) => ConValue::Bool(a ^ b),
412 (a, b) => Err(Error::TypeError(a.type_of(), b.type_of()))?
413 ]
414 Div: div = [
415 (ConValue::Empty, ConValue::Empty) => ConValue::Empty,
416 (ConValue::Int(a), ConValue::Int(b)) => ConValue::Int(a.checked_div(b).unwrap_or_else(|| {
417 eprintln!("Warning: Divide by zero in {a} / {b}"); a
418 })),
419 (ConValue::Float(a), ConValue::Float(b)) => ConValue::Float(a / b),
420 (a, b) => Err(Error::TypeError(a.type_of(), b.type_of()))?
421 ]
422 Mul: mul = [
423 (ConValue::Empty, ConValue::Empty) => ConValue::Empty,
424 (ConValue::Int(a), ConValue::Int(b)) => ConValue::Int(a.wrapping_mul(b)),
425 (ConValue::Float(a), ConValue::Float(b)) => ConValue::Float(a * b),
426 (a, b) => Err(Error::TypeError(a.type_of(), b.type_of()))?
427 ]
428 Rem: rem = [
429 (ConValue::Empty, ConValue::Empty) => ConValue::Empty,
430 (ConValue::Int(a), ConValue::Int(b)) => ConValue::Int(a.checked_rem(b).unwrap_or_else(|| {
431 println!("Warning: Divide by zero in {a} % {b}"); a
432 })),
433 (ConValue::Float(a), ConValue::Float(b)) => ConValue::Float(a % b),
434 (a, b) => Err(Error::TypeError(a.type_of(), b.type_of()))?
435 ]
436 Shl: shl = [
437 (ConValue::Empty, ConValue::Empty) => ConValue::Empty,
438 (ConValue::Int(a), ConValue::Int(b)) => ConValue::Int(a.wrapping_shl(b as _)),
439 (a, ConValue::Int(_)) => Err(Error::TypeError("type implements Shl", a.type_of()))?,
440 (_, b) => Err(Error::TypeError("int", b.type_of()))?
441 ]
442 Shr: shr = [
443 (ConValue::Empty, ConValue::Empty) => ConValue::Empty,
444 (ConValue::Int(a), ConValue::Int(b)) => ConValue::Int(a.wrapping_shr(b as _)),
445 (a, ConValue::Int(_)) => Err(Error::TypeError("type implements Shr", a.type_of()))?,
446 (_, b) => Err(Error::TypeError("int", b.type_of()))?
447 ]
448 Sub: sub = [
449 (ConValue::Empty, ConValue::Empty) => ConValue::Empty,
450 (ConValue::Int(a), ConValue::Int(b)) => ConValue::Int(a.wrapping_sub(b)),
451 (ConValue::Float(a), ConValue::Float(b)) => ConValue::Float(a - b),
452 (a, b) => Err(Error::TypeError(a.type_of(), b.type_of()))?
453 ]
454}
455impl std::fmt::Display for ConValue {
456 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
457 match self {
458 ConValue::Empty => "Empty".fmt(f),
459 ConValue::Int(v) => v.fmt(f),
460 ConValue::Float(v) => v.fmt(f),
461 ConValue::Bool(v) => v.fmt(f),
462 ConValue::Char(v) => v.fmt(f),
463 ConValue::Str(v) => v.fmt(f),
464 ConValue::String(v) => v.fmt(f),
465 ConValue::Ref(v) => write!(f, "&<{}>", v),
466 ConValue::Slice(id, start, len) => write!(f, "&<{id}>[{start}..{len}]"),
467 ConValue::Array(array) => f.delimit('[', ']').list(array, ", "),
468 ConValue::Tuple(tuple) => f.delimit('(', ')').list(tuple, ", "),
469 ConValue::TupleStruct(id, tuple) => f
470 .delimit(format_args!("{}(", id.name()), ")")
471 .list(tuple, ", "),
472 ConValue::Struct(id, map) => {
473 use std::fmt::Write;
474 write!(f, "{} ", id.name())?;
475 let mut f = f.delimit_indented("{", "\n}");
476 for (k, v) in map.iter() {
477 write!(f, "\n{k}: {v},")?;
478 }
479 Ok(())
480 }
481 ConValue::Module(module) => {
482 use std::fmt::Write;
483 let mut f = f.delimit("{", "\n}");
484 for (k, v) in module.iter() {
485 write!(f, "\n{k}: {v},")?;
486 }
487 Ok(())
488 }
489 ConValue::Quote(q) => write!(f, "`{q}`"),
490 ConValue::Function(func) => func.fmt(f),
491 ConValue::Builtin(func) => func.fmt(f),
492 ConValue::TypeInfo(ty) => ty.fmt(f),
493 }
494 }
495}
496
497pub macro cvstruct (
498 $Name:ident {
499 $($member:ident : $expr:expr),*
500 }
501) {{
502 let mut members = HashMap::new();
503 $(members.insert(stringify!($member).into(), ($expr).into());)*
504 ConValue::Struct(Box::new((stringify!($Name).into(), members)))
505}}