use crate::{Environment, is_number_eq};
#[derive(Clone)]
pub enum Value {
Unit,
Module(String, Environment),
Identity(String),
Atom(String),
String(String),
Number(f64),
List(Vec<Value>),
Lambda(Vec<String>, Box<Value>, Environment),
Builtin(&'static str),
Plugin(String, String),
Object(String, Environment),
RawObject(String, *mut u8),
Apply(Vec<Value>, Box<Value>),
}
impl Value {
pub fn into_string(&self, is_list: bool) -> String {
match self {
Value::Unit => String::from("()"),
Value::Module(name, binds) => format!("Module[{}, {:?}]", name, binds.keys()),
Value::Identity(id) => format!("{}", id),
Value::Atom(a) => format!("#{}", a),
Value::String(s) => {
if is_list {
s.clone()
} else {
format!("\"{}\"", s)
}
}
Value::Number(n) => format!("{}", n),
Value::List(elements) => format!(
"{{{}}}",
elements
.iter()
.map(|element| format!("{}", element.into_string(true)))
.collect::<Vec<String>>()
.join(", ")
),
Value::Lambda(params, _, _) => {
format!("λ({}) => <lambda>", params.join(", "),)
}
Value::Builtin(name) => format!("<<{}>>", name),
Value::Plugin(lib, name) => format!("<${}:{}>", lib, name),
Value::Object(type_name, env) => {
format!(
"#({}){{{}}}",
type_name,
env.keys().cloned().collect::<Vec<String>>().join(", ")
)
}
Value::RawObject(type_name, _) => format!("#({})<<Raw>>", type_name),
Value::Apply(arguments, func) => format!(
"({})[{}]",
func.into_string(false),
arguments
.iter()
.map(|val| format!("{}", val.into_string(false)))
.collect::<Vec<String>>()
.join(", ")
),
}
}
}
impl std::cmp::PartialEq for Value {
fn eq(&self, other: &Self) -> bool {
match (self, other) {
(Value::Unit, Value::Unit) => true,
(Value::Identity(id1), Value::Identity(id2)) => id1 == id2,
(Value::Atom(a1), Value::Atom(a2)) => a1 == a2,
(Value::String(s1), Value::String(s2)) => s1 == s2,
(Value::Number(n1), Value::Number(n2)) => is_number_eq(*n1, *n2),
(Value::List(v1), Value::List(v2)) => v1.len() == v2.len() && v1.iter().zip(v2.iter()).all(|(e1, e2)| e1 == e2),
(Value::Builtin(n1), Value::Builtin(n2)) => n1 == n2,
_ => false,
}
}
}
impl std::fmt::Debug for Value {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Value::List(elements) => write!(
f,
"{{{}}}",
elements
.iter()
.map(|element| format!("{}", element.into_string(false)))
.collect::<Vec<String>>()
.join(", ")
),
e => write!(f, "{}", e.into_string(false)),
}
}
}
impl std::fmt::Display for Value {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Value::String(s) => write!(f, "{}", s),
e => write!(f, "{:?}", e),
}
}
}