Skip to main content

aver/interpreter/
eval.rs

1use super::*;
2
3#[derive(Debug)]
4enum EvalState {
5    Expr(Expr),
6    Body {
7        body: Rc<FnBody>,
8        idx: usize,
9        local_slots: Option<Rc<HashMap<String, u16>>>,
10        last: Value,
11    },
12    Apply(Result<Value, RuntimeError>),
13}
14
15#[derive(Debug, Clone)]
16enum EvalCont {
17    Attr(String),
18    Call {
19        args: Vec<Expr>,
20        idx: usize,
21        fn_val: Option<Value>,
22        arg_vals: Vec<Value>,
23    },
24    BinOpLeft {
25        op: BinOp,
26        right: Expr,
27    },
28    BinOpRight {
29        op: BinOp,
30        left: Value,
31    },
32    Match {
33        arms: Vec<MatchArm>,
34        line: usize,
35    },
36    Constructor(String),
37    ErrorProp,
38    InterpolatedStr {
39        parts: Vec<StrPart>,
40        idx: usize,
41        result: String,
42    },
43    List {
44        items: Vec<Expr>,
45        idx: usize,
46        values: Vec<Value>,
47    },
48    Tuple {
49        items: Vec<Expr>,
50        idx: usize,
51        values: Vec<Value>,
52    },
53    MapKey {
54        entries: Vec<(Expr, Expr)>,
55        idx: usize,
56        map: HashMap<Value, Value>,
57    },
58    MapValue {
59        entries: Vec<(Expr, Expr)>,
60        idx: usize,
61        map: HashMap<Value, Value>,
62        key: Value,
63    },
64    RecordCreate {
65        type_name: String,
66        fields: Vec<(String, Expr)>,
67        idx: usize,
68        seen: HashSet<String>,
69        values: Vec<(String, Value)>,
70    },
71    RecordUpdateBase {
72        type_name: String,
73        updates: Vec<(String, Expr)>,
74    },
75    RecordUpdateField(RecordUpdateProgress),
76    TailCallArgs {
77        target: String,
78        args: Vec<Expr>,
79        idx: usize,
80        values: Vec<Value>,
81    },
82    BodyBinding {
83        name: String,
84        next_idx: usize,
85        body: Rc<FnBody>,
86        local_slots: Option<Rc<HashMap<String, u16>>>,
87    },
88    BodyExpr {
89        next_idx: usize,
90        body: Rc<FnBody>,
91        local_slots: Option<Rc<HashMap<String, u16>>>,
92    },
93    MatchScope,
94    FunctionReturn(FunctionFrame),
95}
96
97#[derive(Debug, Clone)]
98struct ActiveFunction {
99    name: String,
100    params: Vec<(String, String)>,
101    body: Rc<FnBody>,
102    resolution: Option<FnResolution>,
103}
104
105#[derive(Debug, Clone)]
106struct FunctionFrame {
107    active: ActiveFunction,
108    prev_local_slots: Option<HashMap<String, u16>>,
109    saved_frames: Vec<EnvFrame>,
110    prev_global: Option<EnvFrame>,
111    memo_key: Option<(u64, Vec<Value>)>,
112}
113
114#[derive(Debug, Clone)]
115struct RecordUpdateProgress {
116    type_name: String,
117    base_type: String,
118    base_fields: Vec<(String, Value)>,
119    updates: Vec<(String, Expr)>,
120    idx: usize,
121    update_vals: Vec<(String, Value)>,
122}
123
124enum CallDispatch {
125    Immediate(Result<Value, RuntimeError>),
126    EnterFunction {
127        frame: Box<FunctionFrame>,
128        state: EvalState,
129    },
130}
131
132impl Interpreter {
133    fn empty_slots(local_count: u16) -> Vec<Rc<Value>> {
134        let unit = Rc::new(Value::Unit);
135        vec![unit; local_count as usize]
136    }
137
138    pub fn eval_expr(&mut self, expr: &Expr) -> Result<Value, RuntimeError> {
139        self.eval_loop(EvalState::Expr(expr.clone()), Vec::new())
140    }
141
142    fn eval_loop(
143        &mut self,
144        initial: EvalState,
145        mut conts: Vec<EvalCont>,
146    ) -> Result<Value, RuntimeError> {
147        let mut state = initial;
148
149        loop {
150            state = match state {
151                EvalState::Expr(expr) => self.step_expr(expr, &mut conts),
152                EvalState::Body {
153                    body,
154                    idx,
155                    local_slots,
156                    last,
157                } => self.step_body(body, idx, local_slots, last, &mut conts),
158                EvalState::Apply(result) => {
159                    let Some(cont) = conts.pop() else {
160                        return result;
161                    };
162                    self.apply_cont(cont, result, &mut conts)
163                }
164            };
165        }
166    }
167
168    fn step_expr(&mut self, expr: Expr, conts: &mut Vec<EvalCont>) -> EvalState {
169        match expr {
170            Expr::Literal(lit) => EvalState::Apply(Ok(self.eval_literal(&lit))),
171            Expr::Resolved(slot) => EvalState::Apply(self.lookup_slot(slot)),
172            Expr::Ident(name) => EvalState::Apply(self.lookup(&name)),
173            Expr::Attr(obj, field) => {
174                if let Expr::Ident(name) = obj.as_ref() {
175                    let rc = match self.lookup_rc(name) {
176                        Ok(rc) => rc,
177                        Err(err) => return EvalState::Apply(Err(err)),
178                    };
179                    let result = match rc.as_ref() {
180                        Value::Namespace { name, members } => {
181                            members.get(field.as_str()).cloned().ok_or_else(|| {
182                                RuntimeError::Error(format!("Unknown member '{}.{}'", name, field))
183                            })
184                        }
185                        Value::Record { fields, .. } => fields
186                            .iter()
187                            .find(|(k, _)| k == &field)
188                            .map(|(_, value)| Ok(value.clone()))
189                            .unwrap_or_else(|| {
190                                Err(RuntimeError::Error(format!("Unknown field '{}'", field)))
191                            }),
192                        _ => Err(RuntimeError::Error(format!(
193                            "Field access '{}' is not supported on this value",
194                            field
195                        ))),
196                    };
197                    return EvalState::Apply(result);
198                }
199
200                conts.push(EvalCont::Attr(field));
201                EvalState::Expr(*obj)
202            }
203            Expr::FnCall(fn_expr, args) => {
204                conts.push(EvalCont::Call {
205                    args,
206                    idx: 0,
207                    fn_val: None,
208                    arg_vals: Vec::new(),
209                });
210                EvalState::Expr(*fn_expr)
211            }
212            Expr::BinOp(op, left, right) => {
213                conts.push(EvalCont::BinOpLeft { op, right: *right });
214                EvalState::Expr(*left)
215            }
216            Expr::Match {
217                subject,
218                arms,
219                line,
220            } => {
221                conts.push(EvalCont::Match { arms, line });
222                EvalState::Expr(*subject)
223            }
224            Expr::Constructor(name, arg) => match arg {
225                Some(inner) => {
226                    conts.push(EvalCont::Constructor(name));
227                    EvalState::Expr(*inner)
228                }
229                None => EvalState::Apply(match name.as_str() {
230                    "None" => Ok(Value::None),
231                    "Ok" | "Err" | "Some" => Err(RuntimeError::Error(format!(
232                        "Constructor '{}' expects an argument",
233                        name
234                    ))),
235                    _ => Err(RuntimeError::Error(format!(
236                        "Unknown constructor: {}",
237                        name
238                    ))),
239                }),
240            },
241            Expr::ErrorProp(inner) => {
242                conts.push(EvalCont::ErrorProp);
243                EvalState::Expr(*inner)
244            }
245            Expr::InterpolatedStr(parts) => {
246                self.resume_interpolated_str(parts, 0, String::new(), conts)
247            }
248            Expr::List(items) => self.resume_list(items, 0, Vec::new(), conts),
249            Expr::Tuple(items) => {
250                let cap = items.len();
251                self.resume_tuple(items, 0, Vec::with_capacity(cap), conts)
252            }
253            Expr::MapLiteral(entries) => self.resume_map(entries, 0, HashMap::new(), conts),
254            Expr::RecordCreate { type_name, fields } => {
255                self.resume_record_create(type_name, fields, 0, HashSet::new(), Vec::new(), conts)
256            }
257            Expr::RecordUpdate {
258                type_name,
259                base,
260                updates,
261            } => {
262                conts.push(EvalCont::RecordUpdateBase { type_name, updates });
263                EvalState::Expr(*base)
264            }
265            Expr::TailCall(boxed) => {
266                let (target, args) = *boxed;
267                self.resume_tail_call(target, args, 0, Vec::new(), conts)
268            }
269        }
270    }
271
272    fn step_body(
273        &mut self,
274        body: Rc<FnBody>,
275        idx: usize,
276        local_slots: Option<Rc<HashMap<String, u16>>>,
277        last: Value,
278        conts: &mut Vec<EvalCont>,
279    ) -> EvalState {
280        let stmts = body.stmts();
281        if idx >= stmts.len() {
282            return EvalState::Apply(Ok(last));
283        }
284
285        match stmts[idx].clone() {
286            Stmt::Binding(name, _, expr) => {
287                conts.push(EvalCont::BodyBinding {
288                    name,
289                    next_idx: idx + 1,
290                    body,
291                    local_slots,
292                });
293                EvalState::Expr(expr)
294            }
295            Stmt::Expr(expr) => {
296                conts.push(EvalCont::BodyExpr {
297                    next_idx: idx + 1,
298                    body,
299                    local_slots,
300                });
301                EvalState::Expr(expr)
302            }
303        }
304    }
305
306    fn apply_cont(
307        &mut self,
308        cont: EvalCont,
309        result: Result<Value, RuntimeError>,
310        conts: &mut Vec<EvalCont>,
311    ) -> EvalState {
312        match cont {
313            EvalCont::Attr(field) => match result {
314                Ok(obj_val) => EvalState::Apply(match obj_val {
315                    Value::Record { fields, .. } => fields
316                        .into_iter()
317                        .find(|(k, _)| k == &field)
318                        .map(|(_, value)| Ok(value))
319                        .unwrap_or_else(|| {
320                            Err(RuntimeError::Error(format!("Unknown field '{}'", field)))
321                        }),
322                    Value::Namespace { name, members } => {
323                        members.get(&field).cloned().ok_or_else(|| {
324                            RuntimeError::Error(format!("Unknown member '{}.{}'", name, field))
325                        })
326                    }
327                    _ => Err(RuntimeError::Error(format!(
328                        "Field access '{}' is not supported on this value",
329                        field
330                    ))),
331                }),
332                Err(err) => EvalState::Apply(Err(err)),
333            },
334            EvalCont::Call {
335                args,
336                mut idx,
337                mut fn_val,
338                mut arg_vals,
339            } => match result {
340                Ok(value) => {
341                    if fn_val.is_none() {
342                        fn_val = Some(value);
343                        if args.is_empty() {
344                            return self.dispatch_call(
345                                fn_val.expect("function value set before dispatch"),
346                                arg_vals,
347                                conts,
348                            );
349                        }
350                        conts.push(EvalCont::Call {
351                            args: args.clone(),
352                            idx,
353                            fn_val,
354                            arg_vals,
355                        });
356                        return EvalState::Expr(args[idx].clone());
357                    }
358
359                    arg_vals.push(value);
360                    idx += 1;
361                    if idx < args.len() {
362                        conts.push(EvalCont::Call {
363                            args: args.clone(),
364                            idx,
365                            fn_val,
366                            arg_vals,
367                        });
368                        EvalState::Expr(args[idx].clone())
369                    } else {
370                        self.dispatch_call(
371                            fn_val.expect("function value present when args are done"),
372                            arg_vals,
373                            conts,
374                        )
375                    }
376                }
377                Err(err) => EvalState::Apply(Err(err)),
378            },
379            EvalCont::BinOpLeft { op, right } => match result {
380                Ok(left) => {
381                    conts.push(EvalCont::BinOpRight { op, left });
382                    EvalState::Expr(right)
383                }
384                Err(err) => EvalState::Apply(Err(err)),
385            },
386            EvalCont::BinOpRight { op, left } => match result {
387                Ok(right) => EvalState::Apply(self.eval_binop(&op, left, right)),
388                Err(err) => EvalState::Apply(Err(err)),
389            },
390            EvalCont::Match { arms, line } => match result {
391                Ok(subject) => self.dispatch_match(subject, arms, line, conts),
392                Err(err) => EvalState::Apply(Err(err)),
393            },
394            EvalCont::Constructor(name) => match result {
395                Ok(value) => EvalState::Apply(match name.as_str() {
396                    "Ok" => Ok(Value::Ok(Box::new(value))),
397                    "Err" => Ok(Value::Err(Box::new(value))),
398                    "Some" => Ok(Value::Some(Box::new(value))),
399                    "None" => Err(RuntimeError::Error(
400                        "Constructor 'None' does not take an argument".to_string(),
401                    )),
402                    _ => Err(RuntimeError::Error(format!(
403                        "Unknown constructor: {}",
404                        name
405                    ))),
406                }),
407                Err(err) => EvalState::Apply(Err(err)),
408            },
409            EvalCont::ErrorProp => match result {
410                Ok(value) => EvalState::Apply(match value {
411                    Value::Ok(inner) => Ok(*inner),
412                    Value::Err(err) => Err(RuntimeError::ErrProp(err)),
413                    _ => Err(RuntimeError::Error(
414                        "Operator '?' can only be applied to Result".to_string(),
415                    )),
416                }),
417                Err(err) => EvalState::Apply(Err(err)),
418            },
419            EvalCont::InterpolatedStr {
420                parts,
421                idx,
422                result: mut text,
423            } => match result {
424                Ok(value) => {
425                    text.push_str(&aver_repr(&value));
426                    self.resume_interpolated_str(parts, idx, text, conts)
427                }
428                Err(err) => EvalState::Apply(Err(err)),
429            },
430            EvalCont::List {
431                items,
432                idx,
433                mut values,
434            } => match result {
435                Ok(value) => {
436                    values.push(value);
437                    self.resume_list(items, idx, values, conts)
438                }
439                Err(err) => EvalState::Apply(Err(err)),
440            },
441            EvalCont::Tuple {
442                items,
443                idx,
444                mut values,
445            } => match result {
446                Ok(value) => {
447                    values.push(value);
448                    self.resume_tuple(items, idx, values, conts)
449                }
450                Err(err) => EvalState::Apply(Err(err)),
451            },
452            EvalCont::MapKey { entries, idx, map } => match result {
453                Ok(key) => {
454                    if !Self::is_hashable_map_key(&key) {
455                        return EvalState::Apply(Err(RuntimeError::Error(
456                            "Map literal key must be Int, Float, String, or Bool".to_string(),
457                        )));
458                    }
459                    conts.push(EvalCont::MapValue {
460                        entries: entries.clone(),
461                        idx,
462                        map,
463                        key,
464                    });
465                    EvalState::Expr(entries[idx].1.clone())
466                }
467                Err(err) => EvalState::Apply(Err(err)),
468            },
469            EvalCont::MapValue {
470                entries,
471                idx,
472                mut map,
473                key,
474            } => match result {
475                Ok(value) => {
476                    map.insert(key, value);
477                    self.resume_map(entries, idx + 1, map, conts)
478                }
479                Err(err) => EvalState::Apply(Err(err)),
480            },
481            EvalCont::RecordCreate {
482                type_name,
483                fields,
484                idx,
485                mut seen,
486                mut values,
487            } => match result {
488                Ok(value) => {
489                    let field_name = fields[idx].0.clone();
490                    if !seen.insert(field_name.clone()) {
491                        return EvalState::Apply(Err(RuntimeError::Error(format!(
492                            "Record '{}' field '{}' provided more than once",
493                            type_name, field_name
494                        ))));
495                    }
496                    values.push((field_name, value));
497                    self.resume_record_create(type_name, fields, idx + 1, seen, values, conts)
498                }
499                Err(err) => EvalState::Apply(Err(err)),
500            },
501            EvalCont::RecordUpdateBase { type_name, updates } => match result {
502                Ok(base_val) => match base_val {
503                    Value::Record {
504                        type_name: base_type,
505                        fields,
506                    } => {
507                        if base_type != type_name {
508                            return EvalState::Apply(Err(RuntimeError::Error(format!(
509                                "{}.update: base is a {} record, expected {}",
510                                type_name, base_type, type_name
511                            ))));
512                        }
513                        self.resume_record_update(
514                            RecordUpdateProgress {
515                                type_name,
516                                base_type,
517                                base_fields: fields,
518                                updates,
519                                idx: 0,
520                                update_vals: Vec::new(),
521                            },
522                            conts,
523                        )
524                    }
525                    _ => EvalState::Apply(Err(RuntimeError::Error(format!(
526                        "{}.update: base must be a {} record",
527                        type_name, type_name
528                    )))),
529                },
530                Err(err) => EvalState::Apply(Err(err)),
531            },
532            EvalCont::RecordUpdateField(mut progress) => match result {
533                Ok(value) => {
534                    progress
535                        .update_vals
536                        .push((progress.updates[progress.idx].0.clone(), value));
537                    progress.idx += 1;
538                    self.resume_record_update(progress, conts)
539                }
540                Err(err) => EvalState::Apply(Err(err)),
541            },
542            EvalCont::TailCallArgs {
543                target,
544                args,
545                idx,
546                mut values,
547            } => match result {
548                Ok(value) => {
549                    values.push(value);
550                    self.resume_tail_call(target, args, idx + 1, values, conts)
551                }
552                Err(err) => EvalState::Apply(Err(err)),
553            },
554            EvalCont::BodyBinding {
555                name,
556                next_idx,
557                body,
558                local_slots,
559            } => match result {
560                Ok(value) => {
561                    if let Some(local_slots) = local_slots.as_ref()
562                        && let Some(&slot) = local_slots.get(&name)
563                    {
564                        self.define_slot(slot, value);
565                    } else {
566                        self.define(name, value);
567                    }
568                    EvalState::Body {
569                        body,
570                        idx: next_idx,
571                        local_slots,
572                        last: Value::Unit,
573                    }
574                }
575                Err(err) => EvalState::Apply(Err(err)),
576            },
577            EvalCont::BodyExpr {
578                next_idx,
579                body,
580                local_slots,
581            } => match result {
582                Ok(value) => EvalState::Body {
583                    body,
584                    idx: next_idx,
585                    local_slots,
586                    last: value,
587                },
588                Err(err) => EvalState::Apply(Err(err)),
589            },
590            EvalCont::MatchScope => {
591                self.pop_env();
592                EvalState::Apply(result)
593            }
594            EvalCont::FunctionReturn(frame) => self.finish_function_call(frame, result, conts),
595        }
596    }
597
598    fn dispatch_match(
599        &mut self,
600        subject: Value,
601        arms: Vec<MatchArm>,
602        line: usize,
603        conts: &mut Vec<EvalCont>,
604    ) -> EvalState {
605        let arm_count = arms.len();
606        for (arm_idx, arm) in arms.into_iter().enumerate() {
607            if let Some(bindings) = self.match_pattern(&arm.pattern, &subject) {
608                self.note_verify_match_arm(line, arm_count, arm_idx);
609                if let Some(local_slots) = self.active_local_slots.clone() {
610                    let all_slotted = bindings.keys().all(|name| local_slots.contains_key(name));
611                    if all_slotted {
612                        for (name, value) in bindings {
613                            if let Some(&slot) = local_slots.get(&name) {
614                                self.define_slot(slot, value);
615                            }
616                        }
617                        return EvalState::Expr(*arm.body);
618                    }
619                }
620
621                let rc_scope = bindings
622                    .into_iter()
623                    .map(|(k, v)| (k, Rc::new(v)))
624                    .collect::<HashMap<_, _>>();
625                self.push_env(EnvFrame::Owned(rc_scope));
626                conts.push(EvalCont::MatchScope);
627                return EvalState::Expr(*arm.body);
628            }
629        }
630
631        EvalState::Apply(Err(RuntimeError::Error(format!(
632            "No match found for value {}",
633            aver_repr(&subject)
634        ))))
635    }
636
637    fn dispatch_call(
638        &mut self,
639        fn_val: Value,
640        args: Vec<Value>,
641        conts: &mut Vec<EvalCont>,
642    ) -> EvalState {
643        match self.start_call(fn_val, args) {
644            Ok(CallDispatch::Immediate(result)) => EvalState::Apply(result),
645            Ok(CallDispatch::EnterFunction { frame, state }) => {
646                conts.push(EvalCont::FunctionReturn(*frame));
647                state
648            }
649            Err(err) => EvalState::Apply(Err(err)),
650        }
651    }
652
653    fn start_call(
654        &mut self,
655        fn_val: Value,
656        args: Vec<Value>,
657    ) -> Result<CallDispatch, RuntimeError> {
658        match &fn_val {
659            Value::Builtin(name) => {
660                self.ensure_effects_allowed(name, Self::builtin_effects(name).iter().copied())?;
661                Ok(CallDispatch::Immediate(self.call_builtin(name, &args)))
662            }
663            Value::Fn {
664                name,
665                params,
666                effects,
667                body,
668                resolution,
669                memo_eligible,
670                home_globals,
671                ..
672            } => {
673                if args.len() != params.len() {
674                    return Err(RuntimeError::Error(format!(
675                        "Function '{}' expects {} arguments, got {}",
676                        name,
677                        params.len(),
678                        args.len()
679                    )));
680                }
681                self.ensure_effects_allowed(name, effects.iter().map(String::as_str))?;
682
683                let memo_key = if *memo_eligible {
684                    let key = hash_memo_args(&args);
685                    if let Some(cached) = self
686                        .memo_cache
687                        .entry(name.clone())
688                        .or_default()
689                        .get(key, &args)
690                    {
691                        return Ok(CallDispatch::Immediate(Ok(cached)));
692                    }
693                    Some((key, args.clone()))
694                } else {
695                    None
696                };
697
698                self.call_stack.push(CallFrame {
699                    name: name.clone(),
700                    effects: effects.clone(),
701                });
702
703                let prev_local_slots = self.active_local_slots.take();
704                let saved_frames: Vec<EnvFrame> = self.env.drain(1..).collect();
705                let prev_global = if let Some(home) = home_globals {
706                    let global = self
707                        .env
708                        .first_mut()
709                        .ok_or_else(|| RuntimeError::Error("No global scope".to_string()))?;
710                    Some(std::mem::replace(global, EnvFrame::Shared(Rc::clone(home))))
711                } else {
712                    None
713                };
714
715                let active = ActiveFunction {
716                    name: name.clone(),
717                    params: params.clone(),
718                    body: Rc::clone(body),
719                    resolution: resolution.clone(),
720                };
721                let frame = FunctionFrame {
722                    active,
723                    prev_local_slots,
724                    saved_frames,
725                    prev_global,
726                    memo_key,
727                };
728                let state = self.enter_function_body(&frame.active, args);
729                Ok(CallDispatch::EnterFunction {
730                    frame: Box::new(frame),
731                    state,
732                })
733            }
734            _ => Err(RuntimeError::Error(format!(
735                "Cannot call value: {:?}",
736                fn_val
737            ))),
738        }
739    }
740
741    fn enter_function_body(&mut self, active: &ActiveFunction, args: Vec<Value>) -> EvalState {
742        if let Some(resolution) = &active.resolution {
743            let local_slots = Rc::new(resolution.local_slots.clone());
744            let mut slots = Self::empty_slots(resolution.local_count);
745            for ((param_name, _), arg_val) in active.params.iter().zip(args.into_iter()) {
746                if let Some(&slot) = resolution.local_slots.get(param_name) {
747                    slots[slot as usize] = Rc::new(arg_val);
748                }
749            }
750            self.active_local_slots = Some(resolution.local_slots.clone());
751            self.push_env(EnvFrame::Slots(slots));
752            EvalState::Body {
753                body: Rc::clone(&active.body),
754                idx: 0,
755                local_slots: Some(local_slots),
756                last: Value::Unit,
757            }
758        } else {
759            let mut params_scope = HashMap::new();
760            for ((param_name, _), arg_val) in active.params.iter().zip(args.into_iter()) {
761                params_scope.insert(param_name.clone(), Rc::new(arg_val));
762            }
763            self.push_env(EnvFrame::Owned(params_scope));
764            EvalState::Body {
765                body: Rc::clone(&active.body),
766                idx: 0,
767                local_slots: None,
768                last: Value::Unit,
769            }
770        }
771    }
772
773    fn finish_function_call(
774        &mut self,
775        mut frame: FunctionFrame,
776        result: Result<Value, RuntimeError>,
777        conts: &mut Vec<EvalCont>,
778    ) -> EvalState {
779        self.pop_env();
780
781        match result {
782            Err(RuntimeError::TailCall(boxed)) => {
783                let (target, args) = *boxed;
784                let next_active = if target == frame.active.name {
785                    frame.active.clone()
786                } else {
787                    match self.lookup(&target) {
788                        Ok(Value::Fn {
789                            name,
790                            params,
791                            effects,
792                            body,
793                            resolution,
794                            home_globals: _,
795                            ..
796                        }) => {
797                            if let Some(call_frame) = self.call_stack.last_mut() {
798                                call_frame.name = name.clone();
799                                call_frame.effects = effects.clone();
800                            }
801                            ActiveFunction {
802                                name,
803                                params,
804                                body,
805                                resolution,
806                            }
807                        }
808                        Ok(other) => {
809                            return EvalState::Apply(Err(RuntimeError::Error(format!(
810                                "TCO target '{}' is not a function: {:?}",
811                                target, other
812                            ))));
813                        }
814                        Err(err) => return EvalState::Apply(Err(err)),
815                    }
816                };
817
818                frame.active = next_active;
819                let state = self.enter_function_body(&frame.active, args);
820                conts.push(EvalCont::FunctionReturn(frame));
821                state
822            }
823            other => {
824                self.active_local_slots = frame.prev_local_slots;
825                if let Some(prev) = frame.prev_global
826                    && let Some(global) = self.env.first_mut()
827                {
828                    *global = prev;
829                }
830                self.env.truncate(1);
831                self.env.extend(frame.saved_frames);
832                self.call_stack.pop();
833
834                let final_result = match other {
835                    Ok(value) => Ok(value),
836                    Err(RuntimeError::ErrProp(err)) => Ok(Value::Err(err)),
837                    Err(err) => Err(err),
838                };
839
840                if let (Some((key, memo_args)), Ok(value)) = (frame.memo_key, &final_result) {
841                    let cache = self.memo_cache.entry(frame.active.name).or_default();
842                    cache.insert(key, memo_args, value.clone(), MEMO_CACHE_CAP_PER_FN);
843                }
844
845                EvalState::Apply(final_result)
846            }
847        }
848    }
849
850    fn resume_interpolated_str(
851        &mut self,
852        parts: Vec<StrPart>,
853        mut idx: usize,
854        mut result: String,
855        conts: &mut Vec<EvalCont>,
856    ) -> EvalState {
857        while idx < parts.len() {
858            match parts[idx].clone() {
859                StrPart::Literal(text) => {
860                    result.push_str(&text);
861                    idx += 1;
862                }
863                StrPart::Parsed(expr) => {
864                    conts.push(EvalCont::InterpolatedStr {
865                        parts,
866                        idx: idx + 1,
867                        result,
868                    });
869                    return EvalState::Expr(*expr);
870                }
871            }
872        }
873        EvalState::Apply(Ok(Value::Str(result)))
874    }
875
876    fn resume_list(
877        &mut self,
878        items: Vec<Expr>,
879        idx: usize,
880        values: Vec<Value>,
881        conts: &mut Vec<EvalCont>,
882    ) -> EvalState {
883        if idx >= items.len() {
884            return EvalState::Apply(Ok(list_from_vec(values)));
885        }
886
887        conts.push(EvalCont::List {
888            items: items.clone(),
889            idx: idx + 1,
890            values,
891        });
892        EvalState::Expr(items[idx].clone())
893    }
894
895    fn resume_tuple(
896        &mut self,
897        items: Vec<Expr>,
898        idx: usize,
899        values: Vec<Value>,
900        conts: &mut Vec<EvalCont>,
901    ) -> EvalState {
902        if idx >= items.len() {
903            return EvalState::Apply(Ok(Value::Tuple(values)));
904        }
905
906        conts.push(EvalCont::Tuple {
907            items: items.clone(),
908            idx: idx + 1,
909            values,
910        });
911        EvalState::Expr(items[idx].clone())
912    }
913
914    fn resume_map(
915        &mut self,
916        entries: Vec<(Expr, Expr)>,
917        idx: usize,
918        map: HashMap<Value, Value>,
919        conts: &mut Vec<EvalCont>,
920    ) -> EvalState {
921        if idx >= entries.len() {
922            return EvalState::Apply(Ok(Value::Map(map)));
923        }
924
925        conts.push(EvalCont::MapKey {
926            entries: entries.clone(),
927            idx,
928            map,
929        });
930        EvalState::Expr(entries[idx].0.clone())
931    }
932
933    fn resume_record_create(
934        &mut self,
935        type_name: String,
936        fields: Vec<(String, Expr)>,
937        idx: usize,
938        seen: HashSet<String>,
939        values: Vec<(String, Value)>,
940        conts: &mut Vec<EvalCont>,
941    ) -> EvalState {
942        if idx >= fields.len() {
943            return EvalState::Apply(self.build_record_create_value(&type_name, values));
944        }
945
946        conts.push(EvalCont::RecordCreate {
947            type_name,
948            fields: fields.clone(),
949            idx,
950            seen,
951            values,
952        });
953        EvalState::Expr(fields[idx].1.clone())
954    }
955
956    fn resume_record_update(
957        &mut self,
958        progress: RecordUpdateProgress,
959        conts: &mut Vec<EvalCont>,
960    ) -> EvalState {
961        if progress.idx >= progress.updates.len() {
962            return EvalState::Apply(self.build_record_update_value(
963                &progress.type_name,
964                progress.base_type,
965                progress.base_fields,
966                progress.update_vals,
967            ));
968        }
969
970        let next_expr = progress.updates[progress.idx].1.clone();
971        conts.push(EvalCont::RecordUpdateField(progress));
972        EvalState::Expr(next_expr)
973    }
974
975    fn resume_tail_call(
976        &mut self,
977        target: String,
978        args: Vec<Expr>,
979        idx: usize,
980        values: Vec<Value>,
981        conts: &mut Vec<EvalCont>,
982    ) -> EvalState {
983        if idx >= args.len() {
984            return EvalState::Apply(Err(RuntimeError::TailCall(Box::new((target, values)))));
985        }
986
987        conts.push(EvalCont::TailCallArgs {
988            target,
989            args: args.clone(),
990            idx,
991            values,
992        });
993        EvalState::Expr(args[idx].clone())
994    }
995
996    fn build_record_create_value(
997        &self,
998        type_name: &str,
999        field_vals: Vec<(String, Value)>,
1000    ) -> Result<Value, RuntimeError> {
1001        if let Some(schema) = self.record_schemas.get(type_name) {
1002            let mut by_name = HashMap::with_capacity(field_vals.len());
1003            for (name, value) in field_vals {
1004                if by_name.insert(name.clone(), value).is_some() {
1005                    return Err(RuntimeError::Error(format!(
1006                        "Record '{}' field '{}' provided more than once",
1007                        type_name, name
1008                    )));
1009                }
1010            }
1011
1012            for provided in by_name.keys() {
1013                if !schema.iter().any(|field| field == provided) {
1014                    return Err(RuntimeError::Error(format!(
1015                        "Record '{}' has no field '{}'",
1016                        type_name, provided
1017                    )));
1018                }
1019            }
1020
1021            let mut ordered = Vec::with_capacity(schema.len());
1022            for required in schema {
1023                let value = by_name.remove(required).ok_or_else(|| {
1024                    RuntimeError::Error(format!(
1025                        "Record '{}' missing required field '{}'",
1026                        type_name, required
1027                    ))
1028                })?;
1029                ordered.push((required.clone(), value));
1030            }
1031
1032            return Ok(Value::Record {
1033                type_name: type_name.to_string(),
1034                fields: ordered,
1035            });
1036        }
1037
1038        Ok(Value::Record {
1039            type_name: type_name.to_string(),
1040            fields: field_vals,
1041        })
1042    }
1043
1044    fn build_record_update_value(
1045        &self,
1046        type_name: &str,
1047        base_type: String,
1048        mut base_fields: Vec<(String, Value)>,
1049        update_vals: Vec<(String, Value)>,
1050    ) -> Result<Value, RuntimeError> {
1051        if base_type != type_name {
1052            return Err(RuntimeError::Error(format!(
1053                "{}.update: base is a {} record, expected {}",
1054                type_name, base_type, type_name
1055            )));
1056        }
1057
1058        if let Some(schema) = self.record_schemas.get(type_name) {
1059            for (field_name, _) in &update_vals {
1060                if !schema.iter().any(|field| field == field_name) {
1061                    return Err(RuntimeError::Error(format!(
1062                        "Record '{}' has no field '{}'",
1063                        type_name, field_name
1064                    )));
1065                }
1066            }
1067        }
1068
1069        for (update_name, update_val) in update_vals {
1070            if let Some(field) = base_fields
1071                .iter_mut()
1072                .find(|(name, _)| name == &update_name)
1073            {
1074                field.1 = update_val;
1075            } else {
1076                return Err(RuntimeError::Error(format!(
1077                    "Record '{}' has no field '{}'",
1078                    type_name, update_name
1079                )));
1080            }
1081        }
1082
1083        Ok(Value::Record {
1084            type_name: type_name.to_string(),
1085            fields: base_fields,
1086        })
1087    }
1088
1089    fn is_hashable_map_key(value: &Value) -> bool {
1090        matches!(
1091            value,
1092            Value::Int(_) | Value::Float(_) | Value::Str(_) | Value::Bool(_)
1093        )
1094    }
1095
1096    pub(super) fn eval_literal(&self, lit: &Literal) -> Value {
1097        match lit {
1098            Literal::Int(i) => Value::Int(*i),
1099            Literal::Float(f) => Value::Float(*f),
1100            Literal::Str(s) => Value::Str(s.clone()),
1101            Literal::Bool(b) => Value::Bool(*b),
1102            Literal::Unit => Value::Unit,
1103        }
1104    }
1105
1106    pub(super) fn call_value(
1107        &mut self,
1108        fn_val: Value,
1109        args: Vec<Value>,
1110    ) -> Result<Value, RuntimeError> {
1111        match self.start_call(fn_val, args)? {
1112            CallDispatch::Immediate(result) => result,
1113            CallDispatch::EnterFunction { frame, state } => {
1114                self.eval_loop(state, vec![EvalCont::FunctionReturn(*frame)])
1115            }
1116        }
1117    }
1118}