Skip to main content

lambda_throw_cat/
value.rs

1//! Runtime values.
2//!
3//! Spike 3 adds an [`Value::Object`] variant carrying a string-keyed map of
4//! property values and an optional prototype [`Address`].  Objects live on
5//! the heap; user-facing variables hold [`Value::Ref`] pointing to a cell
6//! whose contents is the [`Value::Object`].
7
8use std::collections::BTreeMap;
9
10use crate::env::Env;
11use crate::heap::Address;
12use crate::syntax::{Expr, VarName};
13
14/// A runtime value.
15#[derive(Debug, Clone, PartialEq, Eq)]
16pub enum Value {
17    /// A function closed over its lexical environment.
18    Closure {
19        /// The parameter the function binds when applied.
20        param: VarName,
21        /// The function body.
22        body: Expr,
23        /// The captured environment.
24        env: Env,
25    },
26    /// A reference to a cell on the heap.
27    Ref(Address),
28    /// An object: a string-keyed property map plus an optional prototype.
29    Object {
30        /// Own properties of the object, sorted by name for determinism.
31        properties: BTreeMap<VarName, Value>,
32        /// Optional prototype cell on the heap.
33        prototype: Option<Address>,
34    },
35}
36
37impl Value {
38    /// Build a closure value.
39    #[must_use]
40    pub fn closure(param: VarName, body: Expr, env: Env) -> Self {
41        Self::Closure { param, body, env }
42    }
43
44    /// Build a reference value.
45    #[must_use]
46    pub fn reference(address: Address) -> Self {
47        Self::Ref(address)
48    }
49
50    /// Build an object value.
51    #[must_use]
52    pub fn object(properties: BTreeMap<VarName, Value>, prototype: Option<Address>) -> Self {
53        Self::Object {
54            properties,
55            prototype,
56        }
57    }
58}
59
60impl std::fmt::Display for Value {
61    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
62        match self {
63            Self::Closure { param, body, .. } => write!(f, "\\{param}. {body}"),
64            Self::Ref(address) => write!(f, "ref({address})"),
65            Self::Object {
66                properties,
67                prototype,
68            } => write_object(f, properties, *prototype),
69        }
70    }
71}
72
73fn write_object(
74    f: &mut std::fmt::Formatter<'_>,
75    properties: &BTreeMap<VarName, Value>,
76    prototype: Option<Address>,
77) -> std::fmt::Result {
78    let entries = properties
79        .iter()
80        .map(|(k, v)| format!("{k} = {v}"))
81        .collect::<Vec<_>>()
82        .join(", ");
83    let prefix = prototype.map_or(String::new(), |a| format!("proto={a} "));
84    write!(f, "{{{prefix}{entries}}}")
85}