Skip to main content

aver/interpreter/
eval.rs

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