use crate::util::scoped_map::ScopedMap; use internment::ArcIntern; use std::fmt; /// Values in the interpreter. /// /// Yes, this is yet another definition of a structure called `Value`, which /// are almost entirely identical. However, it's nice to have them separated /// by type so that we don't mix them up. #[derive(Clone)] pub enum Value { Void, I8(i8), I16(i16), I32(i32), I64(i64), U8(u8), U16(u16), U32(u32), U64(u64), Closure( Option>, ScopedMap, Value>, Vec>, IR, ), } impl Value { /// Given a Value associated with some expression type, just strip out /// the expressions and replace them with unit. /// /// Doing this transformation will likely make this value useless for /// computation, but is very useful in allowing equivalence checks. pub fn strip(&self) -> Value<()> { match self { Value::Void => Value::Void, Value::U8(x) => Value::U8(*x), Value::U16(x) => Value::U16(*x), Value::U32(x) => Value::U32(*x), Value::U64(x) => Value::U64(*x), Value::I8(x) => Value::I8(*x), Value::I16(x) => Value::I16(*x), Value::I32(x) => Value::I32(*x), Value::I64(x) => Value::I64(*x), Value::Closure(name, env, args, _) => { let new_env = env.clone().map_values(|x| x.strip()); Value::Closure(name.clone(), new_env, args.clone(), ()) } } } } fn format_value(value: &Value, f: &mut fmt::Formatter<'_>) -> fmt::Result { match value { Value::Void => write!(f, ""), Value::I8(x) => write!(f, "{}i8", x), Value::I16(x) => write!(f, "{}i16", x), Value::I32(x) => write!(f, "{}i32", x), Value::I64(x) => write!(f, "{}i64", x), Value::U8(x) => write!(f, "{}u8", x), Value::U16(x) => write!(f, "{}u16", x), Value::U32(x) => write!(f, "{}u32", x), Value::U64(x) => write!(f, "{}u64", x), Value::Closure(Some(name), _, _, _) => write!(f, "", name), Value::Closure(None, _, _, _) => write!(f, ""), } } impl fmt::Debug for Value { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { format_value(self, f) } } impl fmt::Display for Value { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { format_value(self, f) } } impl PartialEq> for Value { fn eq(&self, other: &Value) -> bool { match self { Value::Void => matches!(other, Value::Void), Value::I8(x) => match other { Value::I8(y) => x == y, _ => false, }, Value::I16(x) => match other { Value::I16(y) => x == y, _ => false, }, Value::I32(x) => match other { Value::I32(y) => x == y, _ => false, }, Value::I64(x) => match other { Value::I64(y) => x == y, _ => false, }, Value::U8(x) => match other { Value::U8(y) => x == y, _ => false, }, Value::U16(x) => match other { Value::U16(y) => x == y, _ => false, }, Value::U32(x) => match other { Value::U32(y) => x == y, _ => false, }, Value::U64(x) => match other { Value::U64(y) => x == y, _ => false, }, Value::Closure(_, _, _, _) => false, } } } impl From for Value { fn from(value: i8) -> Self { Value::I8(value) } } impl From for Value { fn from(value: i16) -> Self { Value::I16(value) } } impl From for Value { fn from(value: i32) -> Self { Value::I32(value) } } impl From for Value { fn from(value: i64) -> Self { Value::I64(value) } } impl From for Value { fn from(value: u8) -> Self { Value::U8(value) } } impl From for Value { fn from(value: u16) -> Self { Value::U16(value) } } impl From for Value { fn from(value: u32) -> Self { Value::U32(value) } } impl From for Value { fn from(value: u64) -> Self { Value::U64(value) } }