Skip to main content

aver/
value.rs

1/// Core Aver runtime value type and associated utilities.
2///
3/// Lives in its own module so the VM 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    /// Compile-time resolution metadata (slot layout for locals).
113    pub resolution: Option<crate::ast::FnResolution>,
114    pub memo_eligible: bool,
115    /// Optional function-specific global scope (used by imported module
116    /// functions so they resolve names in their home module).
117    pub home_globals: Option<Rc<HashMap<String, NanValue>>>,
118}
119
120#[derive(Debug, Clone)]
121pub enum Value {
122    Int(i64),
123    Float(f64),
124    Str(String),
125    Bool(bool),
126    Unit,
127    Ok(Box<Value>),
128    Err(Box<Value>),
129    Some(Box<Value>),
130    None,
131    List(AverList<Value>),
132    Vector(AverVector<Value>),
133    Tuple(Vec<Value>),
134    Map(HashMap<Value, Value>),
135    Fn(Rc<FunctionValue>),
136    Builtin(String),
137    /// User-defined sum type variant, e.g. `Shape.Circle(3.14)`
138    Variant {
139        type_name: String,
140        variant: String,
141        fields: Rc<[Value]>,
142    },
143    /// User-defined product type (record), e.g. `User(name = "Alice", age = 30)`
144    Record {
145        type_name: String,
146        fields: Rc<[(String, Value)]>,
147    },
148    /// Type namespace: `Shape` — provides `Shape.Circle`, `Shape.Rect`, etc.
149    Namespace {
150        name: String,
151        members: HashMap<String, Value>,
152    },
153}
154
155impl PartialEq for Value {
156    fn eq(&self, other: &Self) -> bool {
157        match (list_view(self), list_view(other)) {
158            (Some(xs), Some(ys)) => return xs.iter().eq(ys.iter()),
159            (Some(_), None) | (None, Some(_)) => return false,
160            (None, None) => {}
161        }
162
163        match (self, other) {
164            (Value::Int(a), Value::Int(b)) => a == b,
165            (Value::Float(a), Value::Float(b)) => {
166                if a.is_nan() || b.is_nan() {
167                    a.to_bits() == b.to_bits()
168                } else {
169                    a == b
170                }
171            }
172            (Value::Str(a), Value::Str(b)) => a == b,
173            (Value::Bool(a), Value::Bool(b)) => a == b,
174            (Value::Unit, Value::Unit) => true,
175            (Value::Ok(a), Value::Ok(b)) => a == b,
176            (Value::Err(a), Value::Err(b)) => a == b,
177            (Value::Some(a), Value::Some(b)) => a == b,
178            (Value::None, Value::None) => true,
179            (Value::Vector(a), Value::Vector(b)) => a == b,
180            (Value::Tuple(a), Value::Tuple(b)) => a == b,
181            (Value::Map(a), Value::Map(b)) => a == b,
182            (Value::Fn(a), Value::Fn(b)) => {
183                a.name == b.name
184                    && a.params == b.params
185                    && a.return_type == b.return_type
186                    && a.effects == b.effects
187                    && a.body == b.body
188            }
189            (Value::Builtin(a), Value::Builtin(b)) => a == b,
190            (
191                Value::Variant {
192                    type_name: t1,
193                    variant: v1,
194                    fields: f1,
195                },
196                Value::Variant {
197                    type_name: t2,
198                    variant: v2,
199                    fields: f2,
200                },
201            ) => t1 == t2 && v1 == v2 && f1 == f2,
202            (
203                Value::Record {
204                    type_name: t1,
205                    fields: f1,
206                },
207                Value::Record {
208                    type_name: t2,
209                    fields: f2,
210                },
211            ) => t1 == t2 && f1 == f2,
212            (
213                Value::Namespace {
214                    name: n1,
215                    members: m1,
216                },
217                Value::Namespace {
218                    name: n2,
219                    members: m2,
220                },
221            ) => n1 == n2 && m1 == m2,
222            _ => false,
223        }
224    }
225}
226
227impl Eq for Value {}
228
229impl std::hash::Hash for Value {
230    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
231        if let Some(items) = list_view(self) {
232            8u8.hash(state);
233            items.len().hash(state);
234            for item in items.iter() {
235                item.hash(state);
236            }
237            return;
238        }
239
240        match self {
241            Value::Int(i) => {
242                0u8.hash(state);
243                i.hash(state);
244            }
245            Value::Float(f) => {
246                1u8.hash(state);
247                let bits = if *f == 0.0 {
248                    0.0f64.to_bits()
249                } else {
250                    f.to_bits()
251                };
252                bits.hash(state);
253            }
254            Value::Str(s) => {
255                2u8.hash(state);
256                s.hash(state);
257            }
258            Value::Bool(b) => {
259                3u8.hash(state);
260                b.hash(state);
261            }
262            Value::Unit => {
263                4u8.hash(state);
264            }
265            Value::Ok(v) => {
266                5u8.hash(state);
267                v.hash(state);
268            }
269            Value::Err(v) => {
270                6u8.hash(state);
271                v.hash(state);
272            }
273            Value::Some(v) => {
274                7u8.hash(state);
275                v.hash(state);
276            }
277            Value::None => {
278                9u8.hash(state);
279            }
280            Value::Map(map) => {
281                10u8.hash(state);
282                let mut entries = map.iter().collect::<Vec<_>>();
283                entries.sort_by(|(k1, _), (k2, _)| aver_repr(k1).cmp(&aver_repr(k2)));
284                for (k, v) in entries {
285                    k.hash(state);
286                    v.hash(state);
287                }
288            }
289            Value::Vector(vec) => {
290                17u8.hash(state);
291                vec.hash(state);
292            }
293            Value::Tuple(items) => {
294                16u8.hash(state);
295                items.hash(state);
296            }
297            Value::Fn(function) => {
298                11u8.hash(state);
299                function.name.hash(state);
300                function.params.hash(state);
301                function.return_type.hash(state);
302                function.effects.hash(state);
303                format!("{:?}", function.body).hash(state);
304            }
305            Value::Builtin(name) => {
306                12u8.hash(state);
307                name.hash(state);
308            }
309            Value::Variant {
310                type_name,
311                variant,
312                fields,
313            } => {
314                13u8.hash(state);
315                type_name.hash(state);
316                variant.hash(state);
317                fields.hash(state);
318            }
319            Value::Record { type_name, fields } => {
320                14u8.hash(state);
321                type_name.hash(state);
322                fields.hash(state);
323            }
324            Value::Namespace { name, members } => {
325                15u8.hash(state);
326                name.hash(state);
327                let mut keys = members.keys().collect::<Vec<_>>();
328                keys.sort();
329                for key in keys {
330                    key.hash(state);
331                    if let Some(value) = members.get(key) {
332                        value.hash(state);
333                    }
334                }
335            }
336            Value::List(_) => unreachable!("list hashed above"),
337        }
338    }
339}
340
341// ---------------------------------------------------------------------------
342// Environment
343// ---------------------------------------------------------------------------
344
345#[derive(Debug, Clone)]
346pub enum EnvFrame {
347    Owned(HashMap<String, NanValue>),
348    Shared(Rc<HashMap<String, NanValue>>),
349    /// Slot-indexed frame for resolved function bodies — O(1) lookup.
350    Slots(Vec<NanValue>),
351}
352
353/// Scope stack: innermost scope last.
354pub type Env = Vec<EnvFrame>;
355
356// ---------------------------------------------------------------------------
357// List helpers
358// ---------------------------------------------------------------------------
359
360pub(crate) type ListView<'a> = &'a AverList<Value>;
361
362pub(crate) fn list_view(value: &Value) -> Option<ListView<'_>> {
363    match value {
364        Value::List(items) => Some(items),
365        _ => None,
366    }
367}
368
369pub fn list_slice(value: &Value) -> Option<&[Value]> {
370    list_view(value).and_then(AverList::as_slice)
371}
372
373pub fn list_from_vec(items: Vec<Value>) -> Value {
374    Value::List(AverList::from_vec(items))
375}
376
377pub fn list_to_vec(value: &Value) -> Option<Vec<Value>> {
378    list_view(value).map(AverList::to_vec)
379}
380
381pub fn list_len(value: &Value) -> Option<usize> {
382    list_view(value).map(AverList::len)
383}
384
385pub fn list_head(value: &Value) -> Option<Value> {
386    list_view(value).and_then(|items| items.first().cloned())
387}
388
389pub(crate) fn list_prepend(item: Value, list: &Value) -> Option<Value> {
390    list_view(list).map(|items| Value::List(AverList::prepend(item, items)))
391}
392
393pub(crate) fn list_concat(left: &Value, right: &Value) -> Option<Value> {
394    let left = list_view(left)?;
395    let right = list_view(right)?;
396    Some(Value::List(AverList::concat(left, right)))
397}
398
399pub(crate) fn list_reverse(list: &Value) -> Option<Value> {
400    list_view(list).map(|items| Value::List(items.reverse()))
401}
402
403// ---------------------------------------------------------------------------
404// Effect inspection
405// ---------------------------------------------------------------------------
406
407/// Extract the declared effects from a callable value.
408pub fn callable_declared_effects(fn_val: &Value) -> Vec<String> {
409    match fn_val {
410        Value::Fn(function) => function.effects.as_ref().clone(),
411        _ => vec![],
412    }
413}
414
415// ---------------------------------------------------------------------------
416// Display helpers
417// ---------------------------------------------------------------------------
418
419/// Human-readable representation of a value (used by `str()` and `:env`).
420pub fn aver_repr(val: &Value) -> String {
421    if let Some(items) = list_view(val) {
422        let parts: Vec<String> = items.iter().map(aver_repr_inner).collect();
423        return format!("[{}]", parts.join(", "));
424    }
425
426    match val {
427        Value::Int(i) => i.to_string(),
428        Value::Float(f) => f.to_string(),
429        Value::Str(s) => s.clone(),
430        Value::Bool(b) => if *b { "true" } else { "false" }.to_string(),
431        Value::Unit => "Unit".to_string(),
432        Value::Ok(v) => format!("Result.Ok({})", aver_repr_inner(v)),
433        Value::Err(v) => format!("Result.Err({})", aver_repr_inner(v)),
434        Value::Some(v) => format!("Option.Some({})", aver_repr_inner(v)),
435        Value::None => "Option.None".to_string(),
436        Value::Tuple(items) => {
437            let parts: Vec<String> = items.iter().map(aver_repr_inner).collect();
438            format!("({})", parts.join(", "))
439        }
440        Value::Vector(vec) => {
441            let parts: Vec<String> = vec.iter().map(aver_repr_inner).collect();
442            format!("Vector[{}]", parts.join(", "))
443        }
444        Value::List(_) => unreachable!("handled via list_view above"),
445        Value::Map(entries) => {
446            let mut pairs = entries
447                .iter()
448                .map(|(k, v)| (aver_repr_inner(k), aver_repr_inner(v)))
449                .collect::<Vec<_>>();
450            pairs.sort_by(|(k1, _), (k2, _)| k1.cmp(k2));
451            let parts = pairs
452                .into_iter()
453                .map(|(k, v)| format!("{}: {}", k, v))
454                .collect::<Vec<_>>();
455            format!("{{{}}}", parts.join(", "))
456        }
457        Value::Fn(function) => format!("<fn {}>", function.name),
458        Value::Builtin(name) => format!("<builtin {}>", name),
459        Value::Variant {
460            variant, fields, ..
461        } => {
462            if fields.is_empty() {
463                variant.clone()
464            } else {
465                let parts: Vec<String> = fields.iter().map(aver_repr_inner).collect();
466                format!("{}({})", variant, parts.join(", "))
467            }
468        }
469        Value::Record { type_name, fields } => {
470            let parts: Vec<String> = fields
471                .iter()
472                .map(|(k, v)| format!("{}: {}", k, aver_repr_inner(v)))
473                .collect();
474            format!("{}({})", type_name, parts.join(", "))
475        }
476        Value::Namespace { name, .. } => format!("<type {}>", name),
477    }
478}
479
480/// Like `aver_repr` but strings get quoted — used inside constructors and lists.
481fn aver_repr_inner(val: &Value) -> String {
482    if let Some(items) = list_view(val) {
483        let parts: Vec<String> = items.iter().map(aver_repr_inner).collect();
484        return format!("[{}]", parts.join(", "));
485    }
486
487    match val {
488        Value::Str(s) => format!("\"{}\"", s),
489        Value::Tuple(items) => {
490            let parts: Vec<String> = items.iter().map(aver_repr_inner).collect();
491            format!("({})", parts.join(", "))
492        }
493        Value::Vector(vec) => {
494            let parts: Vec<String> = vec.iter().map(aver_repr_inner).collect();
495            format!("Vector[{}]", parts.join(", "))
496        }
497        Value::List(_) => unreachable!("handled via list_view above"),
498        other => aver_repr(other),
499    }
500}
501
502/// Returns the display string for `print()` — `None` for `Unit` (silent).
503pub fn aver_display(val: &Value) -> Option<String> {
504    match val {
505        Value::Unit => None,
506        other => Some(aver_repr(other)),
507    }
508}