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