use crate::{eval, prims}; use std::rc::Rc; #[derive(Clone /*, debug2::Debug*/)] crate enum Value { Num(f64), // TODO: implement debug2::Debug for `fn` type, and do it right // https://godbolt.org/z/vr9erGeKq Func(prims::NativeFunc), Lambda(eval::Lambda), Bool(bool), /// Result of things that shouldnt have values, like (define x 3) /// TODO: Figure this out Trap, } impl std::fmt::Debug for Value { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { Self::Num(arg0) => f.debug_tuple("Num").field(arg0).finish(), // We cant just pass the field because of livetime bs, see https://godbolt.org/z/vr9erGeKq Self::Func(_) => f.debug_struct("Func").finish_non_exhaustive(), Self::Lambda(arg0) => f.debug_tuple("Lambda").field(arg0).finish(), Self::Bool(arg0) => f.debug_tuple("Bool").field(arg0).finish(), Self::Trap => write!(f, "Trap"), } } } impl PartialEq for Value { fn eq(&self, other: &Self) -> bool { use Value::*; match (self, other) { (Num(l), Num(r)) => l == r, (Func(l), Func(r)) => *l as usize == *r as usize, (Bool(l), Bool(r)) => l == r, (Lambda(l), Lambda(r)) => { Rc::ptr_eq(&l.func, &r.func) && Rc::ptr_eq(&l.captures, &r.captures) } (Num(_), _) => false, (Func(_), _) => false, (Bool(_), _) => false, (Lambda(_), _) => false, (Trap, _) => panic!("Trap value"), } } } impl std::fmt::Display for Value { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { Self::Num(n) => std::fmt::Debug::fmt(n, f), // TODO: Change to displays Self::Func(_) => f.write_str("#"), Self::Lambda(_) => f.write_str("#"), Self::Bool(b) => f.write_str(if *b { "#t" } else { "#f" }), Self::Trap => Ok(()), } } } impl Value { crate fn as_num(&self) -> Result { if let Self::Num(n) = self { Ok(*n) } else { Err(eval::RTError("Expected a number".to_owned())) } } crate fn as_func(self) -> Result { match self { Self::Func(f) => Ok(eval::Callable::Func(f)), Self::Lambda(l) => Ok(eval::Callable::Lambda(l)), _ => Err(eval::RTError(format!("Expected a function, got {}", self))), } } crate fn as_bool(&self) -> Result { if let Self::Bool(b) = self { Ok(*b) } else { Err(eval::RTError("Expected a bool".to_owned())) } } }