handball/src/value.rs

88 lines
2.8 KiB
Rust

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("#<procedure>"),
Self::Lambda(_) => f.write_str("#<procedure>"),
Self::Bool(b) => f.write_str(if *b { "#t" } else { "#f" }),
Self::Trap => Ok(()),
}
}
}
impl Value {
crate fn as_num(&self) -> Result<f64, eval::RTError> {
if let Self::Num(n) = self {
Ok(*n)
} else {
Err(eval::RTError("Expected a number".to_owned()))
}
}
crate fn as_func(self) -> Result<eval::Callable, eval::RTError> {
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<bool, eval::RTError> {
if let Self::Bool(b) = self {
Ok(*b)
} else {
Err(eval::RTError("Expected a bool".to_owned()))
}
}
}