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