use std::collections::BTreeMap;
use crate::env::Env;
use crate::heap::Address;
use crate::syntax::{Expr, VarName};
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Value {
Closure {
param: VarName,
body: Expr,
env: Env,
},
Ref(Address),
Object {
properties: BTreeMap<VarName, Value>,
prototype: Option<Address>,
},
}
impl Value {
#[must_use]
pub fn closure(param: VarName, body: Expr, env: Env) -> Self {
Self::Closure { param, body, env }
}
#[must_use]
pub fn reference(address: Address) -> Self {
Self::Ref(address)
}
#[must_use]
pub fn object(properties: BTreeMap<VarName, Value>, prototype: Option<Address>) -> Self {
Self::Object {
properties,
prototype,
}
}
}
impl std::fmt::Display for Value {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Closure { param, body, .. } => write!(f, "\\{param}. {body}"),
Self::Ref(address) => write!(f, "ref({address})"),
Self::Object {
properties,
prototype,
} => write_object(f, properties, *prototype),
}
}
}
fn write_object(
f: &mut std::fmt::Formatter<'_>,
properties: &BTreeMap<VarName, Value>,
prototype: Option<Address>,
) -> std::fmt::Result {
let entries = properties
.iter()
.map(|(k, v)| format!("{k} = {v}"))
.collect::<Vec<_>>()
.join(", ");
let prefix = prototype.map_or(String::new(), |a| format!("proto={a} "));
write!(f, "{{{prefix}{entries}}}")
}