1use std::collections::HashMap;
7use std::rc::Rc;
8use thiserror::Error;
9
10use crate::ast::FnBody;
11
12#[derive(Debug, Error)]
17pub enum RuntimeError {
18 #[error("Runtime error: {0}")]
19 Error(String),
20 #[error("Error propagation")]
24 ErrProp(Box<Value>),
25 #[error("Tail call")]
28 TailCall(Box<(String, Vec<Value>)>),
29 #[error("Replay mismatch at seq {seq}: expected '{expected}', got '{got}'")]
30 ReplayMismatch {
31 seq: u32,
32 expected: String,
33 got: String,
34 },
35 #[error(
36 "Replay args mismatch at seq {seq} for '{effect_type}': expected {expected}, got {got}"
37 )]
38 ReplayArgsMismatch {
39 seq: u32,
40 effect_type: String,
41 expected: String,
42 got: String,
43 },
44 #[error("Replay exhausted at position {position}: no recorded effect for call '{effect_type}'")]
45 ReplayExhausted {
46 effect_type: String,
47 position: usize,
48 },
49 #[error("Replay has {remaining} unconsumed effect(s)")]
50 ReplayUnconsumed { remaining: usize },
51 #[error("Replay serialization error: {0}")]
52 ReplaySerialization(String),
53}
54
55#[derive(Debug, Clone)]
60pub enum Value {
61 Int(i64),
62 Float(f64),
63 Str(String),
64 Bool(bool),
65 Unit,
66 Ok(Box<Value>),
67 Err(Box<Value>),
68 Some(Box<Value>),
69 None,
70 List(Vec<Value>),
71 Tuple(Vec<Value>),
72 Map(HashMap<Value, Value>),
73 ListSlice {
76 items: Rc<Vec<Value>>,
77 start: usize,
78 },
79 Fn {
80 name: String,
81 params: Vec<(String, String)>,
82 effects: Vec<String>,
83 body: Rc<FnBody>,
84 resolution: Option<crate::ast::FnResolution>,
86 memo_eligible: bool,
89 home_globals: Option<Rc<HashMap<String, Rc<Value>>>>,
92 },
93 Builtin(String),
94 Variant {
96 type_name: String,
97 variant: String,
98 fields: Vec<Value>,
99 },
100 Record {
102 type_name: String,
103 fields: Vec<(String, Value)>,
104 },
105 Namespace {
107 name: String,
108 members: HashMap<String, Value>,
109 },
110}
111
112impl PartialEq for Value {
113 fn eq(&self, other: &Self) -> bool {
114 match (list_slice(self), list_slice(other)) {
115 (Some(xs), Some(ys)) => return xs == ys,
116 (Some(_), None) | (None, Some(_)) => return false,
117 (None, None) => {}
118 }
119
120 match (self, other) {
121 (Value::Int(a), Value::Int(b)) => a == b,
122 (Value::Float(a), Value::Float(b)) => {
123 if a.is_nan() || b.is_nan() {
124 a.to_bits() == b.to_bits()
125 } else {
126 a == b
127 }
128 }
129 (Value::Str(a), Value::Str(b)) => a == b,
130 (Value::Bool(a), Value::Bool(b)) => a == b,
131 (Value::Unit, Value::Unit) => true,
132 (Value::Ok(a), Value::Ok(b)) => a == b,
133 (Value::Err(a), Value::Err(b)) => a == b,
134 (Value::Some(a), Value::Some(b)) => a == b,
135 (Value::None, Value::None) => true,
136 (Value::Tuple(a), Value::Tuple(b)) => a == b,
137 (Value::Map(a), Value::Map(b)) => a == b,
138 (
139 Value::Fn {
140 name: n1,
141 params: p1,
142 effects: e1,
143 body: b1,
144 ..
145 },
146 Value::Fn {
147 name: n2,
148 params: p2,
149 effects: e2,
150 body: b2,
151 ..
152 },
153 ) => n1 == n2 && p1 == p2 && e1 == e2 && b1 == b2,
154 (Value::Builtin(a), Value::Builtin(b)) => a == b,
155 (
156 Value::Variant {
157 type_name: t1,
158 variant: v1,
159 fields: f1,
160 },
161 Value::Variant {
162 type_name: t2,
163 variant: v2,
164 fields: f2,
165 },
166 ) => t1 == t2 && v1 == v2 && f1 == f2,
167 (
168 Value::Record {
169 type_name: t1,
170 fields: f1,
171 },
172 Value::Record {
173 type_name: t2,
174 fields: f2,
175 },
176 ) => t1 == t2 && f1 == f2,
177 (
178 Value::Namespace {
179 name: n1,
180 members: m1,
181 },
182 Value::Namespace {
183 name: n2,
184 members: m2,
185 },
186 ) => n1 == n2 && m1 == m2,
187 _ => false,
188 }
189 }
190}
191
192impl Eq for Value {}
193
194impl std::hash::Hash for Value {
195 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
196 if let Some(items) = list_slice(self) {
197 8u8.hash(state);
198 items.len().hash(state);
199 for item in items {
200 item.hash(state);
201 }
202 return;
203 }
204
205 match self {
206 Value::Int(i) => {
207 0u8.hash(state);
208 i.hash(state);
209 }
210 Value::Float(f) => {
211 1u8.hash(state);
212 let bits = if *f == 0.0 {
213 0.0f64.to_bits()
214 } else {
215 f.to_bits()
216 };
217 bits.hash(state);
218 }
219 Value::Str(s) => {
220 2u8.hash(state);
221 s.hash(state);
222 }
223 Value::Bool(b) => {
224 3u8.hash(state);
225 b.hash(state);
226 }
227 Value::Unit => {
228 4u8.hash(state);
229 }
230 Value::Ok(v) => {
231 5u8.hash(state);
232 v.hash(state);
233 }
234 Value::Err(v) => {
235 6u8.hash(state);
236 v.hash(state);
237 }
238 Value::Some(v) => {
239 7u8.hash(state);
240 v.hash(state);
241 }
242 Value::None => {
243 9u8.hash(state);
244 }
245 Value::Map(map) => {
246 10u8.hash(state);
247 let mut entries = map.iter().collect::<Vec<_>>();
248 entries.sort_by(|(k1, _), (k2, _)| aver_repr(k1).cmp(&aver_repr(k2)));
249 for (k, v) in entries {
250 k.hash(state);
251 v.hash(state);
252 }
253 }
254 Value::Tuple(items) => {
255 16u8.hash(state);
256 items.hash(state);
257 }
258 Value::Fn {
259 name,
260 params,
261 effects,
262 body,
263 ..
264 } => {
265 11u8.hash(state);
266 name.hash(state);
267 params.hash(state);
268 effects.hash(state);
269 format!("{:?}", body).hash(state);
270 }
271 Value::Builtin(name) => {
272 12u8.hash(state);
273 name.hash(state);
274 }
275 Value::Variant {
276 type_name,
277 variant,
278 fields,
279 } => {
280 13u8.hash(state);
281 type_name.hash(state);
282 variant.hash(state);
283 fields.hash(state);
284 }
285 Value::Record { type_name, fields } => {
286 14u8.hash(state);
287 type_name.hash(state);
288 fields.hash(state);
289 }
290 Value::Namespace { name, members } => {
291 15u8.hash(state);
292 name.hash(state);
293 let mut keys = members.keys().collect::<Vec<_>>();
294 keys.sort();
295 for key in keys {
296 key.hash(state);
297 if let Some(value) = members.get(key) {
298 value.hash(state);
299 }
300 }
301 }
302 Value::List(_) | Value::ListSlice { .. } => unreachable!("list hashed above"),
303 }
304 }
305}
306
307#[derive(Debug, Clone)]
312pub enum EnvFrame {
313 Owned(HashMap<String, Rc<Value>>),
314 Shared(Rc<HashMap<String, Rc<Value>>>),
315 Slots(Vec<Rc<Value>>),
317}
318
319pub type Env = Vec<EnvFrame>;
321
322pub fn list_slice(value: &Value) -> Option<&[Value]> {
327 match value {
328 Value::List(items) => Some(items.as_slice()),
329 Value::ListSlice { items, start } => Some(items.get(*start..).unwrap_or(&[])),
330 _ => None,
331 }
332}
333
334pub fn list_from_vec(items: Vec<Value>) -> Value {
335 Value::ListSlice {
336 items: Rc::new(items),
337 start: 0,
338 }
339}
340
341pub fn list_to_vec(value: &Value) -> Option<Vec<Value>> {
342 list_slice(value).map(|items| items.to_vec())
343}
344
345pub fn list_len(value: &Value) -> Option<usize> {
346 list_slice(value).map(|items| items.len())
347}
348
349pub fn list_head(value: &Value) -> Option<Value> {
350 list_slice(value).and_then(|items| items.first().cloned())
351}
352
353pub fn list_tail_view(value: &Value) -> Option<Value> {
354 match value {
355 Value::List(items) => {
356 if items.is_empty() {
357 None
358 } else {
359 Some(Value::ListSlice {
360 items: Rc::new(items.clone()),
361 start: 1,
362 })
363 }
364 }
365 Value::ListSlice { items, start } => {
366 if *start >= items.len() {
367 None
368 } else {
369 Some(Value::ListSlice {
370 items: Rc::clone(items),
371 start: start + 1,
372 })
373 }
374 }
375 _ => None,
376 }
377}
378
379pub fn aver_repr(val: &Value) -> String {
385 match val {
386 Value::Int(i) => i.to_string(),
387 Value::Float(f) => f.to_string(),
388 Value::Str(s) => s.clone(),
389 Value::Bool(b) => if *b { "true" } else { "false" }.to_string(),
390 Value::Unit => "()".to_string(),
391 Value::Ok(v) => format!("Result.Ok({})", aver_repr_inner(v)),
392 Value::Err(v) => format!("Result.Err({})", aver_repr_inner(v)),
393 Value::Some(v) => format!("Option.Some({})", aver_repr_inner(v)),
394 Value::None => "Option.None".to_string(),
395 Value::List(_) | Value::ListSlice { .. } => {
396 let items = list_slice(val).expect("list variants must have a slice view");
397 let parts: Vec<String> = items.iter().map(aver_repr_inner).collect();
398 format!("[{}]", parts.join(", "))
399 }
400 Value::Tuple(items) => {
401 let parts: Vec<String> = items.iter().map(aver_repr_inner).collect();
402 format!("({})", parts.join(", "))
403 }
404 Value::Map(entries) => {
405 let mut pairs = entries
406 .iter()
407 .map(|(k, v)| (aver_repr_inner(k), aver_repr_inner(v)))
408 .collect::<Vec<_>>();
409 pairs.sort_by(|(k1, _), (k2, _)| k1.cmp(k2));
410 let parts = pairs
411 .into_iter()
412 .map(|(k, v)| format!("{}: {}", k, v))
413 .collect::<Vec<_>>();
414 format!("{{{}}}", parts.join(", "))
415 }
416 Value::Fn { name, .. } => format!("<fn {}>", name),
417 Value::Builtin(name) => format!("<builtin {}>", name),
418 Value::Variant {
419 variant, fields, ..
420 } => {
421 if fields.is_empty() {
422 variant.clone()
423 } else {
424 let parts: Vec<String> = fields.iter().map(aver_repr_inner).collect();
425 format!("{}({})", variant, parts.join(", "))
426 }
427 }
428 Value::Record { type_name, fields } => {
429 let parts: Vec<String> = fields
430 .iter()
431 .map(|(k, v)| format!("{}: {}", k, aver_repr_inner(v)))
432 .collect();
433 format!("{}({})", type_name, parts.join(", "))
434 }
435 Value::Namespace { name, .. } => format!("<type {}>", name),
436 }
437}
438
439fn aver_repr_inner(val: &Value) -> String {
441 match val {
442 Value::Str(s) => format!("\"{}\"", s),
443 Value::Tuple(items) => {
444 let parts: Vec<String> = items.iter().map(aver_repr_inner).collect();
445 format!("({})", parts.join(", "))
446 }
447 Value::List(_) | Value::ListSlice { .. } => {
448 let items = list_slice(val).expect("list variants must have a slice view");
449 let parts: Vec<String> = items.iter().map(aver_repr_inner).collect();
450 format!("[{}]", parts.join(", "))
451 }
452 other => aver_repr(other),
453 }
454}
455
456pub fn aver_display(val: &Value) -> Option<String> {
458 match val {
459 Value::Unit => None,
460 other => Some(aver_repr(other)),
461 }
462}
463
464pub fn hash_memo_args(args: &[Value]) -> u64 {
470 use std::hash::Hasher;
471 let mut hasher = std::collections::hash_map::DefaultHasher::new();
472 for arg in args {
473 hash_value(arg, &mut hasher);
474 }
475 hasher.finish()
476}
477
478fn hash_value(val: &Value, hasher: &mut impl std::hash::Hasher) {
479 use std::hash::Hash;
480 match val {
481 Value::Int(i) => {
482 0u8.hash(hasher);
483 i.hash(hasher);
484 }
485 Value::Float(f) => {
486 1u8.hash(hasher);
487 f.to_bits().hash(hasher);
488 }
489 Value::Str(s) => {
490 2u8.hash(hasher);
491 s.hash(hasher);
492 }
493 Value::Bool(b) => {
494 3u8.hash(hasher);
495 b.hash(hasher);
496 }
497 Value::Unit => {
498 4u8.hash(hasher);
499 }
500 Value::Tuple(items) => {
501 7u8.hash(hasher);
502 items.len().hash(hasher);
503 for item in items {
504 hash_value(item, hasher);
505 }
506 }
507 Value::Record { type_name, fields } => {
508 5u8.hash(hasher);
509 type_name.hash(hasher);
510 for (k, v) in fields {
511 k.hash(hasher);
512 hash_value(v, hasher);
513 }
514 }
515 Value::Variant {
516 type_name,
517 variant,
518 fields,
519 } => {
520 6u8.hash(hasher);
521 type_name.hash(hasher);
522 variant.hash(hasher);
523 for v in fields {
524 hash_value(v, hasher);
525 }
526 }
527 _ => {
529 255u8.hash(hasher);
530 }
531 }
532}