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