Skip to main content

aver/
value.rs

1/// Core Aver runtime value type and associated utilities.
2///
3/// Lives in its own module so both the interpreter and the service
4/// implementations (`services::*`) can import it without circular
5/// dependencies.
6use std::collections::HashMap;
7use std::rc::Rc;
8use thiserror::Error;
9
10use crate::ast::FnBody;
11
12// ---------------------------------------------------------------------------
13// RuntimeError
14// ---------------------------------------------------------------------------
15
16#[derive(Debug, Error)]
17pub enum RuntimeError {
18    #[error("Runtime error: {0}")]
19    Error(String),
20    /// Internal signal: `?` operator encountered Err — caught by call_value to
21    /// do early return. Never surfaces to the user (type checker prevents
22    /// top-level use).
23    #[error("Error propagation")]
24    ErrProp(Box<Value>),
25    /// Internal signal: tail-call — caught by the trampoline in call_fn_ref.
26    /// Never surfaces to the user. Boxed to keep RuntimeError small.
27    #[error("Tail call")]
28    TailCall(Box<(String, Vec<Value>)>),
29    #[error("Replay mismatch at seq {seq}: expected '{expected}', got '{got}'")]
30    ReplayMismatch {
31        seq: u32,
32        expected: String,
33        got: String,
34    },
35    #[error(
36        "Replay args mismatch at seq {seq} for '{effect_type}': expected {expected}, got {got}"
37    )]
38    ReplayArgsMismatch {
39        seq: u32,
40        effect_type: String,
41        expected: String,
42        got: String,
43    },
44    #[error(
45        "Replay exhausted at position {position}: no recorded effect for call '{effect_type}'"
46    )]
47    ReplayExhausted {
48        effect_type: String,
49        position: usize,
50    },
51    #[error("Replay has {remaining} unconsumed effect(s)")]
52    ReplayUnconsumed { remaining: usize },
53    #[error("Replay serialization error: {0}")]
54    ReplaySerialization(String),
55}
56
57// ---------------------------------------------------------------------------
58// Value
59// ---------------------------------------------------------------------------
60
61#[derive(Debug, Clone)]
62pub enum Value {
63    Int(i64),
64    Float(f64),
65    Str(String),
66    Bool(bool),
67    Unit,
68    Ok(Box<Value>),
69    Err(Box<Value>),
70    Some(Box<Value>),
71    None,
72    List(Vec<Value>),
73    Tuple(Vec<Value>),
74    Map(HashMap<Value, Value>),
75    /// Shared list view (`items[start..]`) to avoid O(n^2) tail copying in
76    /// recursive list processing.
77    ListSlice {
78        items: Rc<Vec<Value>>,
79        start: usize,
80    },
81    Fn {
82        name: String,
83        params: Vec<(String, String)>,
84        effects: Vec<String>,
85        body: Rc<FnBody>,
86        /// Compile-time resolution metadata (slot layout for locals).
87        resolution: Option<crate::ast::FnResolution>,
88        /// True only for functions selected by `compute_memo_fns` in the
89        /// interpreter that defined them.
90        memo_eligible: bool,
91        /// Optional function-specific global scope (used by imported module
92        /// functions so they resolve names in their home module).
93        home_globals: Option<Rc<HashMap<String, Rc<Value>>>>,
94    },
95    Builtin(String),
96    /// User-defined sum type variant, e.g. `Shape.Circle(3.14)`
97    Variant {
98        type_name: String,
99        variant: String,
100        fields: Vec<Value>,
101    },
102    /// User-defined product type (record), e.g. `User(name = "Alice", age = 30)`
103    Record {
104        type_name: String,
105        fields: Vec<(String, Value)>,
106    },
107    /// Type namespace: `Shape` — provides `Shape.Circle`, `Shape.Rect`, etc.
108    Namespace {
109        name: String,
110        members: HashMap<String, Value>,
111    },
112}
113
114impl PartialEq for Value {
115    fn eq(&self, other: &Self) -> bool {
116        match (list_slice(self), list_slice(other)) {
117            (Some(xs), Some(ys)) => return xs == ys,
118            (Some(_), None) | (None, Some(_)) => return false,
119            (None, None) => {}
120        }
121
122        match (self, other) {
123            (Value::Int(a), Value::Int(b)) => a == b,
124            (Value::Float(a), Value::Float(b)) => {
125                if a.is_nan() || b.is_nan() {
126                    a.to_bits() == b.to_bits()
127                } else {
128                    a == b
129                }
130            }
131            (Value::Str(a), Value::Str(b)) => a == b,
132            (Value::Bool(a), Value::Bool(b)) => a == b,
133            (Value::Unit, Value::Unit) => true,
134            (Value::Ok(a), Value::Ok(b)) => a == b,
135            (Value::Err(a), Value::Err(b)) => a == b,
136            (Value::Some(a), Value::Some(b)) => a == b,
137            (Value::None, Value::None) => true,
138            (Value::Tuple(a), Value::Tuple(b)) => a == b,
139            (Value::Map(a), Value::Map(b)) => a == b,
140            (
141                Value::Fn {
142                    name: n1,
143                    params: p1,
144                    effects: e1,
145                    body: b1,
146                    ..
147                },
148                Value::Fn {
149                    name: n2,
150                    params: p2,
151                    effects: e2,
152                    body: b2,
153                    ..
154                },
155            ) => n1 == n2 && p1 == p2 && e1 == e2 && b1 == b2,
156            (Value::Builtin(a), Value::Builtin(b)) => a == b,
157            (
158                Value::Variant {
159                    type_name: t1,
160                    variant: v1,
161                    fields: f1,
162                },
163                Value::Variant {
164                    type_name: t2,
165                    variant: v2,
166                    fields: f2,
167                },
168            ) => t1 == t2 && v1 == v2 && f1 == f2,
169            (
170                Value::Record {
171                    type_name: t1,
172                    fields: f1,
173                },
174                Value::Record {
175                    type_name: t2,
176                    fields: f2,
177                },
178            ) => t1 == t2 && f1 == f2,
179            (
180                Value::Namespace {
181                    name: n1,
182                    members: m1,
183                },
184                Value::Namespace {
185                    name: n2,
186                    members: m2,
187                },
188            ) => n1 == n2 && m1 == m2,
189            _ => false,
190        }
191    }
192}
193
194impl Eq for Value {}
195
196impl std::hash::Hash for Value {
197    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
198        if let Some(items) = list_slice(self) {
199            8u8.hash(state);
200            items.len().hash(state);
201            for item in items {
202                item.hash(state);
203            }
204            return;
205        }
206
207        match self {
208            Value::Int(i) => {
209                0u8.hash(state);
210                i.hash(state);
211            }
212            Value::Float(f) => {
213                1u8.hash(state);
214                let bits = if *f == 0.0 {
215                    0.0f64.to_bits()
216                } else {
217                    f.to_bits()
218                };
219                bits.hash(state);
220            }
221            Value::Str(s) => {
222                2u8.hash(state);
223                s.hash(state);
224            }
225            Value::Bool(b) => {
226                3u8.hash(state);
227                b.hash(state);
228            }
229            Value::Unit => {
230                4u8.hash(state);
231            }
232            Value::Ok(v) => {
233                5u8.hash(state);
234                v.hash(state);
235            }
236            Value::Err(v) => {
237                6u8.hash(state);
238                v.hash(state);
239            }
240            Value::Some(v) => {
241                7u8.hash(state);
242                v.hash(state);
243            }
244            Value::None => {
245                9u8.hash(state);
246            }
247            Value::Map(map) => {
248                10u8.hash(state);
249                let mut entries = map.iter().collect::<Vec<_>>();
250                entries.sort_by(|(k1, _), (k2, _)| aver_repr(k1).cmp(&aver_repr(k2)));
251                for (k, v) in entries {
252                    k.hash(state);
253                    v.hash(state);
254                }
255            }
256            Value::Tuple(items) => {
257                16u8.hash(state);
258                items.hash(state);
259            }
260            Value::Fn {
261                name,
262                params,
263                effects,
264                body,
265                ..
266            } => {
267                11u8.hash(state);
268                name.hash(state);
269                params.hash(state);
270                effects.hash(state);
271                format!("{:?}", body).hash(state);
272            }
273            Value::Builtin(name) => {
274                12u8.hash(state);
275                name.hash(state);
276            }
277            Value::Variant {
278                type_name,
279                variant,
280                fields,
281            } => {
282                13u8.hash(state);
283                type_name.hash(state);
284                variant.hash(state);
285                fields.hash(state);
286            }
287            Value::Record { type_name, fields } => {
288                14u8.hash(state);
289                type_name.hash(state);
290                fields.hash(state);
291            }
292            Value::Namespace { name, members } => {
293                15u8.hash(state);
294                name.hash(state);
295                let mut keys = members.keys().collect::<Vec<_>>();
296                keys.sort();
297                for key in keys {
298                    key.hash(state);
299                    if let Some(value) = members.get(key) {
300                        value.hash(state);
301                    }
302                }
303            }
304            Value::List(_) | Value::ListSlice { .. } => unreachable!("list hashed above"),
305        }
306    }
307}
308
309// ---------------------------------------------------------------------------
310// Environment
311// ---------------------------------------------------------------------------
312
313#[derive(Debug, Clone)]
314pub enum EnvFrame {
315    Owned(HashMap<String, Rc<Value>>),
316    Shared(Rc<HashMap<String, Rc<Value>>>),
317    /// Slot-indexed frame for resolved function bodies — O(1) lookup.
318    Slots(Vec<Rc<Value>>),
319}
320
321/// Scope stack: innermost scope last.
322pub type Env = Vec<EnvFrame>;
323
324// ---------------------------------------------------------------------------
325// List helpers
326// ---------------------------------------------------------------------------
327
328pub fn list_slice(value: &Value) -> Option<&[Value]> {
329    match value {
330        Value::List(items) => Some(items.as_slice()),
331        Value::ListSlice { items, start } => Some(items.get(*start..).unwrap_or(&[])),
332        _ => None,
333    }
334}
335
336pub fn list_from_vec(items: Vec<Value>) -> Value {
337    Value::ListSlice {
338        items: Rc::new(items),
339        start: 0,
340    }
341}
342
343pub fn list_to_vec(value: &Value) -> Option<Vec<Value>> {
344    list_slice(value).map(|items| items.to_vec())
345}
346
347pub fn list_len(value: &Value) -> Option<usize> {
348    list_slice(value).map(|items| items.len())
349}
350
351pub fn list_head(value: &Value) -> Option<Value> {
352    list_slice(value).and_then(|items| items.first().cloned())
353}
354
355pub fn list_tail_view(value: &Value) -> Option<Value> {
356    match value {
357        Value::List(items) => {
358            if items.is_empty() {
359                None
360            } else {
361                Some(Value::ListSlice {
362                    items: Rc::new(items.clone()),
363                    start: 1,
364                })
365            }
366        }
367        Value::ListSlice { items, start } => {
368            if *start >= items.len() {
369                None
370            } else {
371                Some(Value::ListSlice {
372                    items: Rc::clone(items),
373                    start: start + 1,
374                })
375            }
376        }
377        _ => None,
378    }
379}
380
381// ---------------------------------------------------------------------------
382// Display helpers
383// ---------------------------------------------------------------------------
384
385/// Human-readable representation of a value (used by `str()` and `:env`).
386pub fn aver_repr(val: &Value) -> String {
387    match val {
388        Value::Int(i) => i.to_string(),
389        Value::Float(f) => f.to_string(),
390        Value::Str(s) => s.clone(),
391        Value::Bool(b) => if *b { "true" } else { "false" }.to_string(),
392        Value::Unit => "()".to_string(),
393        Value::Ok(v) => format!("Result.Ok({})", aver_repr_inner(v)),
394        Value::Err(v) => format!("Result.Err({})", aver_repr_inner(v)),
395        Value::Some(v) => format!("Option.Some({})", aver_repr_inner(v)),
396        Value::None => "Option.None".to_string(),
397        Value::List(_) | Value::ListSlice { .. } => {
398            let items = list_slice(val).expect("list variants must have a slice view");
399            let parts: Vec<String> = items.iter().map(aver_repr_inner).collect();
400            format!("[{}]", parts.join(", "))
401        }
402        Value::Tuple(items) => {
403            let parts: Vec<String> = items.iter().map(aver_repr_inner).collect();
404            format!("({})", parts.join(", "))
405        }
406        Value::Map(entries) => {
407            let mut pairs = entries
408                .iter()
409                .map(|(k, v)| (aver_repr_inner(k), aver_repr_inner(v)))
410                .collect::<Vec<_>>();
411            pairs.sort_by(|(k1, _), (k2, _)| k1.cmp(k2));
412            let parts = pairs
413                .into_iter()
414                .map(|(k, v)| format!("{}: {}", k, v))
415                .collect::<Vec<_>>();
416            format!("{{{}}}", parts.join(", "))
417        }
418        Value::Fn { name, .. } => format!("<fn {}>", name),
419        Value::Builtin(name) => format!("<builtin {}>", name),
420        Value::Variant {
421            variant, fields, ..
422        } => {
423            if fields.is_empty() {
424                variant.clone()
425            } else {
426                let parts: Vec<String> = fields.iter().map(aver_repr_inner).collect();
427                format!("{}({})", variant, parts.join(", "))
428            }
429        }
430        Value::Record { type_name, fields } => {
431            let parts: Vec<String> = fields
432                .iter()
433                .map(|(k, v)| format!("{}: {}", k, aver_repr_inner(v)))
434                .collect();
435            format!("{}({})", type_name, parts.join(", "))
436        }
437        Value::Namespace { name, .. } => format!("<type {}>", name),
438    }
439}
440
441/// Like `aver_repr` but strings get quoted — used inside constructors and lists.
442fn aver_repr_inner(val: &Value) -> String {
443    match val {
444        Value::Str(s) => format!("\"{}\"", s),
445        Value::Tuple(items) => {
446            let parts: Vec<String> = items.iter().map(aver_repr_inner).collect();
447            format!("({})", parts.join(", "))
448        }
449        Value::List(_) | Value::ListSlice { .. } => {
450            let items = list_slice(val).expect("list variants must have a slice view");
451            let parts: Vec<String> = items.iter().map(aver_repr_inner).collect();
452            format!("[{}]", parts.join(", "))
453        }
454        other => aver_repr(other),
455    }
456}
457
458/// Returns the display string for `print()` — `None` for `Unit` (silent).
459pub fn aver_display(val: &Value) -> Option<String> {
460    match val {
461        Value::Unit => None,
462        other => Some(aver_repr(other)),
463    }
464}
465
466// ---------------------------------------------------------------------------
467// Memo hashing — only for memo-safe (scalar + record/variant of scalar) values
468// ---------------------------------------------------------------------------
469
470/// Hash a slice of memo-safe argument values into a single u64.
471pub fn hash_memo_args(args: &[Value]) -> u64 {
472    use std::hash::Hasher;
473    let mut hasher = std::collections::hash_map::DefaultHasher::new();
474    for arg in args {
475        hash_value(arg, &mut hasher);
476    }
477    hasher.finish()
478}
479
480fn hash_value(val: &Value, hasher: &mut impl std::hash::Hasher) {
481    use std::hash::Hash;
482    match val {
483        Value::Int(i) => {
484            0u8.hash(hasher);
485            i.hash(hasher);
486        }
487        Value::Float(f) => {
488            1u8.hash(hasher);
489            f.to_bits().hash(hasher);
490        }
491        Value::Str(s) => {
492            2u8.hash(hasher);
493            s.hash(hasher);
494        }
495        Value::Bool(b) => {
496            3u8.hash(hasher);
497            b.hash(hasher);
498        }
499        Value::Unit => {
500            4u8.hash(hasher);
501        }
502        Value::Tuple(items) => {
503            7u8.hash(hasher);
504            items.len().hash(hasher);
505            for item in items {
506                hash_value(item, hasher);
507            }
508        }
509        Value::Record { type_name, fields } => {
510            5u8.hash(hasher);
511            type_name.hash(hasher);
512            for (k, v) in fields {
513                k.hash(hasher);
514                hash_value(v, hasher);
515            }
516        }
517        Value::Variant {
518            type_name,
519            variant,
520            fields,
521        } => {
522            6u8.hash(hasher);
523            type_name.hash(hasher);
524            variant.hash(hasher);
525            for v in fields {
526                hash_value(v, hasher);
527            }
528        }
529        // Should not reach here for non-memo-safe values; no-op to avoid panic.
530        _ => {
531            255u8.hash(hasher);
532        }
533    }
534}