Skip to main content

cl_interpret/
convalue.rs

1//! [Conlang Values](ConValue) in the dynamically typed AST interpreter.
2//!
3//! > The most permanent fix is a temporary one.
4use 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
20/*
21A Value can be:
22- A Primitive (Empty, isize, etc.)
23- A Record (Array, Tuple, Struct)
24- A Variant (discriminant, Value) pair
25
26array [
27    10,     // 0
28    20,     // 1
29]
30
31tuple (
32    10,     // 0
33    20,     // 1
34)
35
36struct {
37    x: 10,  // x => 0
38    y: 20,  // y => 1
39}
40*/
41
42type Integer = i128;
43
44/// A Conlang value stores data in the interpreter
45#[derive(Clone, Debug, Default)]
46pub enum ConValue {
47    /// The empty/unit `()` type
48    #[default]
49    Empty,
50    /// An integer
51    Int(Integer),
52    /// A floating point number
53    Float(f64),
54    /// A boolean
55    Bool(bool),
56    /// A unicode character
57    Char(char),
58    /// A string literal
59    Str(Symbol),
60    /// A dynamic string
61    String(String),
62    /// A reference
63    Ref(Place),
64    /// A reference to an array
65    Slice(Place, usize, usize),
66    /// An Array
67    Array(Box<[ConValue]>),
68    /// A tuple
69    Tuple(Box<[ConValue]>),
70    // TODO: Instead of storing the identifier, store the index of the struct module
71    /// A value of a product type
72    Struct(Type, Box<HashMap<Symbol, ConValue>>),
73    /// A value of a product type with anonymous members
74    TupleStruct(Type, Box<[ConValue]>),
75    /// An entire namespace
76    Module(Box<HashMap<Symbol, ConValue>>),
77    /// A quoted expression
78    Quote(Box<At<Expr>>),
79    /// A callable thing
80    Function(Rc<Function>),
81    /// A built-in function
82    Builtin(&'static Builtin),
83    /// The definition of a type, by index
84    TypeInfo(Type),
85}
86
87impl ConValue {
88    /// Gets whether the current value is true or false
89    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::Closure(func) => func.name(),
272            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                // Move onto stack, and call
289                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
300/// Templates comparison functions for [ConValue]
301macro cmp ($($fn:ident: $op:tt);*$(;)?) {$(
302    /// TODO: Remove when functions are implemented:
303    ///       Desugar into function calls
304    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)*}
326/// Implements [From] for an enum with 1-tuple variants
327macro 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
370/// Implements binary [std::ops] traits for [ConValue]
371///
372/// TODO: Desugar operators into function calls
373macro ops($($trait:ty: $fn:ident = [$($match:tt)*])*) {
374    $(impl $trait for ConValue {
375        type Output = IResult<Self>;
376        /// TODO: Desugar operators into function calls
377        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}}