Skip to main content

tatara_lisp_eval/
value.rs

1//! Runtime values.
2//!
3//! `Value` is distinct from `Sexp`: evaluation produces `Value`, while the
4//! source AST is `Sexp` / `Spanned`. Values include runtime-only variants
5//! (closures, native functions, opaque host-owned Foreign values) that
6//! have no surface syntax.
7
8use std::any::Any;
9use std::collections::HashMap;
10use std::fmt;
11use std::sync::Arc;
12
13use tatara_lisp::{Sexp, Span, Spanned};
14
15use crate::env::Env;
16use crate::ffi::Arity;
17
18/// An evaluated runtime value.
19#[derive(Clone)]
20pub enum Value {
21    Nil,
22    Bool(bool),
23    Int(i64),
24    Float(f64),
25    Str(Arc<str>),
26    Symbol(Arc<str>),
27    Keyword(Arc<str>),
28    List(Arc<Vec<Value>>),
29    /// Persistent hash map keyed by a hashable subset of `Value`
30    /// (`Bool`, `Int`, `Float`, `Str`, `Symbol`, `Keyword`, `Nil`).
31    /// Inserting / removing yields a new Map (copy-on-write via `Arc`).
32    Map(Arc<HashMap<MapKey, Value>>),
33    Closure(Arc<Closure>),
34    NativeFn(Arc<NativeFn>),
35    /// A delayed (lazy) computation. First force triggers evaluation
36    /// of the underlying thunk; subsequent forces return the cached
37    /// result. Backed by `Mutex` so a Promise can be shared across
38    /// references safely (single-threaded runtime, but the lock is
39    /// trivial overhead and gives us zero-effort safety).
40    Promise(Arc<std::sync::Mutex<PromiseState>>),
41    /// A first-class structured error — Clojure ex-info shape:
42    /// a tag (keyword/string), a message string, and a data plist.
43    /// Constructed by `(error tag msg data)` / `(ex-info msg data)`.
44    /// Raised by `(throw err)`. Caught by `(try ... (catch (e) ...))`.
45    Error(Arc<ErrorObj>),
46    /// Escape hatch: unevaluated source form carried as a value, e.g. after
47    /// `(quote x)`. Preserves span info.
48    Sexp(Sexp, Span),
49    /// Opaque host-owned value. The embedder supplies these via FFI; native
50    /// functions read them back via downcast. Used to expose typed Rust
51    /// handles (job refs, client handles) to Lisp code.
52    Foreign(Arc<dyn Any + Send + Sync>),
53}
54
55/// Structured error payload — tag + message + attached data. The data
56/// is a list of (key, value) pairs preserving insertion order — a
57/// plist-style alist. Keys are typically `Value::Keyword`s but any
58/// equality-comparable Value works.
59#[derive(Debug, Clone)]
60pub struct ErrorObj {
61    pub tag: Arc<str>,
62    pub message: Arc<str>,
63    pub data: Vec<(Value, Value)>,
64}
65
66/// Hashable subset of `Value` — every variant that has well-defined
67/// equality and hashing semantics. Used as the key type for `Value::Map`.
68///
69/// `Float` keys are stored as raw bit patterns so two `NaN`s hash to the
70/// same slot and equality is bit-exact. This trades IEEE-NaN-comparison
71/// semantics for usability — keys round-trip correctly.
72#[derive(Debug, Clone, PartialEq, Eq, Hash)]
73pub enum MapKey {
74    Nil,
75    Bool(bool),
76    Int(i64),
77    Float(u64),
78    Str(Arc<str>),
79    Symbol(Arc<str>),
80    Keyword(Arc<str>),
81}
82
83impl MapKey {
84    /// Try to convert a Value into a hashable map key. Returns None
85    /// for non-hashable variants (List, Map, Closure, NativeFn,
86    /// Error, Sexp, Foreign).
87    pub fn from_value(v: &Value) -> Option<Self> {
88        Some(match v {
89            Value::Nil => Self::Nil,
90            Value::Bool(b) => Self::Bool(*b),
91            Value::Int(n) => Self::Int(*n),
92            Value::Float(n) => Self::Float(n.to_bits()),
93            Value::Str(s) => Self::Str(s.clone()),
94            Value::Symbol(s) => Self::Symbol(s.clone()),
95            Value::Keyword(s) => Self::Keyword(s.clone()),
96            _ => return None,
97        })
98    }
99
100    /// Convert back to a Value. The reverse direction is total — every
101    /// MapKey variant has a corresponding Value variant.
102    pub fn to_value(&self) -> Value {
103        match self {
104            Self::Nil => Value::Nil,
105            Self::Bool(b) => Value::Bool(*b),
106            Self::Int(n) => Value::Int(*n),
107            Self::Float(b) => Value::Float(f64::from_bits(*b)),
108            Self::Str(s) => Value::Str(s.clone()),
109            Self::Symbol(s) => Value::Symbol(s.clone()),
110            Self::Keyword(s) => Value::Keyword(s.clone()),
111        }
112    }
113}
114
115impl fmt::Display for MapKey {
116    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
117        write!(f, "{}", self.to_value())
118    }
119}
120
121/// State of a `Value::Promise`. Created Pending wrapping a thunk
122/// (always a unary closure of zero args); on first force, the thunk
123/// runs and the result replaces the state with `Forced(value)`. All
124/// subsequent forces return the cached value without re-evaluation.
125pub enum PromiseState {
126    Pending(Arc<Closure>),
127    Forced(Value),
128}
129
130impl fmt::Debug for PromiseState {
131    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
132        match self {
133            Self::Pending(_) => f.write_str("Pending(…)"),
134            Self::Forced(v) => write!(f, "Forced({v:?})"),
135        }
136    }
137}
138
139/// A user-defined closure produced by `(lambda …)` or `(define (f …) …)`.
140pub struct Closure {
141    pub params: Vec<Arc<str>>,
142    /// Optional rest parameter — `(lambda (a b . rest) …)` or
143    /// `(lambda (a b &rest rs) …)`.
144    pub rest: Option<Arc<str>>,
145    /// Body forms, preserved as `Spanned` so error locations inside the
146    /// body remain accurate after construction.
147    pub body: Vec<Spanned>,
148    pub captured_env: Env,
149    pub source: Span,
150}
151
152/// A host-registered Rust function exposed to Lisp code. The actual
153/// callable lives in the `Interpreter<H>`'s `FnRegistry`, keyed by
154/// `name` — this struct carries just the lookup key and arity so
155/// `Value` remains non-generic over `H`.
156#[derive(Clone, Debug)]
157pub struct NativeFn {
158    pub name: Arc<str>,
159    pub arity: Arity,
160}
161
162// ── Convenience constructors ────────────────────────────────────────────
163
164impl Value {
165    pub fn symbol(s: impl Into<Arc<str>>) -> Self {
166        Self::Symbol(s.into())
167    }
168
169    pub fn keyword(s: impl Into<Arc<str>>) -> Self {
170        Self::Keyword(s.into())
171    }
172
173    pub fn string(s: impl Into<Arc<str>>) -> Self {
174        Self::Str(s.into())
175    }
176
177    pub fn list<I: IntoIterator<Item = Value>>(xs: I) -> Self {
178        Self::List(Arc::new(xs.into_iter().collect()))
179    }
180
181    pub fn is_truthy(&self) -> bool {
182        !matches!(self, Self::Nil | Self::Bool(false))
183    }
184
185    /// Is this `Value` the **only** reference to its heap payload?
186    ///
187    /// The aliasing coordinate. `true` means no other `Value` anywhere can
188    /// observe the payload, so mutating it in place is unobservable and a
189    /// copy-on-write copy would be pure waste. `false` means somebody else
190    /// holds it and the copy is mandatory.
191    ///
192    /// Two things it is not:
193    ///
194    /// - **Not a static promise.** It is a refcount reading at one instant,
195    ///   which is why it is sound to act on: a primitive that reads `true`
196    ///   holds the value by *value*, so nothing can acquire a second
197    ///   reference behind its back.
198    /// - **Not observable from the language.** No Lisp-visible behaviour
199    ///   depends on it — the same call returns the same value either way. It
200    ///   only decides whether an allocation happens.
201    ///
202    /// Variants with no heap payload (`Nil`, `Bool`, `Int`, `Float`) are
203    /// trivially unique: there is nothing to share. `Sexp` answers `false`
204    /// because it carries its tree by value and this query cannot see the
205    /// sharing *inside* that tree — and a wrong `true` is the one answer that
206    /// could license an update somebody else observes, so an unmeasured
207    /// payload rounds down, never up.
208    #[must_use]
209    pub fn is_unique(&self) -> bool {
210        fn solo<T: ?Sized>(a: &Arc<T>) -> bool {
211            Arc::strong_count(a) == 1 && Arc::weak_count(a) == 0
212        }
213        match self {
214            Self::Nil | Self::Bool(_) | Self::Int(_) | Self::Float(_) => true,
215            Self::Str(s) | Self::Symbol(s) | Self::Keyword(s) => solo(s),
216            Self::List(xs) => solo(xs),
217            Self::Map(m) => solo(m),
218            Self::Closure(c) => solo(c),
219            Self::NativeFn(f) => solo(f),
220            Self::Promise(p) => solo(p),
221            Self::Error(e) => solo(e),
222            Self::Sexp(..) => false,
223            Self::Foreign(f) => solo(f),
224        }
225    }
226
227    /// Short type name for error messages.
228    pub fn type_name(&self) -> &'static str {
229        match self {
230            Self::Nil => "nil",
231            Self::Bool(_) => "bool",
232            Self::Int(_) => "int",
233            Self::Float(_) => "float",
234            Self::Str(_) => "string",
235            Self::Symbol(_) => "symbol",
236            Self::Keyword(_) => "keyword",
237            Self::List(_) => "list",
238            Self::Map(_) => "map",
239            Self::Closure(_) => "closure",
240            Self::NativeFn(_) => "native-fn",
241            Self::Promise(_) => "promise",
242            Self::Error(_) => "error",
243            Self::Sexp(..) => "sexp",
244            Self::Foreign(_) => "foreign",
245        }
246    }
247}
248
249// ── Debug / Display ─────────────────────────────────────────────────────
250
251impl fmt::Debug for Value {
252    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
253        match self {
254            Self::Nil => f.write_str("Nil"),
255            Self::Bool(b) => write!(f, "Bool({b})"),
256            Self::Int(n) => write!(f, "Int({n})"),
257            Self::Float(n) => write!(f, "Float({n})"),
258            Self::Str(s) => write!(f, "Str({s:?})"),
259            Self::Symbol(s) => write!(f, "Symbol({s})"),
260            Self::Keyword(s) => write!(f, "Keyword(:{s})"),
261            Self::List(xs) => f.debug_list().entries(xs.iter()).finish(),
262            Self::Map(m) => write!(f, "Map({} entries)", m.len()),
263            Self::Closure(_) => f.write_str("Closure(…)"),
264            Self::NativeFn(n) => write!(f, "NativeFn({})", n.name),
265            Self::Promise(_) => f.write_str("Promise(…)"),
266            Self::Error(e) => write!(f, "Error({}: {})", e.tag, e.message),
267            Self::Sexp(s, sp) => write!(f, "Sexp({s} @ {sp})"),
268            Self::Foreign(_) => f.write_str("Foreign(…)"),
269        }
270    }
271}
272
273impl fmt::Display for Value {
274    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
275        match self {
276            Self::Nil => f.write_str("()"),
277            Self::Bool(true) => f.write_str("#t"),
278            Self::Bool(false) => f.write_str("#f"),
279            Self::Int(n) => write!(f, "{n}"),
280            Self::Float(n) => write!(f, "{n}"),
281            Self::Str(s) => write!(f, "{s:?}"),
282            Self::Symbol(s) => f.write_str(s),
283            Self::Keyword(s) => write!(f, ":{s}"),
284            Self::List(xs) => {
285                f.write_str("(")?;
286                for (i, v) in xs.iter().enumerate() {
287                    if i > 0 {
288                        f.write_str(" ")?;
289                    }
290                    write!(f, "{v}")?;
291                }
292                f.write_str(")")
293            }
294            Self::Map(m) => {
295                // Render as `{k v k v ...}` — Clojure-style. Order is
296                // not guaranteed (HashMap), so consumers that need
297                // determinism should sort keys themselves.
298                f.write_str("{")?;
299                for (i, (k, v)) in m.iter().enumerate() {
300                    if i > 0 {
301                        f.write_str(", ")?;
302                    }
303                    write!(f, "{k} {v}")?;
304                }
305                f.write_str("}")
306            }
307            Self::Closure(c) => {
308                write!(f, "#<closure")?;
309                if !c.params.is_empty() {
310                    write!(f, " ({}", c.params.join(" "))?;
311                    if let Some(rest) = &c.rest {
312                        write!(f, " . {rest}")?;
313                    }
314                    write!(f, ")")?;
315                }
316                write!(f, ">")
317            }
318            Self::NativeFn(n) => write!(f, "#<native {}>", n.name),
319            Self::Promise(p) => {
320                let state = p.lock().unwrap();
321                match &*state {
322                    PromiseState::Pending(_) => f.write_str("#<promise pending>"),
323                    PromiseState::Forced(v) => write!(f, "#<promise {v}>"),
324                }
325            }
326            Self::Error(e) => {
327                write!(f, "#<error :{} {:?}", e.tag, e.message.as_ref())?;
328                if !e.data.is_empty() {
329                    f.write_str(" {")?;
330                    for (i, (k, v)) in e.data.iter().enumerate() {
331                        if i > 0 {
332                            f.write_str(" ")?;
333                        }
334                        write!(f, "{k} {v}")?;
335                    }
336                    f.write_str("}")?;
337                }
338                f.write_str(">")
339            }
340            Self::Sexp(s, _) => write!(f, "'{s}"),
341            Self::Foreign(_) => f.write_str("#<foreign>"),
342        }
343    }
344}
345
346// ── Rust <-> Value conversions (partial; filled in Phase 2.4) ──────────
347
348impl From<bool> for Value {
349    fn from(b: bool) -> Self {
350        Self::Bool(b)
351    }
352}
353
354impl From<i64> for Value {
355    fn from(n: i64) -> Self {
356        Self::Int(n)
357    }
358}
359
360impl From<f64> for Value {
361    fn from(n: f64) -> Self {
362        Self::Float(n)
363    }
364}
365
366impl From<String> for Value {
367    fn from(s: String) -> Self {
368        Self::Str(Arc::from(s))
369    }
370}
371
372impl From<&str> for Value {
373    fn from(s: &str) -> Self {
374        Self::Str(Arc::from(s))
375    }
376}
377
378#[cfg(test)]
379mod tests {
380    use super::*;
381
382    #[test]
383    fn truthiness() {
384        assert!(Value::Bool(true).is_truthy());
385        assert!(!Value::Bool(false).is_truthy());
386        assert!(!Value::Nil.is_truthy());
387        assert!(Value::Int(0).is_truthy(), "zero is truthy (Scheme-ish)");
388        assert!(Value::list(std::iter::empty::<Value>()).is_truthy());
389    }
390
391    #[test]
392    fn display_primitives() {
393        assert_eq!(Value::Int(42).to_string(), "42");
394        assert_eq!(Value::Bool(true).to_string(), "#t");
395        assert_eq!(Value::Bool(false).to_string(), "#f");
396        assert_eq!(Value::symbol("foo").to_string(), "foo");
397        assert_eq!(Value::keyword("k").to_string(), ":k");
398        assert_eq!(Value::Nil.to_string(), "()");
399    }
400
401    #[test]
402    fn display_list() {
403        let v = Value::list([Value::Int(1), Value::Int(2), Value::Int(3)]);
404        assert_eq!(v.to_string(), "(1 2 3)");
405    }
406
407    #[test]
408    fn type_names() {
409        assert_eq!(Value::Int(0).type_name(), "int");
410        assert_eq!(Value::Str(Arc::from("x")).type_name(), "string");
411        assert_eq!(Value::Nil.type_name(), "nil");
412    }
413}