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 aver_rt::AverList;
7use std::collections::HashMap;
8use std::rc::Rc;
9use thiserror::Error;
10
11use crate::ast::FnBody;
12
13mod memo;
14
15pub use memo::hash_memo_args;
16
17// ---------------------------------------------------------------------------
18// RuntimeError
19// ---------------------------------------------------------------------------
20
21#[derive(Debug, Error)]
22pub enum RuntimeError {
23    #[error("Runtime error: {0}")]
24    Error(String),
25    /// Internal signal: `?` operator encountered Err — caught by call_value to
26    /// do early return. Never surfaces to the user (type checker prevents
27    /// top-level use).
28    #[error("Error propagation")]
29    ErrProp(Box<Value>),
30    /// Internal signal: tail-call — caught by the trampoline in call_fn_ref.
31    /// Never surfaces to the user. Boxed to keep RuntimeError small.
32    #[error("Tail call")]
33    TailCall(Box<(String, Vec<Value>)>),
34    #[error("Replay mismatch at seq {seq}: expected '{expected}', got '{got}'")]
35    ReplayMismatch {
36        seq: u32,
37        expected: String,
38        got: String,
39    },
40    #[error(
41        "Replay args mismatch at seq {seq} for '{effect_type}': expected {expected}, got {got}"
42    )]
43    ReplayArgsMismatch {
44        seq: u32,
45        effect_type: String,
46        expected: String,
47        got: String,
48    },
49    #[error("Replay exhausted at position {position}: no recorded effect for call '{effect_type}'")]
50    ReplayExhausted {
51        effect_type: String,
52        position: usize,
53    },
54    #[error("Replay has {remaining} unconsumed effect(s)")]
55    ReplayUnconsumed { remaining: usize },
56    #[error("Replay serialization error: {0}")]
57    ReplaySerialization(String),
58}
59
60// ---------------------------------------------------------------------------
61// Value
62// ---------------------------------------------------------------------------
63
64#[derive(Debug, Clone)]
65pub enum Value {
66    Int(i64),
67    Float(f64),
68    Str(String),
69    Bool(bool),
70    Unit,
71    Ok(Box<Value>),
72    Err(Box<Value>),
73    Some(Box<Value>),
74    None,
75    List(AverList<Value>),
76    Tuple(Vec<Value>),
77    Map(HashMap<Value, Value>),
78    Fn {
79        name: String,
80        params: Vec<(String, String)>,
81        return_type: String,
82        effects: Vec<String>,
83        body: Rc<FnBody>,
84        /// Compile-time resolution metadata (slot layout for locals).
85        resolution: Option<crate::ast::FnResolution>,
86        /// True only for functions selected by `compute_memo_fns` in the
87        /// interpreter that defined them.
88        memo_eligible: bool,
89        /// Optional function-specific global scope (used by imported module
90        /// functions so they resolve names in their home module).
91        home_globals: Option<Rc<HashMap<String, Rc<Value>>>>,
92    },
93    Builtin(String),
94    /// User-defined sum type variant, e.g. `Shape.Circle(3.14)`
95    Variant {
96        type_name: String,
97        variant: String,
98        fields: Vec<Value>,
99    },
100    /// User-defined product type (record), e.g. `User(name = "Alice", age = 30)`
101    Record {
102        type_name: String,
103        fields: Vec<(String, Value)>,
104    },
105    /// Type namespace: `Shape` — provides `Shape.Circle`, `Shape.Rect`, etc.
106    Namespace {
107        name: String,
108        members: HashMap<String, Value>,
109    },
110}
111
112impl PartialEq for Value {
113    fn eq(&self, other: &Self) -> bool {
114        match (list_view(self), list_view(other)) {
115            (Some(xs), Some(ys)) => return xs.iter().eq(ys.iter()),
116            (Some(_), None) | (None, Some(_)) => return false,
117            (None, None) => {}
118        }
119
120        match (self, other) {
121            (Value::Int(a), Value::Int(b)) => a == b,
122            (Value::Float(a), Value::Float(b)) => {
123                if a.is_nan() || b.is_nan() {
124                    a.to_bits() == b.to_bits()
125                } else {
126                    a == b
127                }
128            }
129            (Value::Str(a), Value::Str(b)) => a == b,
130            (Value::Bool(a), Value::Bool(b)) => a == b,
131            (Value::Unit, Value::Unit) => true,
132            (Value::Ok(a), Value::Ok(b)) => a == b,
133            (Value::Err(a), Value::Err(b)) => a == b,
134            (Value::Some(a), Value::Some(b)) => a == b,
135            (Value::None, Value::None) => true,
136            (Value::Tuple(a), Value::Tuple(b)) => a == b,
137            (Value::Map(a), Value::Map(b)) => a == b,
138            (
139                Value::Fn {
140                    name: n1,
141                    params: p1,
142                    return_type: r1,
143                    effects: e1,
144                    body: b1,
145                    ..
146                },
147                Value::Fn {
148                    name: n2,
149                    params: p2,
150                    return_type: r2,
151                    effects: e2,
152                    body: b2,
153                    ..
154                },
155            ) => n1 == n2 && p1 == p2 && r1 == r2 && 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_view(self) {
199            8u8.hash(state);
200            items.len().hash(state);
201            for item in items.iter() {
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                return_type,
264                effects,
265                body,
266                ..
267            } => {
268                11u8.hash(state);
269                name.hash(state);
270                params.hash(state);
271                return_type.hash(state);
272                effects.hash(state);
273                format!("{:?}", body).hash(state);
274            }
275            Value::Builtin(name) => {
276                12u8.hash(state);
277                name.hash(state);
278            }
279            Value::Variant {
280                type_name,
281                variant,
282                fields,
283            } => {
284                13u8.hash(state);
285                type_name.hash(state);
286                variant.hash(state);
287                fields.hash(state);
288            }
289            Value::Record { type_name, fields } => {
290                14u8.hash(state);
291                type_name.hash(state);
292                fields.hash(state);
293            }
294            Value::Namespace { name, members } => {
295                15u8.hash(state);
296                name.hash(state);
297                let mut keys = members.keys().collect::<Vec<_>>();
298                keys.sort();
299                for key in keys {
300                    key.hash(state);
301                    if let Some(value) = members.get(key) {
302                        value.hash(state);
303                    }
304                }
305            }
306            Value::List(_) => unreachable!("list hashed above"),
307        }
308    }
309}
310
311// ---------------------------------------------------------------------------
312// Environment
313// ---------------------------------------------------------------------------
314
315#[derive(Debug, Clone)]
316pub enum EnvFrame {
317    Owned(HashMap<String, Rc<Value>>),
318    Shared(Rc<HashMap<String, Rc<Value>>>),
319    /// Slot-indexed frame for resolved function bodies — O(1) lookup.
320    Slots(Vec<Rc<Value>>),
321}
322
323/// Scope stack: innermost scope last.
324pub type Env = Vec<EnvFrame>;
325
326// ---------------------------------------------------------------------------
327// List helpers
328// ---------------------------------------------------------------------------
329
330pub(crate) type ListView<'a> = &'a AverList<Value>;
331
332pub(crate) fn list_view(value: &Value) -> Option<ListView<'_>> {
333    match value {
334        Value::List(items) => Some(items),
335        _ => None,
336    }
337}
338
339pub fn list_slice(value: &Value) -> Option<&[Value]> {
340    list_view(value).and_then(AverList::as_slice)
341}
342
343pub fn list_from_vec(items: Vec<Value>) -> Value {
344    Value::List(AverList::from_vec(items))
345}
346
347pub(crate) fn list_empty() -> Value {
348    Value::List(AverList::empty())
349}
350
351pub fn list_to_vec(value: &Value) -> Option<Vec<Value>> {
352    list_view(value).map(AverList::to_vec)
353}
354
355pub fn list_len(value: &Value) -> Option<usize> {
356    list_view(value).map(AverList::len)
357}
358
359pub(crate) fn list_get(value: &Value, index: usize) -> Option<Value> {
360    list_view(value).and_then(|items| items.get(index).cloned())
361}
362
363pub fn list_head(value: &Value) -> Option<Value> {
364    list_view(value).and_then(|items| items.first().cloned())
365}
366
367pub fn list_tail_view(value: &Value) -> Option<Value> {
368    list_view(value).and_then(AverList::tail).map(Value::List)
369}
370
371pub(crate) fn list_append(list: &Value, item: Value) -> Option<Value> {
372    list_view(list).map(|items| Value::List(AverList::append(items, item)))
373}
374
375pub(crate) fn list_prepend(item: Value, list: &Value) -> Option<Value> {
376    list_view(list).map(|items| Value::List(AverList::prepend(item, items)))
377}
378
379pub(crate) fn list_concat(left: &Value, right: &Value) -> Option<Value> {
380    let left = list_view(left)?;
381    let right = list_view(right)?;
382    Some(Value::List(AverList::concat(left, right)))
383}
384
385pub(crate) fn list_reverse(list: &Value) -> Option<Value> {
386    list_view(list).map(|items| Value::List(items.reverse()))
387}
388
389// ---------------------------------------------------------------------------
390// Display helpers
391// ---------------------------------------------------------------------------
392
393/// Human-readable representation of a value (used by `str()` and `:env`).
394pub fn aver_repr(val: &Value) -> String {
395    if let Some(items) = list_view(val) {
396        let parts: Vec<String> = items.iter().map(aver_repr_inner).collect();
397        return format!("[{}]", parts.join(", "));
398    }
399
400    match val {
401        Value::Int(i) => i.to_string(),
402        Value::Float(f) => f.to_string(),
403        Value::Str(s) => s.clone(),
404        Value::Bool(b) => if *b { "true" } else { "false" }.to_string(),
405        Value::Unit => "()".to_string(),
406        Value::Ok(v) => format!("Result.Ok({})", aver_repr_inner(v)),
407        Value::Err(v) => format!("Result.Err({})", aver_repr_inner(v)),
408        Value::Some(v) => format!("Option.Some({})", aver_repr_inner(v)),
409        Value::None => "Option.None".to_string(),
410        Value::Tuple(items) => {
411            let parts: Vec<String> = items.iter().map(aver_repr_inner).collect();
412            format!("({})", parts.join(", "))
413        }
414        Value::List(_) => unreachable!("handled via list_view above"),
415        Value::Map(entries) => {
416            let mut pairs = entries
417                .iter()
418                .map(|(k, v)| (aver_repr_inner(k), aver_repr_inner(v)))
419                .collect::<Vec<_>>();
420            pairs.sort_by(|(k1, _), (k2, _)| k1.cmp(k2));
421            let parts = pairs
422                .into_iter()
423                .map(|(k, v)| format!("{}: {}", k, v))
424                .collect::<Vec<_>>();
425            format!("{{{}}}", parts.join(", "))
426        }
427        Value::Fn { name, .. } => format!("<fn {}>", name),
428        Value::Builtin(name) => format!("<builtin {}>", name),
429        Value::Variant {
430            variant, fields, ..
431        } => {
432            if fields.is_empty() {
433                variant.clone()
434            } else {
435                let parts: Vec<String> = fields.iter().map(aver_repr_inner).collect();
436                format!("{}({})", variant, parts.join(", "))
437            }
438        }
439        Value::Record { type_name, fields } => {
440            let parts: Vec<String> = fields
441                .iter()
442                .map(|(k, v)| format!("{}: {}", k, aver_repr_inner(v)))
443                .collect();
444            format!("{}({})", type_name, parts.join(", "))
445        }
446        Value::Namespace { name, .. } => format!("<type {}>", name),
447    }
448}
449
450/// Like `aver_repr` but strings get quoted — used inside constructors and lists.
451fn aver_repr_inner(val: &Value) -> String {
452    if let Some(items) = list_view(val) {
453        let parts: Vec<String> = items.iter().map(aver_repr_inner).collect();
454        return format!("[{}]", parts.join(", "));
455    }
456
457    match val {
458        Value::Str(s) => format!("\"{}\"", s),
459        Value::Tuple(items) => {
460            let parts: Vec<String> = items.iter().map(aver_repr_inner).collect();
461            format!("({})", parts.join(", "))
462        }
463        Value::List(_) => unreachable!("handled via list_view above"),
464        other => aver_repr(other),
465    }
466}
467
468/// Returns the display string for `print()` — `None` for `Unit` (silent).
469pub fn aver_display(val: &Value) -> Option<String> {
470    match val {
471        Value::Unit => None,
472        other => Some(aver_repr(other)),
473    }
474}