use crate::parser::*; use imbl::*; use std::cell::RefCell; use std::fmt; use std::rc::Rc; #[derive(Clone, Debug, PartialEq)] pub struct Fn<'src> { pub name: &'src str, pub body: &'src Vec>, } #[derive(Debug, PartialEq)] pub enum Value<'src> { Nil, Placeholder, Boolean(bool), Number(f64), Keyword(&'src str), String(&'src str), // on the heap for now Tuple(Rc>), Args(Rc>), // ref-counted, immutable, persistent List(Vector), // ref-counted, immutable, persistent Dict(HashMap<&'src str, Self>), Box(&'src str, Rc>), Fn(Rc>), // Set(HashSet), // Sets are hard // Sets require Eq // Eq is not implemented on f64, because NaNs // We could use ordered_float::NotNan // Let's defer that // We're not really using sets in Ludus // Other things we're not implementing yet: // pkgs, nses, tests } impl<'src> Clone for Value<'src> { fn clone(&self) -> Value<'src> { match self { Value::Nil => Value::Nil, Value::Boolean(b) => Value::Boolean(b.clone()), Value::String(s) => Value::String(s), Value::Keyword(s) => Value::Keyword(s), Value::Number(n) => Value::Number(n.clone()), Value::Tuple(t) => Value::Tuple(t.clone()), Value::Args(a) => Value::Args(a.clone()), Value::Fn(f) => Value::Fn(f.clone()), Value::List(l) => Value::List(l.clone()), Value::Dict(d) => Value::Dict(d.clone()), Value::Box(name, b) => Value::Box(name, b.clone()), Value::Placeholder => Value::Placeholder, } } } impl<'src> fmt::Display for Value<'src> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { Value::Nil => write!(f, "nil"), Value::Boolean(b) => write!(f, "{}", b), Value::Number(n) => write!(f, "{}", n), Value::Keyword(k) => write!(f, ":{}", k), Value::String(s) => write!(f, "\"{}\"", s), Value::Fn(fun) => write!(f, "fn {}", fun.name), Value::Tuple(t) | Value::Args(t) => write!( f, "({})", t.iter() .map(|x| x.to_string()) .collect::>() .join(", ") ), Value::List(l) => write!( f, "[{}]", l.iter() .map(|x| x.to_string()) .collect::>() .join(", ") ), Value::Dict(d) => write!( f, "#{{{}}}", d.iter() .map(|(k, v)| format!(":{k} {v}")) .collect::>() .join(", ") ), Value::Box(name, b) => todo!(), Value::Placeholder => write!(f, "_"), } } } impl<'src> Value<'src> { pub fn bool(&self) -> bool { match self { Value::Nil | Value::Boolean(false) => false, _ => true, } } }