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.ident.to_ref(),
138 ConValue::TupleStruct(ty, _) => ty.ident.to_ref(),
139 ConValue::Module(_) => "",
140 ConValue::Quote(_) => "Quote",
141 ConValue::Function(_) => "Fn",
142 ConValue::Builtin(_) => "Fn",
143 ConValue::TypeInfo(ty) => ty.ident.to_ref(),
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 #[allow(non_snake_case)]
196 pub fn tuple_struct(id: Type, values: impl Into<Box<[ConValue]>>) -> Self {
197 Self::TupleStruct(id, values.into())
198 }
199 #[allow(non_snake_case)]
200 pub fn Struct(id: Type, values: HashMap<Symbol, ConValue>) -> Self {
201 Self::Struct(id, Box::new(values))
202 }
203
204 pub fn index(self, index: &Self, _env: &Environment) -> IResult<ConValue> {
205 let &Self::Int(index) = index else {
206 Err(Error::TypeError("int", index.typename()))?
207 };
208 match self {
209 ConValue::Str(string) => string
210 .chars()
211 .nth(index as _)
212 .map(ConValue::Char)
213 .ok_or(Error::OobIndex(index as usize, string.chars().count())),
214 ConValue::String(string) => string
215 .chars()
216 .nth(index as _)
217 .map(ConValue::Char)
218 .ok_or(Error::OobIndex(index as usize, string.chars().count())),
219 ConValue::Array(arr) => arr
220 .get(index as usize)
221 .cloned()
222 .ok_or(Error::OobIndex(index as usize, arr.len())),
223 ConValue::Slice(place, len) => {
224 if (index.unsigned_abs() as usize) < len {
225 Ok(ConValue::Ref(place.index(index as _, index < 0)))
226 } else {
227 Err(Error::OobIndex(index.unsigned_abs() as _, len))
228 }
229 }
230 ConValue::Ref(place) => Ok(ConValue::Ref(
231 place.index(index.unsigned_abs() as _, index < 0),
232 )),
233 other => Err(Error::TypeError("type implements Index", other.typename())),
234 }
235 }
236 cmp! {
237 lt: false, <;
238 lt_eq: true, <=;
239 eq: true, ==;
240 neq: false, !=;
241 gt_eq: true, >=;
242 gt: false, >;
243 }
244 assign! {
245 add_assign: +;
246 bitand_assign: &;
247 bitor_assign: |;
248 bitxor_assign: ^;
249 div_assign: /;
250 mul_assign: *;
251 rem_assign: %;
252 shl_assign: <<;
253 shr_assign: >>;
254 sub_assign: -;
255 }
256}
257
258impl Callable for ConValue {
259 fn name(&self) -> Option<Symbol> {
260 match self {
261 ConValue::Function(func) => func.name(),
262 ConValue::Builtin(func) => func.name(),
264 _ => None,
265 }
266 }
267 fn call(&self, env: &mut Environment, args: &[ConValue]) -> IResult<ConValue> {
268 match self {
269 Self::Function(func) => func.call(env, args),
270 Self::Builtin(func) => func.call(env, args),
271 Self::Module(m) => {
272 if let Some(func) = m.get(&"call".into()) {
273 func.call(env, args)
274 } else {
275 Err(Error::NotCallable(self.clone()))
276 }
277 }
278 Self::Ref(ptr) => {
279 let func = ptr.get(env)?.clone();
281 func.call(env, args)
282 }
283 Self::TypeInfo(idx) => idx.call(env, args),
284 _ => Err(Error::NotCallable(self.clone())),
285 }
286 }
287}
288macro cmp ($($fn:ident: $empty:literal, $op:tt);*$(;)?) {$(
290 pub fn $fn(&self, other: &Self) -> IResult<Self> {
293 match (self, other) {
294 (Self::Empty, Self::Empty) => Ok(Self::Bool($empty)),
295 (Self::Int(a), Self::Int(b)) => Ok(Self::Bool(a $op b)),
296 (Self::Float(a), Self::Float(b)) => Ok(Self::Bool(a $op b)),
297 (Self::Bool(a), Self::Bool(b)) => Ok(Self::Bool(a $op b)),
298 (Self::Char(a), Self::Char(b)) => Ok(Self::Bool(a $op b)),
299 (Self::Str(a), Self::Str(b)) => Ok(Self::Bool(&**a $op &**b)),
300 (Self::Str(a), Self::String(b)) => Ok(Self::Bool(&**a $op &**b)),
301 (Self::String(a), Self::Str(b)) => Ok(Self::Bool(&**a $op &**b)),
302 (Self::String(a), Self::String(b)) => Ok(Self::Bool(&**a $op &**b)),
303 (Self::TypeInfo(a), Self::TypeInfo(b)) => Ok(Self::Bool(&*a $op &*b)),
304 (a, _) => Err(Error::TypeError("type implements Cmp", a.typename()))?,
305 }
306 }
307)*}
308macro assign($( $fn: ident: $op: tt );*$(;)?) {$(
309 pub fn $fn(&mut self, other: Self) -> IResult<()> {
310 *self = (std::mem::take(self) $op other)?;
311 Ok(())
312 }
313)*}
314macro from ($($T:ty => $v:expr),*$(,)?) {
316 $(impl From<$T> for ConValue {
317 fn from(value: $T) -> Self { $v(value.into()) }
318 })*
319}
320impl From<&Symbol> for ConValue {
321 fn from(value: &Symbol) -> Self {
322 ConValue::Str(*value)
323 }
324}
325impl From<Rc<Symbol>> for ConValue {
326 fn from(value: Rc<Symbol>) -> Self {
327 ConValue::Str(value.0.into())
328 }
329}
330from! {
331 Integer => ConValue::Int,
332 f64 => ConValue::Float,
333 bool => ConValue::Bool,
334 char => ConValue::Char,
335 Symbol => ConValue::Str,
336 &str => ConValue::Str,
337 Expr => ConValue::Quote,
338 String => ConValue::String,
339 Function => ConValue::Function,
340 Vec<ConValue> => ConValue::Tuple,
341 &'static Builtin => ConValue::Builtin,
342}
343impl From<()> for ConValue {
344 fn from(_: ()) -> Self {
345 Self::Empty
346 }
347}
348impl From<&[ConValue]> for ConValue {
349 fn from(value: &[ConValue]) -> Self {
350 match value {
351 [] => Self::Empty,
352 [value] => value.clone(),
353 _ => Self::Tuple(value.into()),
354 }
355 }
356}
357
358macro ops($($trait:ty: $fn:ident = [$($match:tt)*])*) {
362 $(impl $trait for ConValue {
363 type Output = IResult<Self>;
364 fn $fn(self, rhs: Self) -> Self::Output {Ok(match (self, rhs) {$($match)*})}
366 })*
367}
368ops! {
369 Add: add = [
370 (ConValue::Empty, ConValue::Empty) => ConValue::Empty,
371 (ConValue::Int(a), ConValue::Int(b)) => ConValue::Int(a.wrapping_add(b)),
372 (ConValue::Float(a), ConValue::Float(b)) => ConValue::Float(a + b),
373 (ConValue::Str(a), ConValue::Str(b)) => (a.to_string() + &*b).into(),
374 (ConValue::Str(a), ConValue::String(b)) => (a.to_string() + &*b).into(),
375 (ConValue::String(a), ConValue::Str(b)) => (a.to_string() + &*b).into(),
376 (ConValue::String(a), ConValue::String(b)) => (a.to_string() + &*b).into(),
377 (ConValue::Str(s), ConValue::Char(c)) => { let mut s = s.to_string(); s.push(c); s.into() }
378 (ConValue::String(s), ConValue::Char(c)) => { let mut s = s.to_string(); s.push(c); s.into() }
379 (ConValue::Char(a), ConValue::Char(b)) => {
380 ConValue::String([a, b].into_iter().collect::<String>())
381 }
382 (a, b) => Err(Error::TypeError(a.typename(), b.typename()))?
383 ]
384 BitAnd: bitand = [
385 (ConValue::Empty, ConValue::Empty) => ConValue::Empty,
386 (ConValue::Int(a), ConValue::Int(b)) => ConValue::Int(a & b),
387 (ConValue::Bool(a), ConValue::Bool(b)) => ConValue::Bool(a & b),
388 (a, b) => Err(Error::TypeError(a.typename(), b.typename()))?
389 ]
390 BitOr: bitor = [
391 (ConValue::Empty, ConValue::Empty) => ConValue::Empty,
392 (ConValue::Int(a), ConValue::Int(b)) => ConValue::Int(a | b),
393 (ConValue::Bool(a), ConValue::Bool(b)) => ConValue::Bool(a | b),
394 (a, b) => Err(Error::TypeError(a.typename(), b.typename()))?
395 ]
396 BitXor: bitxor = [
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.typename(), b.typename()))?
401 ]
402 Div: div = [
403 (ConValue::Empty, ConValue::Empty) => ConValue::Empty,
404 (ConValue::Int(a), ConValue::Int(b)) => ConValue::Int(a.checked_div(b).unwrap_or_else(|| {
405 eprintln!("Warning: Divide by zero in {a} / {b}"); a
406 })),
407 (ConValue::Float(a), ConValue::Float(b)) => ConValue::Float(a / b),
408 (a, b) => Err(Error::TypeError(a.typename(), b.typename()))?
409 ]
410 Mul: mul = [
411 (ConValue::Empty, ConValue::Empty) => ConValue::Empty,
412 (ConValue::Int(a), ConValue::Int(b)) => ConValue::Int(a.wrapping_mul(b)),
413 (ConValue::Float(a), ConValue::Float(b)) => ConValue::Float(a * b),
414 (a, b) => Err(Error::TypeError(a.typename(), b.typename()))?
415 ]
416 Rem: rem = [
417 (ConValue::Empty, ConValue::Empty) => ConValue::Empty,
418 (ConValue::Int(a), ConValue::Int(b)) => ConValue::Int(a.checked_rem(b).unwrap_or_else(|| {
419 println!("Warning: Divide by zero in {a} % {b}"); a
420 })),
421 (ConValue::Float(a), ConValue::Float(b)) => ConValue::Float(a % b),
422 (a, b) => Err(Error::TypeError(a.typename(), b.typename()))?
423 ]
424 Shl: shl = [
425 (ConValue::Empty, ConValue::Empty) => ConValue::Empty,
426 (ConValue::Int(a), ConValue::Int(b)) => ConValue::Int(a.wrapping_shl(b as _)),
427 (a, ConValue::Int(_)) => Err(Error::TypeError("type implements Shl", a.typename()))?,
428 (_, b) => Err(Error::TypeError("int", b.typename()))?
429 ]
430 Shr: shr = [
431 (ConValue::Empty, ConValue::Empty) => ConValue::Empty,
432 (ConValue::Int(a), ConValue::Int(b)) => ConValue::Int(a.wrapping_shr(b as _)),
433 (a, ConValue::Int(_)) => Err(Error::TypeError("type implements Shr", a.typename()))?,
434 (_, b) => Err(Error::TypeError("int", b.typename()))?
435 ]
436 Sub: sub = [
437 (ConValue::Empty, ConValue::Empty) => ConValue::Empty,
438 (ConValue::Int(a), ConValue::Int(b)) => ConValue::Int(a.wrapping_sub(b)),
439 (ConValue::Float(a), ConValue::Float(b)) => ConValue::Float(a - b),
440 (a, b) => Err(Error::TypeError(a.typename(), b.typename()))?
441 ]
442}
443impl std::fmt::Display for ConValue {
444 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
445 match self {
446 ConValue::Empty => "Empty".fmt(f),
447 ConValue::Int(v) => v.fmt(f),
448 ConValue::Float(v) => v.fmt(f),
449 ConValue::Bool(v) => v.fmt(f),
450 ConValue::Char(v) => v.fmt(f),
451 ConValue::Str(v) => v.fmt(f),
452 ConValue::String(v) => v.fmt(f),
453 ConValue::Ref(v) => write!(f, "&<{}>", v),
454 ConValue::Slice(id, len) => write!(f, "&<{id}>[{len}..]"),
455 ConValue::Array(array) => f.delimit('[', ']').list(array, ", "),
456 ConValue::Tuple(tuple) => f.delimit('(', ')').list(tuple, ", "),
457 ConValue::TupleStruct(id, tuple) => f
458 .delimit(format_args!("{} (", id.ident), ")")
459 .list(tuple, ", "),
460 ConValue::Struct(id, map) => {
461 use std::fmt::Write;
462 write!(f, "{} ", id.ident)?;
463 let mut f = f.delimit_indented("{", "\n}");
464 for (k, v) in map.iter() {
465 write!(f, "\n{k}: {v},")?;
466 }
467 Ok(())
468 }
469 ConValue::Module(module) => {
470 use std::fmt::Write;
471 let mut f = f.delimit("{", "\n}");
472 for (k, v) in module.iter() {
473 write!(f, "\n{k}: {v},")?;
474 }
475 Ok(())
476 }
477 ConValue::Quote(q) => write!(f, "`{q}`"),
478 ConValue::Function(func) => func.fmt(f),
479 ConValue::Builtin(func) => func.fmt(f),
480 ConValue::TypeInfo(ty) => ty.fmt(f),
481 }
482 }
483}
484
485pub macro cvstruct (
486 $Name:ident {
487 $($member:ident : $expr:expr),*
488 }
489) {{
490 let mut members = HashMap::new();
491 $(members.insert(stringify!($member).into(), ($expr).into());)*
492 ConValue::Struct(Box::new((stringify!($Name).into(), members)))
493}}