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}