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    /// Short type name for error messages.
186    pub fn type_name(&self) -> &'static str {
187        match self {
188            Self::Nil => "nil",
189            Self::Bool(_) => "bool",
190            Self::Int(_) => "int",
191            Self::Float(_) => "float",
192            Self::Str(_) => "string",
193            Self::Symbol(_) => "symbol",
194            Self::Keyword(_) => "keyword",
195            Self::List(_) => "list",
196            Self::Map(_) => "map",
197            Self::Closure(_) => "closure",
198            Self::NativeFn(_) => "native-fn",
199            Self::Promise(_) => "promise",
200            Self::Error(_) => "error",
201            Self::Sexp(..) => "sexp",
202            Self::Foreign(_) => "foreign",
203        }
204    }
205}
206
207// ── Debug / Display ─────────────────────────────────────────────────────
208
209impl fmt::Debug for Value {
210    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
211        match self {
212            Self::Nil => f.write_str("Nil"),
213            Self::Bool(b) => write!(f, "Bool({b})"),
214            Self::Int(n) => write!(f, "Int({n})"),
215            Self::Float(n) => write!(f, "Float({n})"),
216            Self::Str(s) => write!(f, "Str({s:?})"),
217            Self::Symbol(s) => write!(f, "Symbol({s})"),
218            Self::Keyword(s) => write!(f, "Keyword(:{s})"),
219            Self::List(xs) => f.debug_list().entries(xs.iter()).finish(),
220            Self::Map(m) => write!(f, "Map({} entries)", m.len()),
221            Self::Closure(_) => f.write_str("Closure(…)"),
222            Self::NativeFn(n) => write!(f, "NativeFn({})", n.name),
223            Self::Promise(_) => f.write_str("Promise(…)"),
224            Self::Error(e) => write!(f, "Error({}: {})", e.tag, e.message),
225            Self::Sexp(s, sp) => write!(f, "Sexp({s} @ {sp})"),
226            Self::Foreign(_) => f.write_str("Foreign(…)"),
227        }
228    }
229}
230
231impl fmt::Display for Value {
232    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
233        match self {
234            Self::Nil => f.write_str("()"),
235            Self::Bool(true) => f.write_str("#t"),
236            Self::Bool(false) => f.write_str("#f"),
237            Self::Int(n) => write!(f, "{n}"),
238            Self::Float(n) => write!(f, "{n}"),
239            Self::Str(s) => write!(f, "{s:?}"),
240            Self::Symbol(s) => f.write_str(s),
241            Self::Keyword(s) => write!(f, ":{s}"),
242            Self::List(xs) => {
243                f.write_str("(")?;
244                for (i, v) in xs.iter().enumerate() {
245                    if i > 0 {
246                        f.write_str(" ")?;
247                    }
248                    write!(f, "{v}")?;
249                }
250                f.write_str(")")
251            }
252            Self::Map(m) => {
253                // Render as `{k v k v ...}` — Clojure-style. Order is
254                // not guaranteed (HashMap), so consumers that need
255                // determinism should sort keys themselves.
256                f.write_str("{")?;
257                for (i, (k, v)) in m.iter().enumerate() {
258                    if i > 0 {
259                        f.write_str(", ")?;
260                    }
261                    write!(f, "{k} {v}")?;
262                }
263                f.write_str("}")
264            }
265            Self::Closure(c) => {
266                write!(f, "#<closure")?;
267                if !c.params.is_empty() {
268                    write!(f, " ({}", c.params.join(" "))?;
269                    if let Some(rest) = &c.rest {
270                        write!(f, " . {rest}")?;
271                    }
272                    write!(f, ")")?;
273                }
274                write!(f, ">")
275            }
276            Self::NativeFn(n) => write!(f, "#<native {}>", n.name),
277            Self::Promise(p) => {
278                let state = p.lock().unwrap();
279                match &*state {
280                    PromiseState::Pending(_) => f.write_str("#<promise pending>"),
281                    PromiseState::Forced(v) => write!(f, "#<promise {v}>"),
282                }
283            }
284            Self::Error(e) => {
285                write!(f, "#<error :{} {:?}", e.tag, e.message.as_ref())?;
286                if !e.data.is_empty() {
287                    f.write_str(" {")?;
288                    for (i, (k, v)) in e.data.iter().enumerate() {
289                        if i > 0 {
290                            f.write_str(" ")?;
291                        }
292                        write!(f, "{k} {v}")?;
293                    }
294                    f.write_str("}")?;
295                }
296                f.write_str(">")
297            }
298            Self::Sexp(s, _) => write!(f, "'{s}"),
299            Self::Foreign(_) => f.write_str("#<foreign>"),
300        }
301    }
302}
303
304// ── Rust <-> Value conversions (partial; filled in Phase 2.4) ──────────
305
306impl From<bool> for Value {
307    fn from(b: bool) -> Self {
308        Self::Bool(b)
309    }
310}
311
312impl From<i64> for Value {
313    fn from(n: i64) -> Self {
314        Self::Int(n)
315    }
316}
317
318impl From<f64> for Value {
319    fn from(n: f64) -> Self {
320        Self::Float(n)
321    }
322}
323
324impl From<String> for Value {
325    fn from(s: String) -> Self {
326        Self::Str(Arc::from(s))
327    }
328}
329
330impl From<&str> for Value {
331    fn from(s: &str) -> Self {
332        Self::Str(Arc::from(s))
333    }
334}
335
336#[cfg(test)]
337mod tests {
338    use super::*;
339
340    #[test]
341    fn truthiness() {
342        assert!(Value::Bool(true).is_truthy());
343        assert!(!Value::Bool(false).is_truthy());
344        assert!(!Value::Nil.is_truthy());
345        assert!(Value::Int(0).is_truthy(), "zero is truthy (Scheme-ish)");
346        assert!(Value::list(std::iter::empty::<Value>()).is_truthy());
347    }
348
349    #[test]
350    fn display_primitives() {
351        assert_eq!(Value::Int(42).to_string(), "42");
352        assert_eq!(Value::Bool(true).to_string(), "#t");
353        assert_eq!(Value::Bool(false).to_string(), "#f");
354        assert_eq!(Value::symbol("foo").to_string(), "foo");
355        assert_eq!(Value::keyword("k").to_string(), ":k");
356        assert_eq!(Value::Nil.to_string(), "()");
357    }
358
359    #[test]
360    fn display_list() {
361        let v = Value::list([Value::Int(1), Value::Int(2), Value::Int(3)]);
362        assert_eq!(v.to_string(), "(1 2 3)");
363    }
364
365    #[test]
366    fn type_names() {
367        assert_eq!(Value::Int(0).type_name(), "int");
368        assert_eq!(Value::Str(Arc::from("x")).type_name(), "string");
369        assert_eq!(Value::Nil.type_name(), "nil");
370    }
371}