Files
ngr/src/eval/value.rs

170 lines
4.5 KiB
Rust

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<IR> {
Void,
I8(i8),
I16(i16),
I32(i32),
I64(i64),
U8(u8),
U16(u16),
U32(u32),
U64(u64),
Closure(
Option<ArcIntern<String>>,
ScopedMap<ArcIntern<String>, Value<IR>>,
Vec<ArcIntern<String>>,
IR,
),
}
impl<IR: Clone> Value<IR> {
/// 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<IR>(value: &Value<IR>, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match value {
Value::Void => write!(f, "<void>"),
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, "<function {}>", name),
Value::Closure(None, _, _, _) => write!(f, "<function>"),
}
}
impl<IR> fmt::Debug for Value<IR> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
format_value(self, f)
}
}
impl<IR> fmt::Display for Value<IR> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
format_value(self, f)
}
}
impl<IR1, IR2> PartialEq<Value<IR2>> for Value<IR1> {
fn eq(&self, other: &Value<IR2>) -> 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<IR> From<i8> for Value<IR> {
fn from(value: i8) -> Self {
Value::I8(value)
}
}
impl<IR> From<i16> for Value<IR> {
fn from(value: i16) -> Self {
Value::I16(value)
}
}
impl<IR> From<i32> for Value<IR> {
fn from(value: i32) -> Self {
Value::I32(value)
}
}
impl<IR> From<i64> for Value<IR> {
fn from(value: i64) -> Self {
Value::I64(value)
}
}
impl<IR> From<u8> for Value<IR> {
fn from(value: u8) -> Self {
Value::U8(value)
}
}
impl<IR> From<u16> for Value<IR> {
fn from(value: u16) -> Self {
Value::U16(value)
}
}
impl<IR> From<u32> for Value<IR> {
fn from(value: u32) -> Self {
Value::U32(value)
}
}
impl<IR> From<u64> for Value<IR> {
fn from(value: u64) -> Self {
Value::U64(value)
}
}