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