1use 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#[derive(Debug, Error)]
22pub enum RuntimeError {
23 #[error("Runtime error: {0}")]
24 Error(String),
25 #[error("Error propagation")]
29 ErrProp(Box<Value>),
30 #[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#[derive(Debug, Clone)]
65pub struct FunctionValue {
66 pub name: Rc<String>,
67 pub params: Rc<Vec<(String, String)>>,
68 pub return_type: Rc<String>,
69 pub effects: Rc<Vec<String>>,
70 pub body: Rc<FnBody>,
71 pub(crate) lowered_body: Rc<crate::interpreter::lowered::LoweredFunctionBody>,
72 pub resolution: Option<crate::ast::FnResolution>,
74 pub memo_eligible: bool,
77 pub home_globals: Option<Rc<HashMap<String, Value>>>,
80}
81
82#[derive(Debug, Clone)]
83pub enum Value {
84 Int(i64),
85 Float(f64),
86 Str(String),
87 Bool(bool),
88 Unit,
89 Ok(Box<Value>),
90 Err(Box<Value>),
91 Some(Box<Value>),
92 None,
93 List(AverList<Value>),
94 Tuple(Vec<Value>),
95 Map(HashMap<Value, Value>),
96 Fn(Rc<FunctionValue>),
97 Builtin(String),
98 Variant {
100 type_name: String,
101 variant: String,
102 fields: Rc<[Value]>,
103 },
104 Record {
106 type_name: String,
107 fields: Rc<[(String, Value)]>,
108 },
109 Namespace {
111 name: String,
112 members: HashMap<String, Value>,
113 },
114}
115
116impl PartialEq for Value {
117 fn eq(&self, other: &Self) -> bool {
118 match (list_view(self), list_view(other)) {
119 (Some(xs), Some(ys)) => return xs.iter().eq(ys.iter()),
120 (Some(_), None) | (None, Some(_)) => return false,
121 (None, None) => {}
122 }
123
124 match (self, other) {
125 (Value::Int(a), Value::Int(b)) => a == b,
126 (Value::Float(a), Value::Float(b)) => {
127 if a.is_nan() || b.is_nan() {
128 a.to_bits() == b.to_bits()
129 } else {
130 a == b
131 }
132 }
133 (Value::Str(a), Value::Str(b)) => a == b,
134 (Value::Bool(a), Value::Bool(b)) => a == b,
135 (Value::Unit, Value::Unit) => true,
136 (Value::Ok(a), Value::Ok(b)) => a == b,
137 (Value::Err(a), Value::Err(b)) => a == b,
138 (Value::Some(a), Value::Some(b)) => a == b,
139 (Value::None, Value::None) => true,
140 (Value::Tuple(a), Value::Tuple(b)) => a == b,
141 (Value::Map(a), Value::Map(b)) => a == b,
142 (Value::Fn(a), Value::Fn(b)) => {
143 a.name == b.name
144 && a.params == b.params
145 && a.return_type == b.return_type
146 && a.effects == b.effects
147 && a.body == b.body
148 }
149 (Value::Builtin(a), Value::Builtin(b)) => a == b,
150 (
151 Value::Variant {
152 type_name: t1,
153 variant: v1,
154 fields: f1,
155 },
156 Value::Variant {
157 type_name: t2,
158 variant: v2,
159 fields: f2,
160 },
161 ) => t1 == t2 && v1 == v2 && f1 == f2,
162 (
163 Value::Record {
164 type_name: t1,
165 fields: f1,
166 },
167 Value::Record {
168 type_name: t2,
169 fields: f2,
170 },
171 ) => t1 == t2 && f1 == f2,
172 (
173 Value::Namespace {
174 name: n1,
175 members: m1,
176 },
177 Value::Namespace {
178 name: n2,
179 members: m2,
180 },
181 ) => n1 == n2 && m1 == m2,
182 _ => false,
183 }
184 }
185}
186
187impl Eq for Value {}
188
189impl std::hash::Hash for Value {
190 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
191 if let Some(items) = list_view(self) {
192 8u8.hash(state);
193 items.len().hash(state);
194 for item in items.iter() {
195 item.hash(state);
196 }
197 return;
198 }
199
200 match self {
201 Value::Int(i) => {
202 0u8.hash(state);
203 i.hash(state);
204 }
205 Value::Float(f) => {
206 1u8.hash(state);
207 let bits = if *f == 0.0 {
208 0.0f64.to_bits()
209 } else {
210 f.to_bits()
211 };
212 bits.hash(state);
213 }
214 Value::Str(s) => {
215 2u8.hash(state);
216 s.hash(state);
217 }
218 Value::Bool(b) => {
219 3u8.hash(state);
220 b.hash(state);
221 }
222 Value::Unit => {
223 4u8.hash(state);
224 }
225 Value::Ok(v) => {
226 5u8.hash(state);
227 v.hash(state);
228 }
229 Value::Err(v) => {
230 6u8.hash(state);
231 v.hash(state);
232 }
233 Value::Some(v) => {
234 7u8.hash(state);
235 v.hash(state);
236 }
237 Value::None => {
238 9u8.hash(state);
239 }
240 Value::Map(map) => {
241 10u8.hash(state);
242 let mut entries = map.iter().collect::<Vec<_>>();
243 entries.sort_by(|(k1, _), (k2, _)| aver_repr(k1).cmp(&aver_repr(k2)));
244 for (k, v) in entries {
245 k.hash(state);
246 v.hash(state);
247 }
248 }
249 Value::Tuple(items) => {
250 16u8.hash(state);
251 items.hash(state);
252 }
253 Value::Fn(function) => {
254 11u8.hash(state);
255 function.name.hash(state);
256 function.params.hash(state);
257 function.return_type.hash(state);
258 function.effects.hash(state);
259 format!("{:?}", function.body).hash(state);
260 }
261 Value::Builtin(name) => {
262 12u8.hash(state);
263 name.hash(state);
264 }
265 Value::Variant {
266 type_name,
267 variant,
268 fields,
269 } => {
270 13u8.hash(state);
271 type_name.hash(state);
272 variant.hash(state);
273 fields.hash(state);
274 }
275 Value::Record { type_name, fields } => {
276 14u8.hash(state);
277 type_name.hash(state);
278 fields.hash(state);
279 }
280 Value::Namespace { name, members } => {
281 15u8.hash(state);
282 name.hash(state);
283 let mut keys = members.keys().collect::<Vec<_>>();
284 keys.sort();
285 for key in keys {
286 key.hash(state);
287 if let Some(value) = members.get(key) {
288 value.hash(state);
289 }
290 }
291 }
292 Value::List(_) => unreachable!("list hashed above"),
293 }
294 }
295}
296
297#[derive(Debug, Clone)]
302pub enum EnvFrame {
303 Owned(HashMap<String, Value>),
304 Shared(Rc<HashMap<String, Value>>),
305 Slots(Vec<Value>),
307}
308
309pub type Env = Vec<EnvFrame>;
311
312pub(crate) type ListView<'a> = &'a AverList<Value>;
317
318pub(crate) fn list_view(value: &Value) -> Option<ListView<'_>> {
319 match value {
320 Value::List(items) => Some(items),
321 _ => None,
322 }
323}
324
325pub fn list_slice(value: &Value) -> Option<&[Value]> {
326 list_view(value).and_then(AverList::as_slice)
327}
328
329pub fn list_from_vec(items: Vec<Value>) -> Value {
330 Value::List(AverList::from_vec(items))
331}
332
333pub fn list_to_vec(value: &Value) -> Option<Vec<Value>> {
334 list_view(value).map(AverList::to_vec)
335}
336
337pub fn list_len(value: &Value) -> Option<usize> {
338 list_view(value).map(AverList::len)
339}
340
341pub(crate) fn list_get(value: &Value, index: usize) -> Option<Value> {
342 list_view(value).and_then(|items| items.get(index).cloned())
343}
344
345pub fn list_head(value: &Value) -> Option<Value> {
346 list_view(value).and_then(|items| items.first().cloned())
347}
348
349pub(crate) fn list_append(list: &Value, item: Value) -> Option<Value> {
350 list_view(list).map(|items| Value::List(AverList::append(items, item)))
351}
352
353pub(crate) fn list_prepend(item: Value, list: &Value) -> Option<Value> {
354 list_view(list).map(|items| Value::List(AverList::prepend(item, items)))
355}
356
357pub(crate) fn list_concat(left: &Value, right: &Value) -> Option<Value> {
358 let left = list_view(left)?;
359 let right = list_view(right)?;
360 Some(Value::List(AverList::concat(left, right)))
361}
362
363pub(crate) fn list_reverse(list: &Value) -> Option<Value> {
364 list_view(list).map(|items| Value::List(items.reverse()))
365}
366
367pub fn aver_repr(val: &Value) -> String {
373 if let Some(items) = list_view(val) {
374 let parts: Vec<String> = items.iter().map(aver_repr_inner).collect();
375 return format!("[{}]", parts.join(", "));
376 }
377
378 match val {
379 Value::Int(i) => i.to_string(),
380 Value::Float(f) => f.to_string(),
381 Value::Str(s) => s.clone(),
382 Value::Bool(b) => if *b { "true" } else { "false" }.to_string(),
383 Value::Unit => "Unit".to_string(),
384 Value::Ok(v) => format!("Result.Ok({})", aver_repr_inner(v)),
385 Value::Err(v) => format!("Result.Err({})", aver_repr_inner(v)),
386 Value::Some(v) => format!("Option.Some({})", aver_repr_inner(v)),
387 Value::None => "Option.None".to_string(),
388 Value::Tuple(items) => {
389 let parts: Vec<String> = items.iter().map(aver_repr_inner).collect();
390 format!("({})", parts.join(", "))
391 }
392 Value::List(_) => unreachable!("handled via list_view above"),
393 Value::Map(entries) => {
394 let mut pairs = entries
395 .iter()
396 .map(|(k, v)| (aver_repr_inner(k), aver_repr_inner(v)))
397 .collect::<Vec<_>>();
398 pairs.sort_by(|(k1, _), (k2, _)| k1.cmp(k2));
399 let parts = pairs
400 .into_iter()
401 .map(|(k, v)| format!("{}: {}", k, v))
402 .collect::<Vec<_>>();
403 format!("{{{}}}", parts.join(", "))
404 }
405 Value::Fn(function) => format!("<fn {}>", function.name),
406 Value::Builtin(name) => format!("<builtin {}>", name),
407 Value::Variant {
408 variant, fields, ..
409 } => {
410 if fields.is_empty() {
411 variant.clone()
412 } else {
413 let parts: Vec<String> = fields.iter().map(aver_repr_inner).collect();
414 format!("{}({})", variant, parts.join(", "))
415 }
416 }
417 Value::Record { type_name, fields } => {
418 let parts: Vec<String> = fields
419 .iter()
420 .map(|(k, v)| format!("{}: {}", k, aver_repr_inner(v)))
421 .collect();
422 format!("{}({})", type_name, parts.join(", "))
423 }
424 Value::Namespace { name, .. } => format!("<type {}>", name),
425 }
426}
427
428fn aver_repr_inner(val: &Value) -> String {
430 if let Some(items) = list_view(val) {
431 let parts: Vec<String> = items.iter().map(aver_repr_inner).collect();
432 return format!("[{}]", parts.join(", "));
433 }
434
435 match val {
436 Value::Str(s) => format!("\"{}\"", s),
437 Value::Tuple(items) => {
438 let parts: Vec<String> = items.iter().map(aver_repr_inner).collect();
439 format!("({})", parts.join(", "))
440 }
441 Value::List(_) => unreachable!("handled via list_view above"),
442 other => aver_repr(other),
443 }
444}
445
446pub fn aver_display(val: &Value) -> Option<String> {
448 match val {
449 Value::Unit => None,
450 other => Some(aver_repr(other)),
451 }
452}