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