Skip to main content

yulang_vm/vm/
control.rs

1use super::*;
2use num_bigint::BigInt;
3use serde::{Deserialize, Serialize};
4use std::cmp::Ordering;
5use std::collections::{HashMap, VecDeque};
6use std::io;
7use std::path::Path;
8use yulang_runtime_ir::FinalizedRecordSpreadPattern as RecordSpreadPattern;
9
10const CONTROL_VM_ARTIFACT_MAGIC: &[u8; 8] = b"YLCVMIR\0";
11pub const CONTROL_VM_ARTIFACT_VERSION: u32 = 11;
12const CONTROL_VM_ARTIFACT_HEADER_LEN: usize = CONTROL_VM_ARTIFACT_MAGIC.len() + 4;
13
14#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
15struct ExprId(usize);
16
17#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
18struct ControlSymbolId(usize);
19
20#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
21struct ControlLocalId(usize);
22
23#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
24struct ControlNameId(usize);
25
26#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
27struct ControlLitId(usize);
28
29#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
30struct ControlTypeId(usize);
31
32#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
33struct ControlExprListId(usize);
34
35#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
36struct ControlMatchArmsId(usize);
37
38#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
39struct ControlHandleArmsId(usize);
40
41#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
42struct ControlBlockId(usize);
43
44#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
45struct ControlRecordId(usize);
46
47#[derive(Serialize, Deserialize)]
48pub struct ControlVmModule {
49    module: ControlModule,
50}
51
52impl ControlVmModule {
53    pub fn eval_root_expr(&self, index: usize) -> Result<VmResult, VmError> {
54        let expr = self
55            .module
56            .root_exprs
57            .get(index)
58            .copied()
59            .ok_or(VmError::MissingRootExpr(index))?;
60        ControlInterpreter::new(&self.module).eval_root_expr(expr)
61    }
62
63    pub fn eval_root_expr_profiled(&self, index: usize) -> Result<(VmResult, VmProfile), VmError> {
64        let expr = self
65            .module
66            .root_exprs
67            .get(index)
68            .copied()
69            .ok_or(VmError::MissingRootExpr(index))?;
70        let mut interpreter = ControlInterpreter::new(&self.module);
71        let result = interpreter.eval_root_expr(expr)?;
72        Ok((result, interpreter.profile()))
73    }
74
75    pub fn eval_root_expr_with_basic_host_profiled(
76        &self,
77        index: usize,
78        stdout: &mut String,
79    ) -> Result<(VmResult, VmProfile), VmError> {
80        let expr = self
81            .module
82            .root_exprs
83            .get(index)
84            .copied()
85            .ok_or(VmError::MissingRootExpr(index))?;
86        let mut interpreter = ControlInterpreter::new(&self.module);
87        let mut host = crate::host::BasicHost::new(stdout);
88        let mut pending_undet: VecDeque<ControlContinuation> = VecDeque::new();
89        let mut last_undet_value = None;
90        let mut result = interpreter.eval_root_control_result(expr)?;
91        loop {
92            match result {
93                ControlResult::Value(value) => {
94                    if let Some(request) = pending_undet.pop_front() {
95                        last_undet_value = Some(value);
96                        let resumed = interpreter.resume(request, ControlValue::Bool(false))?;
97                        result = interpreter.normalize_root_result(resumed)?;
98                        continue;
99                    }
100                    return Ok((
101                        VmResult::Value(export_value(&value, Some(&self.module))?),
102                        interpreter.profile(),
103                    ));
104                }
105                ControlResult::Request(request) => {
106                    match interpreter.undet_request_operation(&request) {
107                        Some(crate::host::UndetOperation::Branch) => {
108                            pending_undet
109                                .push_back(interpreter.clone_continuation(&request.continuation));
110                            let resumed = interpreter
111                                .resume(request.continuation, ControlValue::Bool(true))?;
112                            result = interpreter.normalize_root_result(resumed)?;
113                            continue;
114                        }
115                        Some(crate::host::UndetOperation::Reject) => {
116                            let Some(continuation) = pending_undet.pop_front() else {
117                                let value = last_undet_value.unwrap_or(ControlValue::Unit);
118                                return Ok((
119                                    VmResult::Value(export_value(&value, Some(&self.module))?),
120                                    interpreter.profile(),
121                                ));
122                            };
123                            let resumed =
124                                interpreter.resume(continuation, ControlValue::Bool(false))?;
125                            result = interpreter.normalize_root_result(resumed)?;
126                            continue;
127                        }
128                        None => {}
129                    }
130                    let exported = interpreter.export_request(&request)?;
131                    let Some(value) = host.handle_request(&exported) else {
132                        return Ok((VmResult::Request(exported), interpreter.profile()));
133                    };
134                    let value = import_value(&value)?;
135                    let resumed = interpreter.resume(request.continuation, value)?;
136                    result = interpreter.normalize_root_result(resumed)?;
137                }
138            }
139        }
140    }
141
142    pub fn root_count(&self) -> usize {
143        self.module.root_exprs.len()
144    }
145
146    pub fn write_json_file(&self, path: &Path) -> io::Result<()> {
147        let file = std::fs::File::create(path)?;
148        serde_json::to_writer(file, self).map_err(io::Error::other)
149    }
150
151    pub fn read_json_file(path: &Path) -> io::Result<Self> {
152        let file = std::fs::File::open(path)?;
153        let mut module: Self = serde_json::from_reader(file).map_err(io::Error::other)?;
154        module.module.rebuild_indexes();
155        Ok(module)
156    }
157
158    pub fn write_artifact_file(&self, path: &Path) -> io::Result<()> {
159        std::fs::write(path, self.to_artifact_bytes()?)
160    }
161
162    pub fn read_artifact_file(path: &Path) -> io::Result<Self> {
163        Self::from_artifact_bytes(&std::fs::read(path)?)
164    }
165
166    pub fn to_artifact_bytes(&self) -> io::Result<Vec<u8>> {
167        let payload = postcard::to_allocvec(self).map_err(io::Error::other)?;
168        let mut bytes = Vec::with_capacity(CONTROL_VM_ARTIFACT_HEADER_LEN + payload.len());
169        bytes.extend_from_slice(CONTROL_VM_ARTIFACT_MAGIC);
170        bytes.extend_from_slice(&CONTROL_VM_ARTIFACT_VERSION.to_le_bytes());
171        bytes.extend_from_slice(&payload);
172        Ok(bytes)
173    }
174
175    pub fn from_artifact_bytes(bytes: &[u8]) -> io::Result<Self> {
176        if bytes.len() < CONTROL_VM_ARTIFACT_HEADER_LEN {
177            return Err(io::Error::new(
178                io::ErrorKind::InvalidData,
179                "control VM artifact is shorter than the header",
180            ));
181        }
182        let (magic, rest) = bytes.split_at(CONTROL_VM_ARTIFACT_MAGIC.len());
183        if magic != CONTROL_VM_ARTIFACT_MAGIC {
184            return Err(io::Error::new(
185                io::ErrorKind::InvalidData,
186                "invalid control VM artifact magic",
187            ));
188        }
189        let (version, payload) = rest.split_at(4);
190        let version = u32::from_le_bytes(version.try_into().expect("version header length"));
191        if version != CONTROL_VM_ARTIFACT_VERSION {
192            return Err(io::Error::new(
193                io::ErrorKind::InvalidData,
194                format!(
195                    "unsupported control VM artifact version {version}; expected {CONTROL_VM_ARTIFACT_VERSION}"
196                ),
197            ));
198        }
199        let mut module: Self = postcard::from_bytes(payload).map_err(io::Error::other)?;
200        module.module.rebuild_indexes();
201        Ok(module)
202    }
203}
204
205pub fn compile_control_vm_module<M: IntoVmModule>(module: M) -> Result<ControlVmModule, VmError> {
206    let module = module.into_vm_module();
207    let effects = EffectPathResolver::collect(&module);
208    let module = erase_module(module, &effects)?;
209    Ok(ControlVmModule {
210        module: ControlCompiler::compile(module),
211    })
212}
213
214#[derive(Serialize, Deserialize)]
215struct ControlModule {
216    symbols: Vec<typed_ir::Path>,
217    names: Vec<typed_ir::Name>,
218    lits: Vec<typed_ir::Lit>,
219    types: Vec<typed_ir::Type>,
220    expr_lists: Vec<Vec<ExprId>>,
221    match_arms: Vec<Vec<ControlMatchArm>>,
222    handle_arms: Vec<Vec<ControlHandleArm>>,
223    blocks: Vec<ControlBlock>,
224    records: Vec<ControlRecord>,
225    exprs: Vec<ControlExpr>,
226    bindings: Vec<ControlBinding>,
227    #[serde(skip, default)]
228    symbol_by_path: HashMap<typed_ir::Path, ControlSymbolId>,
229    #[serde(skip, default)]
230    binding_by_symbol: Vec<Option<usize>>,
231    local_by_symbol: Vec<Option<ControlLocalId>>,
232    root_exprs: Vec<ExprId>,
233}
234
235impl ControlModule {
236    fn rebuild_indexes(&mut self) {
237        self.symbol_by_path = self
238            .symbols
239            .iter()
240            .cloned()
241            .enumerate()
242            .map(|(index, path)| (path, ControlSymbolId(index)))
243            .collect();
244        self.binding_by_symbol =
245            control_binding_index_by_symbol(&self.bindings, self.symbols.len());
246    }
247
248    fn symbol_path(&self, symbol: ControlSymbolId) -> &typed_ir::Path {
249        &self.symbols[symbol.0]
250    }
251
252    fn name(&self, name: ControlNameId) -> &typed_ir::Name {
253        &self.names[name.0]
254    }
255
256    fn lit(&self, lit: ControlLitId) -> &typed_ir::Lit {
257        &self.lits[lit.0]
258    }
259
260    fn ty(&self, ty: ControlTypeId) -> &typed_ir::Type {
261        &self.types[ty.0]
262    }
263
264    fn expr_list(&self, id: ControlExprListId) -> &[ExprId] {
265        &self.expr_lists[id.0]
266    }
267
268    fn match_arms(&self, id: ControlMatchArmsId) -> &[ControlMatchArm] {
269        &self.match_arms[id.0]
270    }
271
272    fn handle_arms(&self, id: ControlHandleArmsId) -> &[ControlHandleArm] {
273        &self.handle_arms[id.0]
274    }
275
276    fn block(&self, id: ControlBlockId) -> &ControlBlock {
277        &self.blocks[id.0]
278    }
279
280    fn record(&self, id: ControlRecordId) -> &ControlRecord {
281        &self.records[id.0]
282    }
283
284    fn local_for_symbol(&self, symbol: ControlSymbolId) -> Option<ControlLocalId> {
285        self.local_by_symbol.get(symbol.0).and_then(|local| *local)
286    }
287}
288
289fn control_binding_index_by_symbol(
290    bindings: &[ControlBinding],
291    symbol_count: usize,
292) -> Vec<Option<usize>> {
293    let mut index_by_symbol = vec![None; symbol_count];
294    for (index, binding) in bindings.iter().enumerate() {
295        index_by_symbol[binding.name.0] = Some(index);
296    }
297    index_by_symbol
298}
299
300#[derive(Serialize, Deserialize)]
301struct ControlBinding {
302    name: ControlSymbolId,
303    body: ExprId,
304}
305
306#[derive(Serialize, Deserialize)]
307struct ControlExpr {
308    kind: ControlExprKind,
309}
310
311#[derive(Clone, Copy, Serialize, Deserialize)]
312enum ControlExprKind {
313    Var(ControlSymbolId),
314    EffectOp(ControlSymbolId),
315    PrimitiveOp(typed_ir::PrimitiveOp),
316    Lit(ControlLitId),
317    Lambda {
318        param: ControlLocalId,
319        param_forces_thunk_arg: bool,
320        body: ExprId,
321        result_wraps_thunk: bool,
322    },
323    Apply {
324        callee: ExprId,
325        arg: ExprId,
326        delay_arg: bool,
327    },
328    If {
329        cond: ExprId,
330        then_branch: ExprId,
331        else_branch: ExprId,
332    },
333    Tuple(ControlExprListId),
334    Variant {
335        tag: ControlNameId,
336        value: Option<ExprId>,
337    },
338    Match {
339        scrutinee: ExprId,
340        arms: ControlMatchArmsId,
341    },
342    Block(ControlBlockId),
343    Handle {
344        body: ExprId,
345        arms: ControlHandleArmsId,
346        result_wraps_thunk: bool,
347    },
348    BindHere(ExprId),
349    Thunk(ExprId),
350    LocalPushId {
351        id: EffectIdVar,
352        body: ExprId,
353    },
354    PeekId,
355    FindId {
356        id: EffectIdRef,
357    },
358    AddId {
359        id: EffectIdRef,
360        allowed: ControlTypeId,
361        active: bool,
362        thunk: ExprId,
363    },
364    Coerce {
365        to: ControlTypeId,
366        expr: ExprId,
367    },
368    Pack(ExprId),
369    Select {
370        base: ExprId,
371        field: ControlNameId,
372    },
373    Record(ControlRecordId),
374}
375
376#[derive(Serialize, Deserialize)]
377struct ControlRecord {
378    fields: Vec<ControlRecordField>,
379    spread: Option<ControlRecordSpread>,
380}
381
382#[derive(Clone, Serialize, Deserialize)]
383struct ControlRecordField {
384    name: typed_ir::Name,
385    value: ExprId,
386}
387
388#[derive(Clone, Serialize, Deserialize)]
389enum ControlRecordSpread {
390    Head(ExprId),
391    Tail(ExprId),
392}
393
394#[derive(Clone, Serialize, Deserialize)]
395enum ControlPattern {
396    Wildcard,
397    Bind {
398        local: ControlLocalId,
399    },
400    Lit {
401        lit: typed_ir::Lit,
402    },
403    Tuple {
404        items: Vec<ControlPattern>,
405    },
406    List {
407        prefix: Vec<ControlPattern>,
408        spread: Option<Box<ControlPattern>>,
409        suffix: Vec<ControlPattern>,
410    },
411    Record {
412        fields: Vec<ControlRecordPatternField>,
413        spread: Option<ControlRecordSpreadPattern>,
414    },
415    Variant {
416        tag: typed_ir::Name,
417        value: Option<Box<ControlPattern>>,
418    },
419    Or {
420        left: Box<ControlPattern>,
421        right: Box<ControlPattern>,
422    },
423    As {
424        pattern: Box<ControlPattern>,
425        local: ControlLocalId,
426    },
427}
428
429#[derive(Clone, Serialize, Deserialize)]
430struct ControlRecordPatternField {
431    name: typed_ir::Name,
432    pattern: ControlPattern,
433    default: Option<ExprId>,
434}
435
436#[derive(Clone, Serialize, Deserialize)]
437enum ControlRecordSpreadPattern {
438    Head(Box<ControlPattern>),
439    Tail(Box<ControlPattern>),
440}
441
442#[derive(Clone, Serialize, Deserialize)]
443struct ControlMatchArm {
444    pattern: ControlPattern,
445    guard: Option<ExprId>,
446    body: ExprId,
447}
448
449#[derive(Clone, Serialize, Deserialize)]
450struct ControlHandleArm {
451    effect: ControlSymbolId,
452    payload: ControlPattern,
453    resume: Option<ControlLocalId>,
454    guard: Option<ExprId>,
455    body: ExprId,
456}
457
458#[derive(Clone, Serialize, Deserialize)]
459enum ControlStmt {
460    Let {
461        pattern: ControlPattern,
462        value: ExprId,
463    },
464    Expr(ExprId),
465    Module {
466        def: ControlLocalId,
467        body: ExprId,
468    },
469}
470
471#[derive(Serialize, Deserialize)]
472struct ControlBlock {
473    stmts: Vec<ControlStmt>,
474    tail: Option<ExprId>,
475}
476
477struct ControlCompiler {
478    symbols: Vec<typed_ir::Path>,
479    symbol_by_path: HashMap<typed_ir::Path, ControlSymbolId>,
480    names: Vec<typed_ir::Name>,
481    name_by_name: HashMap<typed_ir::Name, ControlNameId>,
482    lits: Vec<typed_ir::Lit>,
483    types: Vec<typed_ir::Type>,
484    expr_lists: Vec<Vec<ExprId>>,
485    match_arms: Vec<Vec<ControlMatchArm>>,
486    handle_arms: Vec<Vec<ControlHandleArm>>,
487    blocks: Vec<ControlBlock>,
488    records: Vec<ControlRecord>,
489    exprs: Vec<ControlExpr>,
490    local_by_symbol: Vec<Option<ControlLocalId>>,
491    local_count: usize,
492}
493
494impl ControlCompiler {
495    fn compile(module: Module) -> ControlModule {
496        let mut compiler = Self {
497            symbols: Vec::new(),
498            symbol_by_path: HashMap::new(),
499            names: Vec::new(),
500            name_by_name: HashMap::new(),
501            lits: Vec::new(),
502            types: Vec::new(),
503            expr_lists: Vec::new(),
504            match_arms: Vec::new(),
505            handle_arms: Vec::new(),
506            blocks: Vec::new(),
507            records: Vec::new(),
508            exprs: Vec::new(),
509            local_by_symbol: Vec::new(),
510            local_count: 0,
511        };
512        let bindings = module
513            .bindings
514            .into_iter()
515            .map(|binding| ControlBinding {
516                name: compiler.intern_path(binding.name),
517                body: compiler.expr(binding.body),
518            })
519            .collect::<Vec<_>>();
520        let root_exprs = module
521            .root_exprs
522            .into_iter()
523            .map(|expr| compiler.expr(expr))
524            .collect();
525        let binding_by_symbol = control_binding_index_by_symbol(&bindings, compiler.symbols.len());
526        ControlModule {
527            symbols: compiler.symbols,
528            names: compiler.names,
529            lits: compiler.lits,
530            types: compiler.types,
531            expr_lists: compiler.expr_lists,
532            match_arms: compiler.match_arms,
533            handle_arms: compiler.handle_arms,
534            blocks: compiler.blocks,
535            records: compiler.records,
536            exprs: compiler.exprs,
537            bindings,
538            symbol_by_path: compiler.symbol_by_path,
539            binding_by_symbol,
540            local_by_symbol: compiler.local_by_symbol,
541            root_exprs,
542        }
543    }
544
545    fn intern_path(&mut self, path: typed_ir::Path) -> ControlSymbolId {
546        if let Some(symbol) = self.symbol_by_path.get(&path).copied() {
547            return symbol;
548        }
549        let symbol = ControlSymbolId(self.symbols.len());
550        self.symbols.push(path.clone());
551        self.local_by_symbol.push(None);
552        self.symbol_by_path.insert(path, symbol);
553        symbol
554    }
555
556    fn intern_local_path(&mut self, path: typed_ir::Path) -> ControlLocalId {
557        let symbol = self.intern_path(path);
558        if let Some(local) = self.local_by_symbol[symbol.0] {
559            return local;
560        }
561        let local = ControlLocalId(self.local_count);
562        self.local_count += 1;
563        self.local_by_symbol[symbol.0] = Some(local);
564        local
565    }
566
567    fn intern_local_name_path(&mut self, name: &typed_ir::Name) -> ControlLocalId {
568        self.intern_local_path(typed_ir::Path::from_name(name.clone()))
569    }
570
571    fn intern_name(&mut self, name: typed_ir::Name) -> ControlNameId {
572        if let Some(id) = self.name_by_name.get(&name).copied() {
573            return id;
574        }
575        let id = ControlNameId(self.names.len());
576        self.names.push(name.clone());
577        self.name_by_name.insert(name, id);
578        id
579    }
580
581    fn push_lit(&mut self, lit: typed_ir::Lit) -> ControlLitId {
582        let id = ControlLitId(self.lits.len());
583        self.lits.push(lit);
584        id
585    }
586
587    fn push_type(&mut self, ty: typed_ir::Type) -> ControlTypeId {
588        let id = ControlTypeId(self.types.len());
589        self.types.push(ty);
590        id
591    }
592
593    fn push_expr_list(&mut self, exprs: Vec<ExprId>) -> ControlExprListId {
594        let id = ControlExprListId(self.expr_lists.len());
595        self.expr_lists.push(exprs);
596        id
597    }
598
599    fn push_match_arms(&mut self, arms: Vec<ControlMatchArm>) -> ControlMatchArmsId {
600        let id = ControlMatchArmsId(self.match_arms.len());
601        self.match_arms.push(arms);
602        id
603    }
604
605    fn push_handle_arms(&mut self, arms: Vec<ControlHandleArm>) -> ControlHandleArmsId {
606        let id = ControlHandleArmsId(self.handle_arms.len());
607        self.handle_arms.push(arms);
608        id
609    }
610
611    fn push_block(&mut self, block: ControlBlock) -> ControlBlockId {
612        let id = ControlBlockId(self.blocks.len());
613        self.blocks.push(block);
614        id
615    }
616
617    fn push_record(&mut self, record: ControlRecord) -> ControlRecordId {
618        let id = ControlRecordId(self.records.len());
619        self.records.push(record);
620        id
621    }
622
623    fn pattern(&mut self, pattern: Pattern) -> ControlPattern {
624        match pattern {
625            Pattern::Wildcard { .. } => ControlPattern::Wildcard,
626            Pattern::Bind { name, .. } => {
627                let local = self.intern_local_name_path(&name);
628                ControlPattern::Bind { local }
629            }
630            Pattern::Lit { lit, .. } => ControlPattern::Lit { lit },
631            Pattern::Tuple { items, .. } => ControlPattern::Tuple {
632                items: items.into_iter().map(|item| self.pattern(item)).collect(),
633            },
634            Pattern::List {
635                prefix,
636                spread,
637                suffix,
638                ..
639            } => ControlPattern::List {
640                prefix: prefix.into_iter().map(|item| self.pattern(item)).collect(),
641                spread: spread.map(|item| Box::new(self.pattern(*item))),
642                suffix: suffix.into_iter().map(|item| self.pattern(item)).collect(),
643            },
644            Pattern::Record { fields, spread, .. } => ControlPattern::Record {
645                fields: fields
646                    .into_iter()
647                    .map(|field| ControlRecordPatternField {
648                        name: field.name,
649                        pattern: self.pattern(field.pattern),
650                        default: field.default.map(|default| self.expr(default)),
651                    })
652                    .collect(),
653                spread: spread.map(|spread| match spread {
654                    RecordSpreadPattern::Head(pattern) => {
655                        ControlRecordSpreadPattern::Head(Box::new(self.pattern(*pattern)))
656                    }
657                    RecordSpreadPattern::Tail(pattern) => {
658                        ControlRecordSpreadPattern::Tail(Box::new(self.pattern(*pattern)))
659                    }
660                }),
661            },
662            Pattern::Variant { tag, value, .. } => ControlPattern::Variant {
663                tag,
664                value: value.map(|value| Box::new(self.pattern(*value))),
665            },
666            Pattern::Or { left, right, .. } => ControlPattern::Or {
667                left: Box::new(self.pattern(*left)),
668                right: Box::new(self.pattern(*right)),
669            },
670            Pattern::As { pattern, name, .. } => {
671                let local = self.intern_local_name_path(&name);
672                ControlPattern::As {
673                    pattern: Box::new(self.pattern(*pattern)),
674                    local,
675                }
676            }
677        }
678    }
679
680    fn expr(&mut self, expr: Expr) -> ExprId {
681        let Expr { ty, kind } = expr;
682        let kind = match kind {
683            ExprKind::Var(path) => ControlExprKind::Var(self.intern_path(path)),
684            ExprKind::EffectOp(path) => ControlExprKind::EffectOp(self.intern_path(path)),
685            ExprKind::PrimitiveOp(op) => ControlExprKind::PrimitiveOp(op),
686            ExprKind::Lit(lit) => ControlExprKind::Lit(self.push_lit(lit)),
687            ExprKind::Lambda {
688                param,
689                param_effect_annotation,
690                body,
691                ..
692            } => {
693                let (param_forces_thunk_arg, result_wraps_thunk) =
694                    control_lambda_shape(&ty, &body.ty, param_effect_annotation.as_ref());
695                let param = self.intern_local_name_path(&param);
696                ControlExprKind::Lambda {
697                    param,
698                    param_forces_thunk_arg,
699                    body: self.expr(*body),
700                    result_wraps_thunk,
701                }
702            }
703            ExprKind::Apply { callee, arg, .. } => {
704                let delay_arg = expects_thunk_arg(&callee.ty);
705                ControlExprKind::Apply {
706                    callee: self.expr(*callee),
707                    arg: self.expr(*arg),
708                    delay_arg,
709                }
710            }
711            ExprKind::If {
712                cond,
713                then_branch,
714                else_branch,
715                ..
716            } => ControlExprKind::If {
717                cond: self.expr(*cond),
718                then_branch: self.expr(*then_branch),
719                else_branch: self.expr(*else_branch),
720            },
721            ExprKind::Tuple(items) => {
722                let items = items.into_iter().map(|item| self.expr(item)).collect();
723                ControlExprKind::Tuple(self.push_expr_list(items))
724            }
725            ExprKind::Variant { tag, value } => ControlExprKind::Variant {
726                tag: self.intern_name(tag),
727                value: value.map(|value| self.expr(*value)),
728            },
729            ExprKind::Match {
730                scrutinee, arms, ..
731            } => {
732                let scrutinee = self.expr(*scrutinee);
733                let arms = arms
734                    .into_iter()
735                    .map(|arm| ControlMatchArm {
736                        pattern: self.pattern(arm.pattern),
737                        guard: arm.guard.map(|guard| self.expr(guard)),
738                        body: self.expr(arm.body),
739                    })
740                    .collect();
741                ControlExprKind::Match {
742                    scrutinee,
743                    arms: self.push_match_arms(arms),
744                }
745            }
746            ExprKind::Block { stmts, tail } => {
747                let stmts = stmts.into_iter().map(|stmt| self.stmt(stmt)).collect();
748                let tail = tail.map(|tail| self.expr(*tail));
749                ControlExprKind::Block(self.push_block(ControlBlock { stmts, tail }))
750            }
751            ExprKind::Handle {
752                body,
753                arms,
754                evidence,
755                ..
756            } => {
757                let body = self.expr(*body);
758                let arms = arms
759                    .into_iter()
760                    .map(|arm| ControlHandleArm {
761                        effect: self.intern_path(arm.effect),
762                        payload: self.pattern(arm.payload),
763                        resume: arm
764                            .resume
765                            .map(|resume| self.intern_local_name_path(&resume.name)),
766                        guard: arm.guard.map(|guard| self.expr(guard)),
767                        body: self.expr(arm.body),
768                    })
769                    .collect();
770                ControlExprKind::Handle {
771                    body,
772                    arms: self.push_handle_arms(arms),
773                    result_wraps_thunk: type_wraps_thunk(&Type::value(evidence.result)),
774                }
775            }
776            ExprKind::BindHere { expr } => ControlExprKind::BindHere(self.expr(*expr)),
777            ExprKind::Thunk { expr, .. } => ControlExprKind::Thunk(self.expr(*expr)),
778            ExprKind::LocalPushId { id, body } => ControlExprKind::LocalPushId {
779                id,
780                body: self.expr(*body),
781            },
782            ExprKind::PeekId => ControlExprKind::PeekId,
783            ExprKind::FindId { id } => ControlExprKind::FindId { id },
784            ExprKind::AddId {
785                id,
786                allowed,
787                active,
788                thunk,
789            } => ControlExprKind::AddId {
790                id,
791                allowed: self.push_type(allowed),
792                active,
793                thunk: self.expr(*thunk),
794            },
795            ExprKind::Coerce { to, expr, .. } => ControlExprKind::Coerce {
796                to: self.push_type(to),
797                expr: self.expr(*expr),
798            },
799            ExprKind::Pack { expr, .. } => ControlExprKind::Pack(self.expr(*expr)),
800            ExprKind::Select { base, field } => ControlExprKind::Select {
801                base: self.expr(*base),
802                field: self.intern_name(field),
803            },
804            ExprKind::Record { fields, spread } => {
805                let fields = fields
806                    .into_iter()
807                    .map(|field| ControlRecordField {
808                        name: field.name,
809                        value: self.expr(field.value),
810                    })
811                    .collect();
812                let spread = spread.map(|spread| match spread {
813                    RecordSpreadExpr::Head(expr) => ControlRecordSpread::Head(self.expr(*expr)),
814                    RecordSpreadExpr::Tail(expr) => ControlRecordSpread::Tail(self.expr(*expr)),
815                });
816                ControlExprKind::Record(self.push_record(ControlRecord { fields, spread }))
817            }
818        };
819        let id = ExprId(self.exprs.len());
820        self.exprs.push(ControlExpr { kind });
821        id
822    }
823
824    fn stmt(&mut self, stmt: Stmt) -> ControlStmt {
825        match stmt {
826            Stmt::Let { pattern, value } => ControlStmt::Let {
827                pattern: self.pattern(pattern),
828                value: self.expr(value),
829            },
830            Stmt::Expr(expr) => ControlStmt::Expr(self.expr(expr)),
831            Stmt::Module { def, body } => ControlStmt::Module {
832                def: self.intern_local_path(def),
833                body: self.expr(body),
834            },
835        }
836    }
837}
838
839#[derive(Clone)]
840enum ControlValue {
841    Int(ControlInt),
842    Float(String),
843    String(StringTree),
844    Bytes(BytesTree),
845    Path(Rc<PathBuf>),
846    FileHandle(VmFileHandle),
847    Bool(bool),
848    Unit,
849    List(ListTree<Rc<ControlValue>>),
850    Tuple(Vec<ControlValue>),
851    Record(BTreeMap<typed_ir::Name, ControlValue>),
852    Variant {
853        tag: typed_ir::Name,
854        value: Option<Box<ControlValue>>,
855    },
856    EffectOp(ControlSymbolId),
857    PrimitiveOp(ControlHeap<ControlPrimitive>),
858    Resume(ControlHeap<ControlResume>),
859    Closure(ControlHeap<ControlClosure>),
860    Thunk(ControlHeap<ControlThunk>),
861    EffectId(u64),
862}
863
864#[derive(Clone)]
865#[repr(transparent)]
866struct ControlHeap<T>(Rc<T>);
867
868impl<T> ControlHeap<T> {
869    #[inline]
870    fn new(value: T) -> Self {
871        Self(Rc::new(value))
872    }
873
874    #[inline]
875    fn try_unwrap(self) -> Result<T, Self> {
876        Rc::try_unwrap(self.0).map_err(Self)
877    }
878}
879
880impl<T> std::ops::Deref for ControlHeap<T> {
881    type Target = T;
882
883    #[inline]
884    fn deref(&self) -> &Self::Target {
885        &self.0
886    }
887}
888
889#[derive(Clone)]
890enum ControlInt {
891    Small(i64),
892    Big(Box<BigInt>),
893}
894
895impl ControlInt {
896    fn from_text(value: String) -> Result<Self, VmError> {
897        if let Ok(value) = value.parse() {
898            return Ok(Self::Small(value));
899        }
900        value
901            .parse()
902            .map(|value| Self::Big(Box::new(value)))
903            .map_err(|_| VmError::ExpectedInt(VmValue::Int(value)))
904    }
905
906    fn from_lit(value: &str) -> Self {
907        Self::from_text(value.to_owned()).expect("typed int literal should parse")
908    }
909
910    fn to_vm_string(&self) -> String {
911        match self {
912            Self::Small(value) => value.to_string(),
913            Self::Big(value) => value.to_string(),
914        }
915    }
916
917    fn to_float_string(&self) -> String {
918        match self {
919            Self::Small(value) => format!("{value}.0"),
920            Self::Big(value) => format!("{value}.0"),
921        }
922    }
923
924    fn to_hex_string(&self, upper: bool) -> String {
925        match (self, upper) {
926            (Self::Small(value), false) => format!("{value:x}"),
927            (Self::Small(value), true) => format!("{value:X}"),
928            (Self::Big(value), false) => format!("{:x}", value.as_ref()),
929            (Self::Big(value), true) => format!("{:X}", value.as_ref()),
930        }
931    }
932
933    fn as_i64(&self) -> Result<i64, VmError> {
934        match self {
935            Self::Small(value) => Ok(*value),
936            Self::Big(value) => value
937                .to_string()
938                .parse()
939                .map_err(|_| VmError::ExpectedInt(VmValue::Int(value.to_string()))),
940        }
941    }
942
943    fn add(&self, other: &Self) -> Self {
944        match (self, other) {
945            (Self::Small(left), Self::Small(right)) => left
946                .checked_add(*right)
947                .map(Self::Small)
948                .unwrap_or_else(|| Self::normalize(BigInt::from(*left) + BigInt::from(*right))),
949            _ => Self::normalize(self.to_bigint() + other.to_bigint()),
950        }
951    }
952
953    fn sub(&self, other: &Self) -> Self {
954        match (self, other) {
955            (Self::Small(left), Self::Small(right)) => left
956                .checked_sub(*right)
957                .map(Self::Small)
958                .unwrap_or_else(|| Self::normalize(BigInt::from(*left) - BigInt::from(*right))),
959            _ => Self::normalize(self.to_bigint() - other.to_bigint()),
960        }
961    }
962
963    fn mul(&self, other: &Self) -> Self {
964        match (self, other) {
965            (Self::Small(left), Self::Small(right)) => left
966                .checked_mul(*right)
967                .map(Self::Small)
968                .unwrap_or_else(|| Self::normalize(BigInt::from(*left) * BigInt::from(*right))),
969            _ => Self::normalize(self.to_bigint() * other.to_bigint()),
970        }
971    }
972
973    fn div(&self, other: &Self) -> Self {
974        match (self, other) {
975            (Self::Small(left), Self::Small(right)) => left
976                .checked_div(*right)
977                .map(Self::Small)
978                .unwrap_or_else(|| Self::normalize(BigInt::from(*left) / BigInt::from(*right))),
979            _ => Self::normalize(self.to_bigint() / other.to_bigint()),
980        }
981    }
982
983    fn rem(&self, other: &Self) -> Self {
984        match (self, other) {
985            (Self::Small(left), Self::Small(right)) => left
986                .checked_rem(*right)
987                .map(Self::Small)
988                .unwrap_or_else(|| Self::normalize(BigInt::from(*left) % BigInt::from(*right))),
989            _ => Self::normalize(self.to_bigint() % other.to_bigint()),
990        }
991    }
992
993    fn to_bigint(&self) -> BigInt {
994        match self {
995            Self::Small(value) => BigInt::from(*value),
996            Self::Big(value) => (**value).clone(),
997        }
998    }
999
1000    fn cmp(&self, other: &Self) -> Ordering {
1001        match (self, other) {
1002            (Self::Small(left), Self::Small(right)) => left.cmp(right),
1003            _ => self.to_bigint().cmp(&other.to_bigint()),
1004        }
1005    }
1006
1007    fn normalize(value: BigInt) -> Self {
1008        value
1009            .to_string()
1010            .parse()
1011            .map(Self::Small)
1012            .unwrap_or_else(|_| Self::Big(Box::new(value)))
1013    }
1014}
1015
1016impl PartialEq for ControlInt {
1017    fn eq(&self, other: &Self) -> bool {
1018        self.cmp(other).is_eq()
1019    }
1020}
1021
1022impl Eq for ControlInt {}
1023
1024#[derive(Clone)]
1025struct ControlPrimitive {
1026    op: typed_ir::PrimitiveOp,
1027    args: Vec<ControlValue>,
1028}
1029
1030#[derive(Clone)]
1031struct ControlClosure {
1032    param: ControlLocalId,
1033    param_forces_thunk_arg: bool,
1034    body: ExprId,
1035    result_wraps_thunk: bool,
1036    env: ControlEnv,
1037    guard_stack: GuardStack,
1038    self_name: Option<ControlLocalId>,
1039}
1040
1041struct DirectKnownClosure {
1042    param: ControlLocalId,
1043    param_forces_thunk_arg: bool,
1044    body: ExprId,
1045    result_wraps_thunk: bool,
1046    guard_stack: GuardStack,
1047}
1048
1049impl DirectKnownClosure {
1050    fn into_control_closure(self) -> ControlClosure {
1051        ControlClosure {
1052            param: self.param,
1053            param_forces_thunk_arg: self.param_forces_thunk_arg,
1054            body: self.body,
1055            result_wraps_thunk: self.result_wraps_thunk,
1056            env: ControlEnv::new(),
1057            guard_stack: self.guard_stack,
1058            self_name: None,
1059        }
1060    }
1061}
1062
1063enum DirectKnownCallee {
1064    Closure(DirectKnownClosure),
1065    PrimitiveOp(typed_ir::PrimitiveOp),
1066    EffectOp(ControlSymbolId),
1067}
1068
1069#[derive(Clone)]
1070struct ControlThunk {
1071    body: ControlThunkBody,
1072    env: ControlEnv,
1073    guard_stack: GuardStack,
1074    blocked: Vec<BlockedEffect>,
1075}
1076
1077#[derive(Clone)]
1078enum ControlThunkBody {
1079    Value(ControlValue),
1080    Expr(ExprId),
1081    Emit {
1082        effect: ControlSymbolId,
1083        payload: ControlValue,
1084    },
1085}
1086
1087#[derive(Clone)]
1088struct ControlResume {
1089    continuation: ControlContinuation,
1090}
1091
1092#[derive(Clone, Default)]
1093struct ControlContinuation {
1094    frames: VecDeque<ControlFrame>,
1095    guard_stack: GuardStack,
1096}
1097
1098#[derive(Clone)]
1099struct ControlRequest {
1100    effect: ControlSymbolId,
1101    payload: ControlValue,
1102    continuation: ControlContinuation,
1103    blocked_id: Option<u64>,
1104    blocked_ids: Vec<u64>,
1105}
1106
1107enum ControlResult {
1108    Value(ControlValue),
1109    Request(ControlRequest),
1110}
1111
1112#[derive(Clone)]
1113enum ControlFrame {
1114    BindHere,
1115    ApplyCallee {
1116        arg: ExprId,
1117        env: ControlEnv,
1118        delay_arg: bool,
1119    },
1120    ApplyArg {
1121        callee: ControlValue,
1122    },
1123    If {
1124        then_branch: ExprId,
1125        else_branch: ExprId,
1126        env: ControlEnv,
1127    },
1128    Tuple {
1129        done: Vec<ControlValue>,
1130        items: ControlExprListId,
1131        next_index: usize,
1132        env: ControlEnv,
1133    },
1134    Select {
1135        field: typed_ir::Name,
1136    },
1137    Match {
1138        arms: ControlMatchArmsId,
1139        env: ControlEnv,
1140    },
1141    Variant {
1142        tag: ControlNameId,
1143    },
1144    BlockLet {
1145        block: ControlBlockId,
1146        stmt_index: usize,
1147        env: ControlEnv,
1148    },
1149    BlockExpr {
1150        block: ControlBlockId,
1151        next_index: usize,
1152        env: ControlEnv,
1153    },
1154    Handle {
1155        id: u64,
1156        arms: ControlHandleArmsId,
1157        env: ControlEnv,
1158        guard_stack: GuardStack,
1159        result_wraps_thunk: bool,
1160    },
1161    HandleGuard {
1162        id: u64,
1163        request: ControlRequest,
1164        outer: ControlContinuation,
1165        handler_guard_stack: GuardStack,
1166        arms: ControlHandleArmsId,
1167        next_arm_index: usize,
1168        env: ControlEnv,
1169        arm_env: ControlEnv,
1170        body: ExprId,
1171        result_wraps_thunk: bool,
1172    },
1173    LocalPushId {
1174        parent: GuardStack,
1175    },
1176    BlockedEffects {
1177        blocked: Vec<BlockedEffect>,
1178        active: bool,
1179    },
1180    Coerce {
1181        to: typed_ir::Type,
1182    },
1183    WrapThunkResult,
1184}
1185
1186#[derive(Clone, Default)]
1187struct ControlEnv {
1188    slots: Rc<Vec<(ControlLocalId, ControlValue)>>,
1189}
1190
1191impl ControlEnv {
1192    fn new() -> Self {
1193        Self {
1194            slots: Rc::new(Vec::new()),
1195        }
1196    }
1197
1198    fn get(&self, local: ControlLocalId) -> Option<&ControlValue> {
1199        self.slots
1200            .iter()
1201            .rev()
1202            .find_map(|(slot, value)| (*slot == local).then_some(value))
1203    }
1204
1205    fn insert(&mut self, local: ControlLocalId, value: ControlValue) {
1206        let slots = Rc::make_mut(&mut self.slots);
1207        if let Some((_, existing)) = slots.iter_mut().rev().find(|(slot, _)| *slot == local) {
1208            *existing = value;
1209            return;
1210        }
1211        slots.push((local, value));
1212    }
1213}
1214
1215struct ControlInterpreter<'m> {
1216    module: &'m ControlModule,
1217    next_guard_id: u64,
1218    guard_stack: GuardStack,
1219    eval_depth: usize,
1220    profile: VmProfile,
1221}
1222
1223impl<'m> ControlInterpreter<'m> {
1224    fn new(module: &'m ControlModule) -> Self {
1225        Self {
1226            module,
1227            next_guard_id: 0,
1228            guard_stack: GuardStack::default(),
1229            eval_depth: 0,
1230            profile: VmProfile::default(),
1231        }
1232    }
1233
1234    fn profile(&self) -> VmProfile {
1235        self.profile
1236    }
1237
1238    fn clone_continuation(&mut self, continuation: &ControlContinuation) -> ControlContinuation {
1239        self.profile.continuation_clones += 1;
1240        self.profile.continuation_clone_frames += continuation.frames.len();
1241        continuation.clone()
1242    }
1243
1244    fn expr(&self, id: ExprId) -> &ControlExpr {
1245        &self.module.exprs[id.0]
1246    }
1247
1248    fn eval_root_expr(&mut self, expr: ExprId) -> Result<VmResult, VmError> {
1249        let result = self.eval_root_control_result(expr)?;
1250        self.export_result(result)
1251    }
1252
1253    fn eval_root_control_result(&mut self, expr: ExprId) -> Result<ControlResult, VmError> {
1254        let result = self.eval_expr(expr, &ControlEnv::new())?;
1255        self.normalize_root_result(result)
1256    }
1257
1258    fn normalize_root_result(&mut self, result: ControlResult) -> Result<ControlResult, VmError> {
1259        let mut result = result;
1260        loop {
1261            result = match result {
1262                ControlResult::Value(ControlValue::Thunk(thunk)) => {
1263                    self.bind_here(ControlValue::Thunk(thunk))?
1264                }
1265                ControlResult::Request(request) => match self.propagate_request(request)? {
1266                    ControlResult::Request(request) => return Ok(ControlResult::Request(request)),
1267                    result => result,
1268                },
1269                result => return Ok(result),
1270            };
1271        }
1272    }
1273
1274    fn export_result(&self, result: ControlResult) -> Result<VmResult, VmError> {
1275        match result {
1276            ControlResult::Value(value) => {
1277                Ok(VmResult::Value(export_value(&value, Some(self.module))?))
1278            }
1279            ControlResult::Request(request) => {
1280                Ok(VmResult::Request(self.export_request(&request)?))
1281            }
1282        }
1283    }
1284
1285    fn export_request(&self, request: &ControlRequest) -> Result<VmRequest, VmError> {
1286        Ok(VmRequest {
1287            effect: self.module.symbol_path(request.effect).clone(),
1288            payload: export_value(&request.payload, Some(self.module))?,
1289            continuation: VmContinuation {
1290                frames: Vec::new(),
1291                guard_stack: GuardStack::default(),
1292                blocked_ids: request.blocked_ids.clone(),
1293            },
1294            blocked_id: request.blocked_id,
1295        })
1296    }
1297
1298    fn undet_request_operation(
1299        &self,
1300        request: &ControlRequest,
1301    ) -> Option<crate::host::UndetOperation> {
1302        crate::host::undet_operation(self.module.symbol_path(request.effect))
1303    }
1304
1305    fn eval_expr(&mut self, expr: ExprId, env: &ControlEnv) -> Result<ControlResult, VmError> {
1306        self.profile.eval_expr_calls += 1;
1307        self.eval_depth += 1;
1308        self.profile.max_eval_depth = self.profile.max_eval_depth.max(self.eval_depth);
1309        let result = self.eval_expr_inner(expr, env);
1310        self.eval_depth -= 1;
1311        result
1312    }
1313
1314    fn eval_expr_inner(
1315        &mut self,
1316        expr: ExprId,
1317        env: &ControlEnv,
1318    ) -> Result<ControlResult, VmError> {
1319        let kind = self.expr(expr).kind;
1320        match kind {
1321            ControlExprKind::Var(path) => self.eval_var(path, env),
1322            ControlExprKind::EffectOp(path) => {
1323                Ok(ControlResult::Value(ControlValue::EffectOp(path)))
1324            }
1325            ControlExprKind::PrimitiveOp(typed_ir::PrimitiveOp::YadaYada) => Err(VmError::YadaYada),
1326            ControlExprKind::PrimitiveOp(op) => Ok(ControlResult::Value(
1327                ControlValue::PrimitiveOp(ControlHeap::new(ControlPrimitive {
1328                    op,
1329                    args: Vec::new(),
1330                })),
1331            )),
1332            ControlExprKind::Lit(lit) => Ok(ControlResult::Value(control_value_from_lit(
1333                self.module.lit(lit),
1334            ))),
1335            ControlExprKind::Lambda {
1336                param,
1337                param_forces_thunk_arg,
1338                body,
1339                result_wraps_thunk,
1340            } => Ok(ControlResult::Value(ControlValue::Closure(
1341                ControlHeap::new(ControlClosure {
1342                    param,
1343                    param_forces_thunk_arg,
1344                    body,
1345                    result_wraps_thunk,
1346                    env: env.clone(),
1347                    guard_stack: self.guard_stack.clone(),
1348                    self_name: None,
1349                }),
1350            ))),
1351            ControlExprKind::Apply {
1352                callee,
1353                arg,
1354                delay_arg,
1355            } => {
1356                if !delay_arg
1357                    && let Some((op, first_arg)) = self.direct_binary_primitive_apply(callee, env)
1358                {
1359                    return self.eval_direct_binary_primitive(op, first_arg, arg, env);
1360                }
1361                if let Some(callee) = self.direct_known_callee(callee, env) {
1362                    return self.continue_direct_known_apply_arg(callee, arg, env, delay_arg);
1363                }
1364                match self.eval_expr(callee, env)? {
1365                    ControlResult::Value(callee) => {
1366                        self.continue_apply_arg(callee, arg, env, delay_arg)
1367                    }
1368                    ControlResult::Request(request) => Ok(ControlResult::Request(push_frame(
1369                        request,
1370                        ControlFrame::ApplyCallee {
1371                            arg,
1372                            env: env.clone(),
1373                            delay_arg,
1374                        },
1375                    ))),
1376                }
1377            }
1378            ControlExprKind::If {
1379                cond,
1380                then_branch,
1381                else_branch,
1382            } => {
1383                let result = self.eval_expr(cond, env)?;
1384                self.continue_if_result(result, then_branch, else_branch, env)
1385            }
1386            ControlExprKind::Tuple(items) => self.eval_tuple(Vec::new(), items, 0, env.clone()),
1387            ControlExprKind::Variant { tag, value } => match value {
1388                Some(value) => {
1389                    let result = self.eval_expr(value, env)?;
1390                    let result = self.force_value_result(result)?;
1391                    self.continue_variant_value(tag, result)
1392                }
1393                None => Ok(ControlResult::Value(ControlValue::Variant {
1394                    tag: self.module.name(tag).clone(),
1395                    value: None,
1396                })),
1397            },
1398            ControlExprKind::Match { scrutinee, arms } => match self.eval_expr(scrutinee, env)? {
1399                ControlResult::Value(value) => self.eval_match(value, arms, env),
1400                ControlResult::Request(request) => Ok(ControlResult::Request(push_frame(
1401                    request,
1402                    ControlFrame::Match {
1403                        arms,
1404                        env: env.clone(),
1405                    },
1406                ))),
1407            },
1408            ControlExprKind::Block(block) => self.eval_block(block, 0, env.clone()),
1409            ControlExprKind::Handle {
1410                body,
1411                arms,
1412                result_wraps_thunk,
1413            } => self.eval_handle(body, arms, result_wraps_thunk, env),
1414            ControlExprKind::BindHere(expr) => match self.eval_expr(expr, env)? {
1415                ControlResult::Value(value) => self.bind_here(value),
1416                ControlResult::Request(request) => Ok(ControlResult::Request(push_frame(
1417                    request,
1418                    ControlFrame::BindHere,
1419                ))),
1420            },
1421            ControlExprKind::Thunk(expr) => Ok(ControlResult::Value(ControlValue::Thunk(
1422                ControlHeap::new(ControlThunk {
1423                    body: ControlThunkBody::Expr(expr),
1424                    env: env.clone(),
1425                    guard_stack: self.guard_stack.clone(),
1426                    blocked: Vec::new(),
1427                }),
1428            ))),
1429            ControlExprKind::LocalPushId { id, body } => {
1430                let guard_id = self.fresh_guard_id();
1431                let parent = self.guard_stack.clone();
1432                self.guard_stack = parent.push(GuardEntry {
1433                    var: id,
1434                    id: guard_id,
1435                });
1436                let result = self.eval_expr(body, env);
1437                self.guard_stack = parent.clone();
1438                match result? {
1439                    ControlResult::Request(request) => Ok(ControlResult::Request(push_frame(
1440                        request,
1441                        ControlFrame::LocalPushId { parent },
1442                    ))),
1443                    value => Ok(value),
1444                }
1445            }
1446            ControlExprKind::PeekId => {
1447                let id = self.guard_stack.peek().ok_or(VmError::UnsupportedFindId)?;
1448                Ok(ControlResult::Value(ControlValue::EffectId(id)))
1449            }
1450            ControlExprKind::FindId { id } => Ok(ControlResult::Value(ControlValue::Bool(
1451                self.find_effect_id(id)?,
1452            ))),
1453            ControlExprKind::AddId {
1454                id,
1455                allowed,
1456                active,
1457                thunk,
1458            } => {
1459                let id = self.eval_effect_id(id)?;
1460                let result = self.eval_expr(thunk, env)?;
1461                let ControlResult::Value(ControlValue::Thunk(thunk)) = result else {
1462                    return Ok(match result {
1463                        ControlResult::Request(request) => {
1464                            let blocked = [BlockedEffect {
1465                                guard_id: id,
1466                                allowed: self.module.ty(allowed).clone(),
1467                                active,
1468                            }];
1469                            let request = if active {
1470                                mark_control_request_with_active_blocked(
1471                                    self.module,
1472                                    request,
1473                                    &blocked,
1474                                )
1475                            } else {
1476                                mark_control_request_with_blocked(self.module, request, &blocked)
1477                            };
1478                            ControlResult::Request(request)
1479                        }
1480                        other => other,
1481                    });
1482                };
1483                let mut thunk = (*thunk).clone();
1484                thunk.blocked.push(BlockedEffect {
1485                    guard_id: id,
1486                    allowed: self.module.ty(allowed).clone(),
1487                    active,
1488                });
1489                Ok(ControlResult::Value(ControlValue::Thunk(ControlHeap::new(
1490                    thunk,
1491                ))))
1492            }
1493            ControlExprKind::Coerce { to, expr } => match self.eval_expr(expr, env)? {
1494                ControlResult::Value(value) => Ok(ControlResult::Value(control_cast_value(
1495                    value,
1496                    self.module.ty(to),
1497                ))),
1498                ControlResult::Request(request) => Ok(ControlResult::Request(push_frame(
1499                    request,
1500                    ControlFrame::Coerce {
1501                        to: self.module.ty(to).clone(),
1502                    },
1503                ))),
1504            },
1505            ControlExprKind::Pack(expr) => self.eval_expr(expr, env),
1506            ControlExprKind::Select { base, field } => match self.eval_expr(base, env)? {
1507                ControlResult::Value(value) => self.select_field(value, self.module.name(field)),
1508                ControlResult::Request(request) => Ok(ControlResult::Request(push_frame(
1509                    request,
1510                    ControlFrame::Select {
1511                        field: self.module.name(field).clone(),
1512                    },
1513                ))),
1514            },
1515            ControlExprKind::Record(record) => self.eval_record(record, env),
1516        }
1517    }
1518
1519    fn eval_var(
1520        &mut self,
1521        path: ControlSymbolId,
1522        env: &ControlEnv,
1523    ) -> Result<ControlResult, VmError> {
1524        if let Some(local) = self.module.local_for_symbol(path)
1525            && let Some(value) = env.get(local)
1526        {
1527            return Ok(ControlResult::Value(value.clone()));
1528        }
1529        if let Some(index) = self
1530            .module
1531            .binding_by_symbol
1532            .get(path.0)
1533            .and_then(|index| *index)
1534        {
1535            return self.eval_expr(self.module.bindings[index].body, &ControlEnv::new());
1536        }
1537        let path_ref = self.module.symbol_path(path);
1538        if path_ref.segments.len() > 1 {
1539            return Ok(ControlResult::Value(ControlValue::EffectOp(path)));
1540        }
1541        Err(VmError::UnboundVariable(path_ref.clone()))
1542    }
1543
1544    fn direct_known_callee(&self, callee: ExprId, env: &ControlEnv) -> Option<DirectKnownCallee> {
1545        let path = match self.expr(callee).kind {
1546            ControlExprKind::PrimitiveOp(typed_ir::PrimitiveOp::YadaYada) => return None,
1547            ControlExprKind::PrimitiveOp(op) => return Some(DirectKnownCallee::PrimitiveOp(op)),
1548            ControlExprKind::EffectOp(effect) => return Some(DirectKnownCallee::EffectOp(effect)),
1549            ControlExprKind::Var(path) => path,
1550            _ => return None,
1551        };
1552        if let Some(local) = self.module.local_for_symbol(path)
1553            && env.get(local).is_some()
1554        {
1555            return None;
1556        }
1557        let Some(binding_index) = self
1558            .module
1559            .binding_by_symbol
1560            .get(path.0)
1561            .and_then(|index| *index)
1562        else {
1563            let path_ref = self.module.symbol_path(path);
1564            return (path_ref.segments.len() > 1).then_some(DirectKnownCallee::EffectOp(path));
1565        };
1566        let binding_body = self.module.bindings[binding_index].body;
1567        match self.expr(binding_body).kind {
1568            ControlExprKind::Lambda {
1569                param,
1570                param_forces_thunk_arg,
1571                body,
1572                result_wraps_thunk,
1573            } => Some(DirectKnownCallee::Closure(DirectKnownClosure {
1574                param,
1575                param_forces_thunk_arg,
1576                body,
1577                result_wraps_thunk,
1578                guard_stack: self.guard_stack.clone(),
1579            })),
1580            ControlExprKind::PrimitiveOp(typed_ir::PrimitiveOp::YadaYada) => None,
1581            ControlExprKind::PrimitiveOp(op) => Some(DirectKnownCallee::PrimitiveOp(op)),
1582            ControlExprKind::EffectOp(effect) => Some(DirectKnownCallee::EffectOp(effect)),
1583            _ => None,
1584        }
1585    }
1586
1587    fn direct_binary_primitive_apply(
1588        &self,
1589        callee: ExprId,
1590        env: &ControlEnv,
1591    ) -> Option<(typed_ir::PrimitiveOp, ExprId)> {
1592        let ControlExprKind::Apply {
1593            callee,
1594            arg,
1595            delay_arg: false,
1596        } = self.expr(callee).kind
1597        else {
1598            return None;
1599        };
1600        let op = self.direct_known_primitive_op(callee, env)?;
1601        (primitive_arity(op) == 2).then_some((op, arg))
1602    }
1603
1604    fn direct_known_primitive_op(
1605        &self,
1606        callee: ExprId,
1607        env: &ControlEnv,
1608    ) -> Option<typed_ir::PrimitiveOp> {
1609        let path = match self.expr(callee).kind {
1610            ControlExprKind::PrimitiveOp(typed_ir::PrimitiveOp::YadaYada) => return None,
1611            ControlExprKind::PrimitiveOp(op) => return Some(op),
1612            ControlExprKind::Var(path) => path,
1613            _ => return None,
1614        };
1615        if let Some(local) = self.module.local_for_symbol(path)
1616            && env.get(local).is_some()
1617        {
1618            return None;
1619        }
1620        let binding_index = self
1621            .module
1622            .binding_by_symbol
1623            .get(path.0)
1624            .and_then(|index| *index)?;
1625        let binding_body = self.module.bindings[binding_index].body;
1626        match self.expr(binding_body).kind {
1627            ControlExprKind::PrimitiveOp(typed_ir::PrimitiveOp::YadaYada) => None,
1628            ControlExprKind::PrimitiveOp(op) => Some(op),
1629            _ => None,
1630        }
1631    }
1632
1633    fn continue_if_result(
1634        &mut self,
1635        result: ControlResult,
1636        then_branch: ExprId,
1637        else_branch: ExprId,
1638        env: &ControlEnv,
1639    ) -> Result<ControlResult, VmError> {
1640        match result {
1641            ControlResult::Value(ControlValue::Thunk(thunk)) => {
1642                match self.bind_here(ControlValue::Thunk(thunk))? {
1643                    ControlResult::Value(value) => {
1644                        self.continue_if_value(value, then_branch, else_branch, env)
1645                    }
1646                    ControlResult::Request(request) => Ok(ControlResult::Request(push_frame(
1647                        request,
1648                        ControlFrame::If {
1649                            then_branch,
1650                            else_branch,
1651                            env: env.clone(),
1652                        },
1653                    ))),
1654                }
1655            }
1656            ControlResult::Value(value) => {
1657                self.continue_if_value(value, then_branch, else_branch, env)
1658            }
1659            ControlResult::Request(request) => Ok(ControlResult::Request(push_frame(
1660                request,
1661                ControlFrame::If {
1662                    then_branch,
1663                    else_branch,
1664                    env: env.clone(),
1665                },
1666            ))),
1667        }
1668    }
1669
1670    fn continue_if_value(
1671        &mut self,
1672        value: ControlValue,
1673        then_branch: ExprId,
1674        else_branch: ExprId,
1675        env: &ControlEnv,
1676    ) -> Result<ControlResult, VmError> {
1677        match value {
1678            ControlValue::Bool(true) => self.eval_expr(then_branch, env),
1679            ControlValue::Bool(false) => self.eval_expr(else_branch, env),
1680            other => Err(VmError::ExpectedBool(export_value_lossy(
1681                &other,
1682                Some(self.module),
1683            ))),
1684        }
1685    }
1686
1687    fn continue_if_value_frame(
1688        &mut self,
1689        value: ControlValue,
1690        then_branch: ExprId,
1691        else_branch: ExprId,
1692        env: ControlEnv,
1693    ) -> Result<ControlResult, VmError> {
1694        match value {
1695            ControlValue::Thunk(thunk) => match self.bind_here(ControlValue::Thunk(thunk))? {
1696                ControlResult::Value(value) => {
1697                    self.continue_if_value_frame(value, then_branch, else_branch, env)
1698                }
1699                ControlResult::Request(request) => Ok(ControlResult::Request(push_frame(
1700                    request,
1701                    ControlFrame::If {
1702                        then_branch,
1703                        else_branch,
1704                        env,
1705                    },
1706                ))),
1707            },
1708            ControlValue::Bool(true) => self.eval_expr(then_branch, &env),
1709            ControlValue::Bool(false) => self.eval_expr(else_branch, &env),
1710            other => Err(VmError::ExpectedBool(export_value_lossy(
1711                &other,
1712                Some(self.module),
1713            ))),
1714        }
1715    }
1716
1717    fn eval_value(&mut self, expr: ExprId, env: &ControlEnv) -> Result<ControlValue, VmError> {
1718        match self.eval_expr(expr, env)? {
1719            ControlResult::Value(value) => Ok(value),
1720            ControlResult::Request(request) => Err(VmError::UnexpectedRequest(
1721                self.module.symbol_path(request.effect).clone(),
1722            )),
1723        }
1724    }
1725
1726    fn bind_here(&mut self, value: ControlValue) -> Result<ControlResult, VmError> {
1727        let parent = self.guard_stack.clone();
1728        let mut value = value;
1729        let mut outer_thunks = Vec::new();
1730        let result = loop {
1731            let ControlValue::Thunk(thunk) = value else {
1732                break Ok(ControlResult::Value(value));
1733            };
1734            self.guard_stack = thunk.guard_stack.clone();
1735            match &thunk.body {
1736                ControlThunkBody::Value(next) => {
1737                    value = next.clone();
1738                }
1739                ControlThunkBody::Expr(expr) => match self.eval_expr(*expr, &thunk.env)? {
1740                    ControlResult::Value(next @ ControlValue::Thunk(_)) => {
1741                        outer_thunks.push(thunk.clone());
1742                        value = next;
1743                    }
1744                    ControlResult::Request(request) => {
1745                        let mut request = push_thunk_expr_frames(request, &thunk);
1746                        for outer in outer_thunks.iter().rev() {
1747                            request = push_thunk_boundary_frame(request, outer);
1748                        }
1749                        break Ok(ControlResult::Request(request));
1750                    }
1751                    other => break Ok(other),
1752                },
1753                ControlThunkBody::Emit { effect, payload } => {
1754                    let mut request = push_thunk_boundary_frame(
1755                        ControlRequest {
1756                            effect: *effect,
1757                            payload: payload.clone(),
1758                            continuation: ControlContinuation {
1759                                frames: VecDeque::new(),
1760                                guard_stack: self.guard_stack.clone(),
1761                            },
1762                            blocked_id: None,
1763                            blocked_ids: Vec::new(),
1764                        },
1765                        &thunk,
1766                    );
1767                    for outer in outer_thunks.iter().rev() {
1768                        request = push_thunk_boundary_frame(request, outer);
1769                    }
1770                    break Ok(ControlResult::Request(request));
1771                }
1772            }
1773        };
1774        self.guard_stack = parent;
1775        result
1776    }
1777
1778    fn continue_apply_arg(
1779        &mut self,
1780        callee: ControlValue,
1781        arg: ExprId,
1782        env: &ControlEnv,
1783        delay_arg: bool,
1784    ) -> Result<ControlResult, VmError> {
1785        if matches!(callee, ControlValue::Thunk(_)) {
1786            return self.force_apply_callee(callee, arg, env.clone(), delay_arg);
1787        }
1788        if delay_arg {
1789            return self.apply(
1790                callee,
1791                ControlValue::Thunk(ControlHeap::new(ControlThunk {
1792                    body: ControlThunkBody::Expr(arg),
1793                    env: env.clone(),
1794                    guard_stack: self.guard_stack.clone(),
1795                    blocked: Vec::new(),
1796                })),
1797            );
1798        }
1799        match self.eval_expr(arg, env)? {
1800            ControlResult::Value(arg) => self.apply(callee, arg),
1801            ControlResult::Request(request) => Ok(ControlResult::Request(push_frame(
1802                request,
1803                ControlFrame::ApplyArg { callee },
1804            ))),
1805        }
1806    }
1807
1808    fn continue_direct_known_apply_arg(
1809        &mut self,
1810        callee: DirectKnownCallee,
1811        arg: ExprId,
1812        env: &ControlEnv,
1813        delay_arg: bool,
1814    ) -> Result<ControlResult, VmError> {
1815        match callee {
1816            DirectKnownCallee::Closure(callee) => {
1817                self.profile.direct_known_closure_calls += 1;
1818                self.continue_direct_apply_arg(callee, arg, env, delay_arg)
1819            }
1820            DirectKnownCallee::PrimitiveOp(op) => self.continue_apply_arg(
1821                ControlValue::PrimitiveOp(ControlHeap::new(ControlPrimitive {
1822                    op,
1823                    args: Vec::new(),
1824                })),
1825                arg,
1826                env,
1827                delay_arg,
1828            ),
1829            DirectKnownCallee::EffectOp(effect) => {
1830                self.continue_apply_arg(ControlValue::EffectOp(effect), arg, env, delay_arg)
1831            }
1832        }
1833    }
1834
1835    fn eval_direct_binary_primitive(
1836        &mut self,
1837        op: typed_ir::PrimitiveOp,
1838        first_arg: ExprId,
1839        second_arg: ExprId,
1840        env: &ControlEnv,
1841    ) -> Result<ControlResult, VmError> {
1842        self.profile.direct_binary_primitive_calls += 1;
1843        let primitive = || {
1844            ControlValue::PrimitiveOp(ControlHeap::new(ControlPrimitive {
1845                op,
1846                args: Vec::new(),
1847            }))
1848        };
1849        let first = match self.eval_expr(first_arg, env)? {
1850            ControlResult::Value(ControlValue::Thunk(thunk)) => {
1851                return match self.apply(primitive(), ControlValue::Thunk(thunk))? {
1852                    ControlResult::Value(callee) => {
1853                        self.continue_apply_arg(callee, second_arg, env, false)
1854                    }
1855                    ControlResult::Request(request) => Ok(ControlResult::Request(push_frame(
1856                        request,
1857                        ControlFrame::ApplyCallee {
1858                            arg: second_arg,
1859                            env: env.clone(),
1860                            delay_arg: false,
1861                        },
1862                    ))),
1863                };
1864            }
1865            ControlResult::Value(value) => value,
1866            ControlResult::Request(request) => {
1867                let request = push_frame(
1868                    request,
1869                    ControlFrame::ApplyArg {
1870                        callee: primitive(),
1871                    },
1872                );
1873                return Ok(ControlResult::Request(push_frame(
1874                    request,
1875                    ControlFrame::ApplyCallee {
1876                        arg: second_arg,
1877                        env: env.clone(),
1878                        delay_arg: false,
1879                    },
1880                )));
1881            }
1882        };
1883        let second = match self.eval_expr(second_arg, env)? {
1884            ControlResult::Value(ControlValue::Thunk(thunk)) => {
1885                return self.apply(
1886                    ControlValue::PrimitiveOp(ControlHeap::new(ControlPrimitive {
1887                        op,
1888                        args: vec![first],
1889                    })),
1890                    ControlValue::Thunk(thunk),
1891                );
1892            }
1893            ControlResult::Value(value) => value,
1894            ControlResult::Request(request) => {
1895                return Ok(ControlResult::Request(push_frame(
1896                    request,
1897                    ControlFrame::ApplyArg {
1898                        callee: ControlValue::PrimitiveOp(ControlHeap::new(ControlPrimitive {
1899                            op,
1900                            args: vec![first],
1901                        })),
1902                    },
1903                )));
1904            }
1905        };
1906        let args = [first, second];
1907        self.record_primitive_profile(op, &args);
1908        Ok(ControlResult::Value(control_apply_primitive(op, &args)?))
1909    }
1910
1911    fn continue_direct_apply_arg(
1912        &mut self,
1913        callee: DirectKnownClosure,
1914        arg: ExprId,
1915        env: &ControlEnv,
1916        delay_arg: bool,
1917    ) -> Result<ControlResult, VmError> {
1918        if delay_arg {
1919            return self.apply_direct_closure(
1920                callee,
1921                ControlValue::Thunk(ControlHeap::new(ControlThunk {
1922                    body: ControlThunkBody::Expr(arg),
1923                    env: env.clone(),
1924                    guard_stack: self.guard_stack.clone(),
1925                    blocked: Vec::new(),
1926                })),
1927            );
1928        }
1929        match self.eval_expr(arg, env)? {
1930            ControlResult::Value(arg) => self.apply_direct_closure(callee, arg),
1931            ControlResult::Request(request) => Ok(ControlResult::Request(push_frame(
1932                request,
1933                ControlFrame::ApplyArg {
1934                    callee: ControlValue::Closure(ControlHeap::new(callee.into_control_closure())),
1935                },
1936            ))),
1937        }
1938    }
1939
1940    fn force_apply_callee(
1941        &mut self,
1942        callee: ControlValue,
1943        arg: ExprId,
1944        env: ControlEnv,
1945        delay_arg: bool,
1946    ) -> Result<ControlResult, VmError> {
1947        match self.bind_here(callee)? {
1948            ControlResult::Value(callee) => self.continue_apply_arg(callee, arg, &env, delay_arg),
1949            ControlResult::Request(request) => Ok(ControlResult::Request(push_frame(
1950                request,
1951                ControlFrame::ApplyCallee {
1952                    arg,
1953                    env,
1954                    delay_arg,
1955                },
1956            ))),
1957        }
1958    }
1959
1960    fn apply(&mut self, callee: ControlValue, arg: ControlValue) -> Result<ControlResult, VmError> {
1961        match callee {
1962            ControlValue::Closure(callee) => {
1963                if callee.param_forces_thunk_arg && matches!(arg, ControlValue::Thunk(_)) {
1964                    return self.force_apply_arg(ControlValue::Closure(callee), arg);
1965                }
1966                let self_value = ControlValue::Closure(callee.clone());
1967                self.apply_closure_body(&callee, Some(self_value), arg)
1968            }
1969            ControlValue::Resume(resume) => {
1970                let continuation = self.clone_continuation(&resume.continuation);
1971                self.resume(continuation, arg)
1972            }
1973            ControlValue::EffectOp(effect) => Ok(ControlResult::Value(ControlValue::Thunk(
1974                ControlHeap::new(ControlThunk {
1975                    body: ControlThunkBody::Emit {
1976                        effect,
1977                        payload: arg,
1978                    },
1979                    env: ControlEnv::new(),
1980                    guard_stack: self.guard_stack.clone(),
1981                    blocked: Vec::new(),
1982                }),
1983            ))),
1984            ControlValue::PrimitiveOp(primitive) => {
1985                if matches!(arg, ControlValue::Thunk(_)) {
1986                    return self.force_apply_arg(ControlValue::PrimitiveOp(primitive), arg);
1987                }
1988                self.apply_primitive(primitive, arg)
1989            }
1990            other => Err(VmError::ExpectedClosure(export_value_lossy(
1991                &other,
1992                Some(self.module),
1993            ))),
1994        }
1995    }
1996
1997    fn apply_direct_closure(
1998        &mut self,
1999        callee: DirectKnownClosure,
2000        arg: ControlValue,
2001    ) -> Result<ControlResult, VmError> {
2002        if callee.param_forces_thunk_arg && matches!(arg, ControlValue::Thunk(_)) {
2003            return self.force_apply_arg(
2004                ControlValue::Closure(ControlHeap::new(callee.into_control_closure())),
2005                arg,
2006            );
2007        }
2008        let mut env = ControlEnv::new();
2009        env.insert(callee.param, arg);
2010        self.eval_closure_body(
2011            env,
2012            &callee.guard_stack,
2013            callee.body,
2014            callee.result_wraps_thunk,
2015        )
2016    }
2017
2018    fn apply_closure_body(
2019        &mut self,
2020        callee: &ControlClosure,
2021        self_value: Option<ControlValue>,
2022        arg: ControlValue,
2023    ) -> Result<ControlResult, VmError> {
2024        let mut env = callee.env.clone();
2025        if let (Some(self_name), Some(self_value)) = (callee.self_name, self_value) {
2026            env.insert(self_name, self_value);
2027        }
2028        env.insert(callee.param, arg);
2029        self.eval_closure_body(
2030            env,
2031            &callee.guard_stack,
2032            callee.body,
2033            callee.result_wraps_thunk,
2034        )
2035    }
2036
2037    fn eval_closure_body(
2038        &mut self,
2039        env: ControlEnv,
2040        guard_stack: &GuardStack,
2041        body: ExprId,
2042        result_wraps_thunk: bool,
2043    ) -> Result<ControlResult, VmError> {
2044        let parent_guard_stack = self.guard_stack.clone();
2045        self.guard_stack = parent_guard_stack.overlay_newer(guard_stack);
2046        let result = self.eval_expr(body, &env)?;
2047        self.guard_stack = parent_guard_stack.clone();
2048        if let ControlResult::Request(request) = result {
2049            return Ok(ControlResult::Request(push_frame(
2050                request,
2051                ControlFrame::LocalPushId {
2052                    parent: parent_guard_stack,
2053                },
2054            )));
2055        }
2056        Ok(control_wrap_result(result, result_wraps_thunk))
2057    }
2058
2059    fn force_apply_arg(
2060        &mut self,
2061        callee: ControlValue,
2062        arg: ControlValue,
2063    ) -> Result<ControlResult, VmError> {
2064        match self.bind_here(arg)? {
2065            ControlResult::Value(arg) => self.apply(callee, arg),
2066            ControlResult::Request(request) => Ok(ControlResult::Request(push_frame(
2067                request,
2068                ControlFrame::ApplyArg { callee },
2069            ))),
2070        }
2071    }
2072
2073    fn apply_primitive(
2074        &mut self,
2075        primitive: ControlHeap<ControlPrimitive>,
2076        arg: ControlValue,
2077    ) -> Result<ControlResult, VmError> {
2078        let mut primitive = match primitive.try_unwrap() {
2079            Ok(primitive) => primitive,
2080            Err(primitive) => (*primitive).clone(),
2081        };
2082        primitive.args.push(arg);
2083        if primitive.args.len() < primitive_arity(primitive.op) {
2084            return Ok(ControlResult::Value(ControlValue::PrimitiveOp(
2085                ControlHeap::new(primitive),
2086            )));
2087        }
2088        self.record_primitive_profile(primitive.op, &primitive.args);
2089        Ok(ControlResult::Value(control_apply_primitive(
2090            primitive.op,
2091            &primitive.args,
2092        )?))
2093    }
2094
2095    fn record_primitive_profile(&mut self, op: typed_ir::PrimitiveOp, args: &[ControlValue]) {
2096        self.profile.primitive_apps += 1;
2097        match op {
2098            typed_ir::PrimitiveOp::ListMerge => self.profile.list_merge_calls += 1,
2099            typed_ir::PrimitiveOp::ListViewRaw => self.profile.list_view_raw_calls += 1,
2100            typed_ir::PrimitiveOp::StringConcat => {
2101                self.profile.string_concat_calls += 1;
2102                self.profile.string_concat_input_chars += args
2103                    .iter()
2104                    .filter_map(|arg| match arg {
2105                        ControlValue::String(value) => Some(value.len()),
2106                        _ => None,
2107                    })
2108                    .sum::<usize>();
2109            }
2110            typed_ir::PrimitiveOp::IntToString
2111            | typed_ir::PrimitiveOp::IntToHex
2112            | typed_ir::PrimitiveOp::IntToUpperHex
2113            | typed_ir::PrimitiveOp::FloatToString
2114            | typed_ir::PrimitiveOp::BoolToString
2115            | typed_ir::PrimitiveOp::CharToString => self.profile.string_to_string_calls += 1,
2116            _ => {}
2117        }
2118    }
2119
2120    fn eval_tuple(
2121        &mut self,
2122        mut done: Vec<ControlValue>,
2123        items: ControlExprListId,
2124        mut next_index: usize,
2125        env: ControlEnv,
2126    ) -> Result<ControlResult, VmError> {
2127        let exprs = self.module.expr_list(items);
2128        while let Some(&next) = exprs.get(next_index) {
2129            next_index += 1;
2130            let result = self.eval_expr(next, &env)?;
2131            match self.force_value_result(result)? {
2132                ControlResult::Value(value) => done.push(value),
2133                ControlResult::Request(request) => {
2134                    return Ok(ControlResult::Request(push_frame(
2135                        request,
2136                        ControlFrame::Tuple {
2137                            done,
2138                            items,
2139                            next_index,
2140                            env,
2141                        },
2142                    )));
2143                }
2144            }
2145        }
2146        Ok(ControlResult::Value(ControlValue::Tuple(done)))
2147    }
2148
2149    fn force_value_result(&mut self, result: ControlResult) -> Result<ControlResult, VmError> {
2150        match result {
2151            ControlResult::Value(ControlValue::Thunk(thunk)) => {
2152                self.bind_here(ControlValue::Thunk(thunk))
2153            }
2154            result => Ok(result),
2155        }
2156    }
2157
2158    fn continue_tuple_item(
2159        &mut self,
2160        mut done: Vec<ControlValue>,
2161        items: ControlExprListId,
2162        next_index: usize,
2163        env: ControlEnv,
2164        value: ControlValue,
2165    ) -> Result<ControlResult, VmError> {
2166        match value {
2167            ControlValue::Thunk(thunk) => match self.bind_here(ControlValue::Thunk(thunk))? {
2168                ControlResult::Value(value) => {
2169                    self.continue_tuple_item(done, items, next_index, env, value)
2170                }
2171                ControlResult::Request(request) => Ok(ControlResult::Request(push_frame(
2172                    request,
2173                    ControlFrame::Tuple {
2174                        done,
2175                        items,
2176                        next_index,
2177                        env,
2178                    },
2179                ))),
2180            },
2181            value => {
2182                done.push(value);
2183                self.eval_tuple(done, items, next_index, env)
2184            }
2185        }
2186    }
2187
2188    fn continue_variant_value(
2189        &mut self,
2190        tag: ControlNameId,
2191        result: ControlResult,
2192    ) -> Result<ControlResult, VmError> {
2193        match result {
2194            ControlResult::Value(ControlValue::Thunk(thunk)) => {
2195                match self.bind_here(ControlValue::Thunk(thunk))? {
2196                    result @ ControlResult::Value(_) => self.continue_variant_value(tag, result),
2197                    ControlResult::Request(request) => Ok(ControlResult::Request(push_frame(
2198                        request,
2199                        ControlFrame::Variant { tag },
2200                    ))),
2201                }
2202            }
2203            ControlResult::Value(value) => Ok(ControlResult::Value(ControlValue::Variant {
2204                tag: self.module.name(tag).clone(),
2205                value: Some(Box::new(value)),
2206            })),
2207            ControlResult::Request(request) => Ok(ControlResult::Request(push_frame(
2208                request,
2209                ControlFrame::Variant { tag },
2210            ))),
2211        }
2212    }
2213
2214    fn eval_record(
2215        &mut self,
2216        record: ControlRecordId,
2217        env: &ControlEnv,
2218    ) -> Result<ControlResult, VmError> {
2219        let record = self.module.record(record);
2220        let mut values = BTreeMap::new();
2221        if let Some(spread) = &record.spread {
2222            let spread_expr = match spread {
2223                ControlRecordSpread::Head(expr) | ControlRecordSpread::Tail(expr) => *expr,
2224            };
2225            let ControlValue::Record(base) = self.eval_value(spread_expr, env)? else {
2226                return Err(VmError::ExpectedRecord(VmValue::Unit));
2227            };
2228            values.extend(base);
2229        }
2230        for field in &record.fields {
2231            values.insert(field.name.clone(), self.eval_value(field.value, env)?);
2232        }
2233        Ok(ControlResult::Value(ControlValue::Record(values)))
2234    }
2235
2236    fn select_field(
2237        &self,
2238        value: ControlValue,
2239        field: &typed_ir::Name,
2240    ) -> Result<ControlResult, VmError> {
2241        let ControlValue::Record(fields) = value else {
2242            return Err(VmError::ExpectedRecord(export_value_lossy(
2243                &value,
2244                Some(self.module),
2245            )));
2246        };
2247        fields
2248            .get(field)
2249            .cloned()
2250            .map(ControlResult::Value)
2251            .ok_or(VmError::PatternMismatch)
2252    }
2253
2254    fn eval_match(
2255        &mut self,
2256        value: ControlValue,
2257        arms: ControlMatchArmsId,
2258        env: &ControlEnv,
2259    ) -> Result<ControlResult, VmError> {
2260        let value = match value {
2261            ControlValue::Thunk(thunk) => match self.bind_here(ControlValue::Thunk(thunk))? {
2262                ControlResult::Value(value) => value,
2263                ControlResult::Request(request) => {
2264                    return Ok(ControlResult::Request(push_frame(
2265                        request,
2266                        ControlFrame::Match {
2267                            arms,
2268                            env: env.clone(),
2269                        },
2270                    )));
2271                }
2272            },
2273            value => value,
2274        };
2275        for arm in self.module.match_arms(arms) {
2276            let mut arm_env = env.clone();
2277            if self
2278                .bind_pattern(&arm.pattern, value.clone(), &mut arm_env)
2279                .is_err()
2280            {
2281                continue;
2282            }
2283            if let Some(guard) = arm.guard {
2284                match self.eval_value(guard, &arm_env)? {
2285                    ControlValue::Bool(true) => {}
2286                    ControlValue::Bool(false) => continue,
2287                    other => {
2288                        return Err(VmError::ExpectedBool(export_value_lossy(
2289                            &other,
2290                            Some(self.module),
2291                        )));
2292                    }
2293                }
2294            }
2295            return self.eval_expr(arm.body, &arm_env);
2296        }
2297        Err(VmError::PatternMismatch)
2298    }
2299
2300    fn eval_block(
2301        &mut self,
2302        block: ControlBlockId,
2303        mut stmt_index: usize,
2304        mut env: ControlEnv,
2305    ) -> Result<ControlResult, VmError> {
2306        let block_ref = self.module.block(block);
2307        while let Some(stmt) = block_ref.stmts.get(stmt_index) {
2308            match stmt {
2309                ControlStmt::Let { pattern, value } => match self.eval_expr(*value, &env)? {
2310                    ControlResult::Value(ControlValue::Thunk(thunk)) => {
2311                        match self.bind_here(ControlValue::Thunk(thunk))? {
2312                            ControlResult::Value(mut value) => {
2313                                value = make_recursive_local_value(&pattern, value);
2314                                self.bind_pattern(&pattern, value, &mut env)?;
2315                            }
2316                            ControlResult::Request(request) => {
2317                                return Ok(ControlResult::Request(push_frame(
2318                                    request,
2319                                    ControlFrame::BlockLet {
2320                                        block,
2321                                        stmt_index,
2322                                        env,
2323                                    },
2324                                )));
2325                            }
2326                        }
2327                    }
2328                    ControlResult::Value(mut value) => {
2329                        value = make_recursive_local_value(&pattern, value);
2330                        self.bind_pattern(&pattern, value, &mut env)?;
2331                    }
2332                    ControlResult::Request(request) => {
2333                        return Ok(ControlResult::Request(push_frame(
2334                            request,
2335                            ControlFrame::BlockLet {
2336                                block,
2337                                stmt_index,
2338                                env,
2339                            },
2340                        )));
2341                    }
2342                },
2343                ControlStmt::Expr(expr) => match self.eval_expr(*expr, &env)? {
2344                    ControlResult::Value(ControlValue::Thunk(thunk)) => {
2345                        match self.bind_here(ControlValue::Thunk(thunk))? {
2346                            ControlResult::Value(_) => {}
2347                            ControlResult::Request(request) => {
2348                                return Ok(ControlResult::Request(push_frame(
2349                                    request,
2350                                    ControlFrame::BlockExpr {
2351                                        block,
2352                                        next_index: stmt_index + 1,
2353                                        env,
2354                                    },
2355                                )));
2356                            }
2357                        }
2358                    }
2359                    ControlResult::Value(_) => {}
2360                    ControlResult::Request(request) => {
2361                        return Ok(ControlResult::Request(push_frame(
2362                            request,
2363                            ControlFrame::BlockExpr {
2364                                block,
2365                                next_index: stmt_index + 1,
2366                                env,
2367                            },
2368                        )));
2369                    }
2370                },
2371                ControlStmt::Module { def, body } => {
2372                    let value = self.eval_value(*body, &env)?;
2373                    env.insert(*def, value);
2374                }
2375            }
2376            stmt_index += 1;
2377        }
2378        match block_ref.tail {
2379            Some(tail) => self.eval_expr(tail, &env),
2380            None => Ok(ControlResult::Value(ControlValue::Unit)),
2381        }
2382    }
2383
2384    fn continue_block_expr(
2385        &mut self,
2386        value: ControlValue,
2387        block: ControlBlockId,
2388        next_index: usize,
2389        env: ControlEnv,
2390    ) -> Result<ControlResult, VmError> {
2391        match value {
2392            ControlValue::Thunk(thunk) => match self.bind_here(ControlValue::Thunk(thunk))? {
2393                ControlResult::Value(_) => self.eval_block(block, next_index, env),
2394                ControlResult::Request(request) => Ok(ControlResult::Request(push_frame(
2395                    request,
2396                    ControlFrame::BlockExpr {
2397                        block,
2398                        next_index,
2399                        env,
2400                    },
2401                ))),
2402            },
2403            _ => self.eval_block(block, next_index, env),
2404        }
2405    }
2406
2407    fn eval_handle(
2408        &mut self,
2409        body: ExprId,
2410        arms: ControlHandleArmsId,
2411        result_wraps_thunk: bool,
2412        env: &ControlEnv,
2413    ) -> Result<ControlResult, VmError> {
2414        let id = self.fresh_guard_id();
2415        let handler_guard_stack = self.guard_stack.clone();
2416        let result = match self.eval_expr(body, env)? {
2417            ControlResult::Value(ControlValue::Thunk(thunk)) => {
2418                self.bind_here(ControlValue::Thunk(thunk))?
2419            }
2420            other => other,
2421        };
2422        match result {
2423            ControlResult::Value(value) => self.handle_value(value, arms, env, result_wraps_thunk),
2424            ControlResult::Request(request) => {
2425                let request = push_frame(
2426                    request,
2427                    ControlFrame::Handle {
2428                        id,
2429                        arms,
2430                        env: env.clone(),
2431                        guard_stack: handler_guard_stack,
2432                        result_wraps_thunk,
2433                    },
2434                );
2435                self.propagate_request(request)
2436            }
2437        }
2438    }
2439
2440    fn handle_value(
2441        &mut self,
2442        value: ControlValue,
2443        arms: ControlHandleArmsId,
2444        env: &ControlEnv,
2445        result_wraps_thunk: bool,
2446    ) -> Result<ControlResult, VmError> {
2447        for arm in self
2448            .module
2449            .handle_arms(arms)
2450            .iter()
2451            .filter(|arm| self.module.symbol_path(arm.effect).segments.is_empty())
2452        {
2453            let mut arm_env = env.clone();
2454            if self
2455                .bind_pattern(&arm.payload, value.clone(), &mut arm_env)
2456                .is_err()
2457            {
2458                continue;
2459            }
2460            let result = self.eval_expr(arm.body, &arm_env)?;
2461            return self.force_handle_result(result, result_wraps_thunk);
2462        }
2463        Ok(ControlResult::Value(value))
2464    }
2465
2466    fn handle_request(
2467        &mut self,
2468        request: ControlRequest,
2469        id: u64,
2470        arms: ControlHandleArmsId,
2471        start_arm_index: usize,
2472        env: &ControlEnv,
2473        handler_guard_stack: &GuardStack,
2474        result_wraps_thunk: bool,
2475    ) -> Result<ControlResult, VmError> {
2476        if control_request_is_blocked_by_stack(&request, handler_guard_stack) {
2477            return Ok(ControlResult::Request(request));
2478        }
2479        let arms_slice = self.module.handle_arms(arms);
2480        let Some((arm_index, arm)) =
2481            arms_slice
2482                .iter()
2483                .enumerate()
2484                .skip(start_arm_index)
2485                .find(|(_, arm)| {
2486                    effect_operation_path_matches(
2487                        self.module.symbol_path(arm.effect),
2488                        self.module.symbol_path(request.effect),
2489                    )
2490                })
2491        else {
2492            return Ok(ControlResult::Request(request));
2493        };
2494        let next_arm_index = arm_index + 1;
2495        let mut arm_env = env.clone();
2496        if let Some(guard) = arm.guard {
2497            self.profile.continuation_splits += 1;
2498            self.profile.continuation_split_frames += request.continuation.frames.len();
2499            let (outer, inner) = split_handle_continuations(&request.continuation, id);
2500            self.bind_pattern(&arm.payload, request.payload.clone(), &mut arm_env)?;
2501            insert_control_resume(&mut arm_env, arm.resume, inner);
2502            let previous = std::mem::replace(&mut self.guard_stack, handler_guard_stack.clone());
2503            let guard_result = self.eval_expr(guard, &arm_env);
2504            self.guard_stack = previous;
2505            return match guard_result? {
2506                ControlResult::Value(guard) => self.continue_handle_guard(
2507                    guard,
2508                    request,
2509                    outer,
2510                    id,
2511                    arms,
2512                    next_arm_index,
2513                    env.clone(),
2514                    handler_guard_stack.clone(),
2515                    arm_env,
2516                    arm.body,
2517                    result_wraps_thunk,
2518                ),
2519                ControlResult::Request(guard_request) => Ok(ControlResult::Request(push_frame(
2520                    guard_request,
2521                    ControlFrame::HandleGuard {
2522                        id,
2523                        request,
2524                        outer,
2525                        handler_guard_stack: handler_guard_stack.clone(),
2526                        arms,
2527                        next_arm_index,
2528                        env: env.clone(),
2529                        arm_env,
2530                        body: arm.body,
2531                        result_wraps_thunk,
2532                    },
2533                ))),
2534            };
2535        }
2536        let ControlRequest {
2537            payload,
2538            continuation,
2539            ..
2540        } = request;
2541        self.profile.continuation_splits += 1;
2542        self.profile.continuation_split_frames += continuation.frames.len();
2543        let (outer, inner) = split_handle_continuations_owned(continuation, id);
2544        self.bind_pattern(&arm.payload, payload, &mut arm_env)?;
2545        insert_control_resume(&mut arm_env, arm.resume, inner);
2546        let previous = std::mem::replace(&mut self.guard_stack, handler_guard_stack.clone());
2547        let result = self.eval_expr(arm.body, &arm_env);
2548        self.guard_stack = previous;
2549        let result = result?;
2550        self.continue_handle_result(result, outer, result_wraps_thunk)
2551    }
2552
2553    #[allow(clippy::too_many_arguments)]
2554    fn continue_handle_guard(
2555        &mut self,
2556        guard: ControlValue,
2557        request: ControlRequest,
2558        outer: ControlContinuation,
2559        id: u64,
2560        arms: ControlHandleArmsId,
2561        next_arm_index: usize,
2562        env: ControlEnv,
2563        handler_guard_stack: GuardStack,
2564        arm_env: ControlEnv,
2565        body: ExprId,
2566        result_wraps_thunk: bool,
2567    ) -> Result<ControlResult, VmError> {
2568        match guard {
2569            ControlValue::Bool(true) => {
2570                let previous =
2571                    std::mem::replace(&mut self.guard_stack, handler_guard_stack.clone());
2572                let result = self.eval_expr(body, &arm_env);
2573                self.guard_stack = previous;
2574                let result = result?;
2575                self.continue_handle_result(result, outer, result_wraps_thunk)
2576            }
2577            ControlValue::Bool(false) => self.handle_request(
2578                request,
2579                id,
2580                arms,
2581                next_arm_index,
2582                &env,
2583                &handler_guard_stack,
2584                result_wraps_thunk,
2585            ),
2586            other => Err(VmError::ExpectedBool(export_value_lossy(
2587                &other,
2588                Some(self.module),
2589            ))),
2590        }
2591    }
2592
2593    fn resume(
2594        &mut self,
2595        mut continuation: ControlContinuation,
2596        mut value: ControlValue,
2597    ) -> Result<ControlResult, VmError> {
2598        let previous = std::mem::replace(&mut self.guard_stack, continuation.guard_stack.clone());
2599        self.profile.max_continuation_frames = self
2600            .profile
2601            .max_continuation_frames
2602            .max(continuation.frames.len());
2603        let result = loop {
2604            let Some(frame) = continuation.frames.pop_back() else {
2605                break Ok(ControlResult::Value(value));
2606            };
2607            self.profile.continuation_steps += 1;
2608            self.profile.max_continuation_frames = self
2609                .profile
2610                .max_continuation_frames
2611                .max(continuation.frames.len());
2612            match self.apply_frame(frame, &mut continuation, value)? {
2613                ControlResult::Value(next) => value = next,
2614                ControlResult::Request(mut request) => {
2615                    self.prepend_frames(&mut request.continuation, continuation.frames);
2616                    break self.propagate_request(request);
2617                }
2618            }
2619        };
2620        self.guard_stack = previous;
2621        result
2622    }
2623
2624    fn apply_frame(
2625        &mut self,
2626        frame: ControlFrame,
2627        continuation: &mut ControlContinuation,
2628        value: ControlValue,
2629    ) -> Result<ControlResult, VmError> {
2630        match frame {
2631            ControlFrame::BindHere => self.bind_here(value),
2632            ControlFrame::ApplyCallee {
2633                arg,
2634                env,
2635                delay_arg,
2636            } => self.continue_apply_arg(value, arg, &env, delay_arg),
2637            ControlFrame::ApplyArg { callee } => self.apply(callee, value),
2638            ControlFrame::If {
2639                then_branch,
2640                else_branch,
2641                env,
2642            } => self.continue_if_value_frame(value, then_branch, else_branch, env),
2643            ControlFrame::Tuple {
2644                done,
2645                items,
2646                next_index,
2647                env,
2648            } => self.continue_tuple_item(done, items, next_index, env, value),
2649            ControlFrame::Select { field } => self.select_field(value, &field),
2650            ControlFrame::Match { arms, env } => self.eval_match(value, arms, &env),
2651            ControlFrame::Variant { tag } => {
2652                self.continue_variant_value(tag, ControlResult::Value(value))
2653            }
2654            ControlFrame::BlockLet {
2655                block,
2656                stmt_index,
2657                mut env,
2658            } => {
2659                let ControlStmt::Let { pattern, .. } = &self.module.block(block).stmts[stmt_index]
2660                else {
2661                    return Err(VmError::PatternMismatch);
2662                };
2663                self.bind_pattern(&pattern, value, &mut env)?;
2664                self.eval_block(block, stmt_index + 1, env)
2665            }
2666            ControlFrame::BlockExpr {
2667                block,
2668                next_index,
2669                env,
2670            } => self.continue_block_expr(value, block, next_index, env),
2671            ControlFrame::Handle {
2672                id,
2673                arms,
2674                env,
2675                guard_stack,
2676                result_wraps_thunk,
2677            } => match value {
2678                ControlValue::Thunk(thunk) => {
2679                    let result = self.bind_here(ControlValue::Thunk(thunk))?;
2680                    continuation.frames.push_back(ControlFrame::Handle {
2681                        id,
2682                        arms,
2683                        env,
2684                        guard_stack,
2685                        result_wraps_thunk,
2686                    });
2687                    Ok(result)
2688                }
2689                value => {
2690                    continuation.guard_stack = guard_stack;
2691                    self.handle_value(value, arms, &env, result_wraps_thunk)
2692                }
2693            },
2694            ControlFrame::HandleGuard {
2695                id,
2696                request,
2697                outer,
2698                handler_guard_stack,
2699                arms,
2700                next_arm_index,
2701                env,
2702                arm_env,
2703                body,
2704                result_wraps_thunk,
2705            } => self.continue_handle_guard(
2706                value,
2707                request,
2708                outer,
2709                id,
2710                arms,
2711                next_arm_index,
2712                env,
2713                handler_guard_stack,
2714                arm_env,
2715                body,
2716                result_wraps_thunk,
2717            ),
2718            ControlFrame::LocalPushId { parent } => {
2719                continuation.guard_stack = parent;
2720                Ok(ControlResult::Value(value))
2721            }
2722            ControlFrame::BlockedEffects { .. } => Ok(ControlResult::Value(value)),
2723            ControlFrame::Coerce { to } => Ok(ControlResult::Value(control_cast_value(value, &to))),
2724            ControlFrame::WrapThunkResult => {
2725                Ok(ControlResult::Value(control_wrap_value(value, true)))
2726            }
2727        }
2728    }
2729
2730    fn continue_result(
2731        &mut self,
2732        result: ControlResult,
2733        continuation: ControlContinuation,
2734    ) -> Result<ControlResult, VmError> {
2735        match result {
2736            ControlResult::Value(value) => self.resume(continuation, value),
2737            ControlResult::Request(mut request) => {
2738                self.prepend_frames(&mut request.continuation, continuation.frames);
2739                self.propagate_request(request)
2740            }
2741        }
2742    }
2743
2744    fn prepend_frames(
2745        &mut self,
2746        continuation: &mut ControlContinuation,
2747        mut frames: VecDeque<ControlFrame>,
2748    ) {
2749        self.profile.continuation_prepends += 1;
2750        self.profile.continuation_prepend_frames += frames.len();
2751        frames.append(&mut continuation.frames);
2752        continuation.frames = frames;
2753    }
2754
2755    fn force_handle_result(
2756        &mut self,
2757        result: ControlResult,
2758        result_wraps_thunk: bool,
2759    ) -> Result<ControlResult, VmError> {
2760        if result_wraps_thunk {
2761            return Ok(result);
2762        }
2763        match result {
2764            ControlResult::Value(ControlValue::Thunk(thunk)) => {
2765                self.bind_here(ControlValue::Thunk(thunk))
2766            }
2767            ControlResult::Request(request) => Ok(ControlResult::Request(push_frame(
2768                request,
2769                ControlFrame::BindHere,
2770            ))),
2771            other => Ok(other),
2772        }
2773    }
2774
2775    fn continue_handle_result(
2776        &mut self,
2777        result: ControlResult,
2778        mut continuation: ControlContinuation,
2779        result_wraps_thunk: bool,
2780    ) -> Result<ControlResult, VmError> {
2781        if result_wraps_thunk {
2782            return self.continue_result(result, continuation);
2783        }
2784        match result {
2785            ControlResult::Value(ControlValue::Thunk(thunk)) => {
2786                let result = self.bind_here(ControlValue::Thunk(thunk))?;
2787                self.continue_result(result, continuation)
2788            }
2789            ControlResult::Request(request) => {
2790                continuation.frames.push_back(ControlFrame::BindHere);
2791                self.continue_result(ControlResult::Request(request), continuation)
2792            }
2793            other => self.continue_result(other, continuation),
2794        }
2795    }
2796
2797    fn propagate_request(&mut self, request: ControlRequest) -> Result<ControlResult, VmError> {
2798        self.propagate_request_before(request, usize::MAX)
2799    }
2800
2801    fn propagate_request_before(
2802        &mut self,
2803        mut request: ControlRequest,
2804        before: usize,
2805    ) -> Result<ControlResult, VmError> {
2806        let end = before.min(request.continuation.frames.len());
2807        let Some(index) = request
2808            .continuation
2809            .frames
2810            .iter()
2811            .take(end)
2812            .rposition(|frame| {
2813                matches!(
2814                    frame,
2815                    ControlFrame::Handle { .. } | ControlFrame::BlockedEffects { .. }
2816                )
2817            })
2818        else {
2819            return Ok(ControlResult::Request(request));
2820        };
2821        if let ControlFrame::BlockedEffects { blocked, active } = request
2822            .continuation
2823            .frames
2824            .get(index)
2825            .expect("frame at propagated index")
2826            .clone()
2827        {
2828            request.continuation.frames.remove(index);
2829            request = if active {
2830                mark_control_request_with_active_blocked(self.module, request, &blocked)
2831            } else {
2832                mark_control_request_with_blocked(self.module, request, &blocked)
2833            };
2834            return self.propagate_request(request);
2835        }
2836        let ControlFrame::Handle {
2837            id,
2838            arms,
2839            env,
2840            guard_stack,
2841            result_wraps_thunk,
2842        } = request
2843            .continuation
2844            .frames
2845            .get(index)
2846            .expect("frame at propagated index")
2847            .clone()
2848        else {
2849            unreachable!();
2850        };
2851        match self.handle_request(request, id, arms, 0, &env, &guard_stack, result_wraps_thunk)? {
2852            ControlResult::Request(request) => self.propagate_request_before(request, index),
2853            value => Ok(value),
2854        }
2855    }
2856
2857    fn bind_pattern(
2858        &mut self,
2859        pattern: &ControlPattern,
2860        value: ControlValue,
2861        env: &mut ControlEnv,
2862    ) -> Result<(), VmError> {
2863        match pattern {
2864            ControlPattern::Wildcard => Ok(()),
2865            ControlPattern::Bind { local } => {
2866                env.insert(*local, value);
2867                Ok(())
2868            }
2869            ControlPattern::Lit { lit } if value == control_value_from_lit(lit) => Ok(()),
2870            ControlPattern::Lit { .. } => Err(VmError::PatternMismatch),
2871            ControlPattern::Tuple { items } => {
2872                let ControlValue::Tuple(values) = value else {
2873                    return Err(VmError::PatternMismatch);
2874                };
2875                if items.len() != values.len() {
2876                    return Err(VmError::PatternMismatch);
2877                }
2878                for (item, value) in items.iter().zip(values) {
2879                    self.bind_pattern(item, value, env)?;
2880                }
2881                Ok(())
2882            }
2883            ControlPattern::Variant {
2884                tag,
2885                value: pattern_value,
2886            } => {
2887                let ControlValue::Variant {
2888                    tag: actual,
2889                    value: actual_value,
2890                } = value
2891                else {
2892                    return Err(VmError::PatternMismatch);
2893                };
2894                if tag != &actual {
2895                    return Err(VmError::PatternMismatch);
2896                }
2897                match (pattern_value, actual_value) {
2898                    (Some(pattern), Some(value)) => self.bind_pattern(pattern, *value, env),
2899                    (None, None) => Ok(()),
2900                    _ => Err(VmError::PatternMismatch),
2901                }
2902            }
2903            ControlPattern::Or { left, right } => {
2904                let snapshot = env.clone();
2905                if self.bind_pattern(left, value.clone(), env).is_ok() {
2906                    return Ok(());
2907                }
2908                *env = snapshot;
2909                self.bind_pattern(right, value, env)
2910            }
2911            ControlPattern::As { pattern, local } => {
2912                self.bind_pattern(pattern, value.clone(), env)?;
2913                env.insert(*local, value);
2914                Ok(())
2915            }
2916            ControlPattern::Record { fields, spread } => {
2917                let ControlValue::Record(values) = value else {
2918                    return Err(VmError::PatternMismatch);
2919                };
2920                let mut rest = values.clone();
2921                for field in fields {
2922                    rest.remove(&field.name);
2923                    let Some(value) = values.get(&field.name).cloned() else {
2924                        let Some(default) = field.default else {
2925                            return Err(VmError::PatternMismatch);
2926                        };
2927                        let value = self.eval_value(default, env)?;
2928                        self.bind_pattern(&field.pattern, value, env)?;
2929                        continue;
2930                    };
2931                    self.bind_pattern(&field.pattern, value, env)?;
2932                }
2933                if let Some(spread) = spread {
2934                    let spread = match spread {
2935                        ControlRecordSpreadPattern::Head(pattern)
2936                        | ControlRecordSpreadPattern::Tail(pattern) => pattern,
2937                    };
2938                    self.bind_pattern(spread, ControlValue::Record(rest), env)?;
2939                }
2940                Ok(())
2941            }
2942            ControlPattern::List {
2943                prefix,
2944                spread,
2945                suffix,
2946            } => {
2947                let ControlValue::List(values) = value else {
2948                    return Err(VmError::PatternMismatch);
2949                };
2950                if values.len() < prefix.len() + suffix.len() {
2951                    return Err(VmError::PatternMismatch);
2952                }
2953                if spread.is_none() && values.len() != prefix.len() + suffix.len() {
2954                    return Err(VmError::PatternMismatch);
2955                }
2956                for (index, pattern) in prefix.iter().enumerate() {
2957                    let Some(value) = values.index(index) else {
2958                        return Err(VmError::PatternMismatch);
2959                    };
2960                    self.bind_pattern(pattern, (*value).clone(), env)?;
2961                }
2962                if let Some(spread) = spread {
2963                    let start = prefix.len();
2964                    let end = values.len() - suffix.len();
2965                    let Some(slice) = values.index_range(start, end) else {
2966                        return Err(VmError::PatternMismatch);
2967                    };
2968                    self.bind_pattern(spread, ControlValue::List(slice), env)?;
2969                }
2970                let suffix_start = values.len() - suffix.len();
2971                for (offset, pattern) in suffix.iter().enumerate() {
2972                    let Some(value) = values.index(suffix_start + offset) else {
2973                        return Err(VmError::PatternMismatch);
2974                    };
2975                    self.bind_pattern(pattern, (*value).clone(), env)?;
2976                }
2977                Ok(())
2978            }
2979        }
2980    }
2981
2982    fn eval_effect_id(&self, id: EffectIdRef) -> Result<u64, VmError> {
2983        match id {
2984            EffectIdRef::Peek => self.guard_stack.peek().ok_or(VmError::UnsupportedFindId),
2985            EffectIdRef::Var(var) => self
2986                .guard_stack
2987                .find_var(var)
2988                .or_else(|| self.guard_stack.peek())
2989                .ok_or(VmError::UnsupportedEffectIdVar(var.0)),
2990        }
2991    }
2992
2993    fn find_effect_id(&self, id: EffectIdRef) -> Result<bool, VmError> {
2994        let id = self.eval_effect_id(id)?;
2995        Ok(self.guard_stack.contains(id))
2996    }
2997
2998    fn fresh_guard_id(&mut self) -> u64 {
2999        let id = self.next_guard_id;
3000        self.next_guard_id += 1;
3001        id
3002    }
3003}
3004
3005fn split_handle_continuations(
3006    continuation: &ControlContinuation,
3007    id: u64,
3008) -> (ControlContinuation, ControlContinuation) {
3009    let Some(index) = continuation.frames.iter().rposition(
3010        |frame| matches!(frame, ControlFrame::Handle { id: current, .. } if *current == id),
3011    ) else {
3012        return (
3013            ControlContinuation {
3014                frames: VecDeque::new(),
3015                guard_stack: continuation.guard_stack.clone(),
3016            },
3017            ControlContinuation {
3018                frames: VecDeque::new(),
3019                guard_stack: continuation.guard_stack.clone(),
3020            },
3021        );
3022    };
3023
3024    let outer_guard_stack =
3025        if let ControlFrame::Handle { guard_stack, .. } = &continuation.frames[index] {
3026            guard_stack.clone()
3027        } else {
3028            continuation.guard_stack.clone()
3029        };
3030
3031    (
3032        ControlContinuation {
3033            frames: continuation.frames.iter().take(index).cloned().collect(),
3034            guard_stack: outer_guard_stack,
3035        },
3036        ControlContinuation {
3037            frames: continuation
3038                .frames
3039                .iter()
3040                .skip(index + 1)
3041                .cloned()
3042                .collect(),
3043            guard_stack: continuation.guard_stack.clone(),
3044        },
3045    )
3046}
3047
3048fn split_handle_continuations_owned(
3049    mut continuation: ControlContinuation,
3050    id: u64,
3051) -> (ControlContinuation, ControlContinuation) {
3052    let Some(index) = continuation.frames.iter().rposition(
3053        |frame| matches!(frame, ControlFrame::Handle { id: current, .. } if *current == id),
3054    ) else {
3055        return (
3056            ControlContinuation {
3057                frames: VecDeque::new(),
3058                guard_stack: continuation.guard_stack.clone(),
3059            },
3060            ControlContinuation {
3061                frames: VecDeque::new(),
3062                guard_stack: continuation.guard_stack,
3063            },
3064        );
3065    };
3066
3067    let inner_frames = continuation.frames.split_off(index + 1);
3068    let handle_frame = continuation
3069        .frames
3070        .pop_back()
3071        .expect("handle frame at split point");
3072    let outer_guard_stack = if let ControlFrame::Handle { guard_stack, .. } = handle_frame {
3073        guard_stack
3074    } else {
3075        continuation.guard_stack.clone()
3076    };
3077
3078    (
3079        ControlContinuation {
3080            frames: continuation.frames,
3081            guard_stack: outer_guard_stack,
3082        },
3083        ControlContinuation {
3084            frames: inner_frames,
3085            guard_stack: continuation.guard_stack,
3086        },
3087    )
3088}
3089
3090fn insert_control_resume(
3091    env: &mut ControlEnv,
3092    resume: Option<ControlLocalId>,
3093    continuation: ControlContinuation,
3094) {
3095    if let Some(resume) = resume {
3096        env.insert(
3097            resume,
3098            ControlValue::Resume(ControlHeap::new(ControlResume { continuation })),
3099        );
3100    }
3101}
3102
3103fn push_frame(mut request: ControlRequest, frame: ControlFrame) -> ControlRequest {
3104    request.continuation.frames.push_front(frame);
3105    request
3106}
3107
3108fn push_thunk_expr_frames(request: ControlRequest, thunk: &ControlThunk) -> ControlRequest {
3109    let request = push_frame(request, ControlFrame::BindHere);
3110    push_thunk_boundary_frame(request, thunk)
3111}
3112
3113fn push_thunk_boundary_frame(request: ControlRequest, thunk: &ControlThunk) -> ControlRequest {
3114    if thunk.blocked.is_empty() {
3115        return request;
3116    }
3117    push_frame(
3118        request,
3119        ControlFrame::BlockedEffects {
3120            blocked: thunk.blocked.clone(),
3121            active: thunk.blocked.iter().any(|blocked| blocked.active),
3122        },
3123    )
3124}
3125
3126fn mark_control_request_with_blocked(
3127    module: &ControlModule,
3128    mut request: ControlRequest,
3129    blocked_effects: &[BlockedEffect],
3130) -> ControlRequest {
3131    for blocked in blocked_effects {
3132        if effect_is_allowed(&blocked.allowed, module.symbol_path(request.effect)) {
3133            continue;
3134        }
3135        let has_live_blocker = control_request_has_live_blocker(&request);
3136        add_control_request_blocker(&mut request, blocked.guard_id, !has_live_blocker);
3137    }
3138    request
3139}
3140
3141fn mark_control_request_with_active_blocked(
3142    module: &ControlModule,
3143    mut request: ControlRequest,
3144    blocked_effects: &[BlockedEffect],
3145) -> ControlRequest {
3146    for blocked in blocked_effects.iter().rev() {
3147        if effect_is_allowed(&blocked.allowed, module.symbol_path(request.effect)) {
3148            continue;
3149        }
3150        let has_live_blocker = control_request_has_live_blocker(&request);
3151        add_control_request_blocker(&mut request, blocked.guard_id, !has_live_blocker);
3152    }
3153    request
3154}
3155
3156fn control_request_is_blocked_by_stack(request: &ControlRequest, stack: &GuardStack) -> bool {
3157    request
3158        .blocked_id
3159        .is_some_and(|blocked| stack.contains(blocked))
3160        || request
3161            .blocked_ids
3162            .iter()
3163            .any(|blocked| stack.contains(*blocked))
3164}
3165
3166fn add_control_request_blocker(request: &mut ControlRequest, guard_id: u64, replace_primary: bool) {
3167    if replace_primary {
3168        if let Some(previous) = request.blocked_id
3169            && previous != guard_id
3170            && !request.blocked_ids.contains(&previous)
3171        {
3172            request.blocked_ids.push(previous);
3173        }
3174        request.blocked_id = Some(guard_id);
3175    } else if request.blocked_id != Some(guard_id) && !request.blocked_ids.contains(&guard_id) {
3176        request.blocked_ids.push(guard_id);
3177    }
3178}
3179
3180fn control_request_has_live_blocker(request: &ControlRequest) -> bool {
3181    control_request_blocker_is_live(request, request.blocked_id)
3182        || request
3183            .blocked_ids
3184            .iter()
3185            .any(|blocked| control_request_blocker_is_live(request, Some(*blocked)))
3186}
3187
3188fn control_request_blocker_is_live(request: &ControlRequest, blocked: Option<u64>) -> bool {
3189    blocked.is_some_and(|blocked| {
3190        request.continuation.guard_stack.contains(blocked)
3191            || request.continuation.frames.iter().any(|frame| match frame {
3192                ControlFrame::Handle { guard_stack, .. } => guard_stack.contains(blocked),
3193                ControlFrame::HandleGuard {
3194                    handler_guard_stack,
3195                    ..
3196                } => handler_guard_stack.contains(blocked),
3197                _ => false,
3198            })
3199    })
3200}
3201
3202fn make_recursive_local_value(pattern: &ControlPattern, value: ControlValue) -> ControlValue {
3203    let Some(local) = single_bind_local(pattern) else {
3204        return value;
3205    };
3206    let ControlValue::Closure(closure) = value else {
3207        return value;
3208    };
3209    let mut closure = (*closure).clone();
3210    closure.self_name = Some(local);
3211    ControlValue::Closure(ControlHeap::new(closure))
3212}
3213
3214fn single_bind_local(pattern: &ControlPattern) -> Option<ControlLocalId> {
3215    match pattern {
3216        ControlPattern::Bind { local } => Some(*local),
3217        ControlPattern::As { local, .. } => Some(*local),
3218        _ => None,
3219    }
3220}
3221
3222fn control_lambda_shape(
3223    lambda_ty: &Type,
3224    body_ty: &Type,
3225    param_effect_annotation: Option<&typed_ir::ParamEffectAnnotation>,
3226) -> (bool, bool) {
3227    match lambda_ty {
3228        Type::Fun { param, ret } => (
3229            param_effect_annotation.is_none() && control_param_forces_thunk_arg(param),
3230            type_wraps_thunk(ret.as_ref()),
3231        ),
3232        _ => (false, type_wraps_thunk(body_ty)),
3233    }
3234}
3235
3236fn control_param_forces_thunk_arg(param_ty: &Type) -> bool {
3237    !matches!(
3238        param_ty,
3239        Type::Thunk { .. } | Type::Value(typed_ir::Type::Any)
3240    )
3241}
3242
3243fn type_wraps_thunk(ty: &Type) -> bool {
3244    matches!(ty, Type::Thunk { .. })
3245}
3246
3247fn control_wrap_result(result: ControlResult, result_wraps_thunk: bool) -> ControlResult {
3248    if !result_wraps_thunk {
3249        return result;
3250    }
3251    match result {
3252        ControlResult::Value(value) => ControlResult::Value(control_wrap_value(value, true)),
3253        ControlResult::Request(request) => {
3254            ControlResult::Request(push_frame(request, ControlFrame::WrapThunkResult))
3255        }
3256    }
3257}
3258
3259fn control_wrap_value(value: ControlValue, result_wraps_thunk: bool) -> ControlValue {
3260    if !result_wraps_thunk || matches!(value, ControlValue::Thunk(_)) {
3261        return value;
3262    }
3263    ControlValue::Thunk(ControlHeap::new(ControlThunk {
3264        body: ControlThunkBody::Value(value),
3265        env: ControlEnv::new(),
3266        guard_stack: GuardStack::default(),
3267        blocked: Vec::new(),
3268    }))
3269}
3270
3271fn control_value_from_lit(lit: &typed_ir::Lit) -> ControlValue {
3272    match lit {
3273        typed_ir::Lit::Int(value) => ControlValue::Int(ControlInt::from_lit(value)),
3274        typed_ir::Lit::Float(value) => ControlValue::Float(value.clone()),
3275        typed_ir::Lit::String(value) => ControlValue::String(StringTree::from_str(value)),
3276        typed_ir::Lit::Bool(value) => ControlValue::Bool(*value),
3277        typed_ir::Lit::Unit => ControlValue::Unit,
3278    }
3279}
3280
3281fn control_cast_value(value: ControlValue, expected: &typed_ir::Type) -> ControlValue {
3282    if is_float_type(expected) {
3283        return match value {
3284            ControlValue::Int(value) => ControlValue::Float(value.to_float_string()),
3285            value => value,
3286        };
3287    }
3288    if is_path_type(expected) {
3289        return match value {
3290            ControlValue::String(value) => {
3291                ControlValue::Path(Rc::new(PathBuf::from(value.to_flat_string())))
3292            }
3293            value => value,
3294        };
3295    }
3296    value
3297}
3298
3299fn control_apply_primitive(
3300    op: typed_ir::PrimitiveOp,
3301    args: &[ControlValue],
3302) -> Result<ControlValue, VmError> {
3303    match op {
3304        typed_ir::PrimitiveOp::YadaYada => Err(VmError::YadaYada),
3305        typed_ir::PrimitiveOp::BoolNot => Ok(ControlValue::Bool(!control_bool_value(&args[0])?)),
3306        typed_ir::PrimitiveOp::BoolEq => Ok(ControlValue::Bool(
3307            control_bool_value(&args[0])? == control_bool_value(&args[1])?,
3308        )),
3309        typed_ir::PrimitiveOp::IntAdd => Ok(ControlValue::Int(
3310            control_int_value(&args[0])?.add(control_int_value(&args[1])?),
3311        )),
3312        typed_ir::PrimitiveOp::IntSub => Ok(ControlValue::Int(
3313            control_int_value(&args[0])?.sub(control_int_value(&args[1])?),
3314        )),
3315        typed_ir::PrimitiveOp::IntMul => Ok(ControlValue::Int(
3316            control_int_value(&args[0])?.mul(control_int_value(&args[1])?),
3317        )),
3318        typed_ir::PrimitiveOp::IntDiv => Ok(ControlValue::Int(
3319            control_int_value(&args[0])?.div(control_int_value(&args[1])?),
3320        )),
3321        typed_ir::PrimitiveOp::IntMod => Ok(ControlValue::Int(
3322            control_int_value(&args[0])?.rem(control_int_value(&args[1])?),
3323        )),
3324        typed_ir::PrimitiveOp::IntEq => Ok(ControlValue::Bool(
3325            control_int_value(&args[0])? == control_int_value(&args[1])?,
3326        )),
3327        typed_ir::PrimitiveOp::IntLt => Ok(ControlValue::Bool(
3328            control_int_value(&args[0])?
3329                .cmp(control_int_value(&args[1])?)
3330                .is_lt(),
3331        )),
3332        typed_ir::PrimitiveOp::IntLe => Ok(ControlValue::Bool(
3333            !control_int_value(&args[0])?
3334                .cmp(control_int_value(&args[1])?)
3335                .is_gt(),
3336        )),
3337        typed_ir::PrimitiveOp::IntGt => Ok(ControlValue::Bool(
3338            control_int_value(&args[0])?
3339                .cmp(control_int_value(&args[1])?)
3340                .is_gt(),
3341        )),
3342        typed_ir::PrimitiveOp::IntGe => Ok(ControlValue::Bool(
3343            !control_int_value(&args[0])?
3344                .cmp(control_int_value(&args[1])?)
3345                .is_lt(),
3346        )),
3347        typed_ir::PrimitiveOp::StringLen => Ok(ControlValue::Int(ControlInt::Small(
3348            control_string_value(&args[0])?.len() as i64,
3349        ))),
3350        typed_ir::PrimitiveOp::StringConcat => Ok(ControlValue::String(StringTree::concat(
3351            control_string_value(&args[0])?.clone(),
3352            control_string_value(&args[1])?.clone(),
3353        ))),
3354        typed_ir::PrimitiveOp::IntToString => Ok(ControlValue::String(StringTree::from(
3355            control_int_value(&args[0])?.to_vm_string(),
3356        ))),
3357        typed_ir::PrimitiveOp::IntToHex => Ok(ControlValue::String(StringTree::from(
3358            control_int_value(&args[0])?.to_hex_string(false),
3359        ))),
3360        typed_ir::PrimitiveOp::IntToUpperHex => Ok(ControlValue::String(StringTree::from(
3361            control_int_value(&args[0])?.to_hex_string(true),
3362        ))),
3363        typed_ir::PrimitiveOp::FloatToString => Ok(ControlValue::String(StringTree::from(
3364            format_float_value(control_float_value(&args[0])?),
3365        ))),
3366        typed_ir::PrimitiveOp::BoolToString => Ok(ControlValue::String(StringTree::from(
3367            control_bool_value(&args[0])?.to_string(),
3368        ))),
3369        typed_ir::PrimitiveOp::CharToString => Ok(ControlValue::String(StringTree::from(
3370            control_grapheme_value(&args[0])?,
3371        ))),
3372        typed_ir::PrimitiveOp::ListEmpty => Ok(ControlValue::List(ListTree::empty())),
3373        typed_ir::PrimitiveOp::ListSingleton => Ok(ControlValue::List(ListTree::singleton(
3374            Rc::new(args[0].clone()),
3375        ))),
3376        typed_ir::PrimitiveOp::ListLen => Ok(ControlValue::Int(ControlInt::Small(
3377            control_list_value(&args[0])?.len() as i64,
3378        ))),
3379        typed_ir::PrimitiveOp::ListMerge => {
3380            let left = control_list_value(&args[0])?;
3381            let right = control_list_value(&args[1])?;
3382            Ok(ControlValue::List(ListTree::concat(
3383                left.clone(),
3384                right.clone(),
3385            )))
3386        }
3387        typed_ir::PrimitiveOp::ListIndex => {
3388            let list = control_list_value(&args[0])?;
3389            let index = usize::try_from(control_int_value(&args[1])?.as_i64()?)
3390                .map_err(|_| VmError::ExpectedInt(export_value_lossy(&args[1], None)))?;
3391            list.index(index)
3392                .map(|value| (*value).clone())
3393                .ok_or_else(|| VmError::ExpectedList(export_value_lossy(&args[0], None)))
3394        }
3395        typed_ir::PrimitiveOp::ListIndexRangeRaw => {
3396            let list = control_list_value(&args[0])?;
3397            let start = usize::try_from(control_int_value(&args[1])?.as_i64()?)
3398                .map_err(|_| VmError::ExpectedInt(export_value_lossy(&args[1], None)))?;
3399            let end = usize::try_from(control_int_value(&args[2])?.as_i64()?)
3400                .map_err(|_| VmError::ExpectedInt(export_value_lossy(&args[2], None)))?;
3401            list.index_range(start, end)
3402                .map(ControlValue::List)
3403                .ok_or_else(|| VmError::ExpectedList(export_value_lossy(&args[0], None)))
3404        }
3405        typed_ir::PrimitiveOp::ListSpliceRaw => {
3406            let list = control_list_value(&args[0])?;
3407            let start = usize::try_from(control_int_value(&args[1])?.as_i64()?)
3408                .map_err(|_| VmError::ExpectedInt(export_value_lossy(&args[1], None)))?;
3409            let end = usize::try_from(control_int_value(&args[2])?.as_i64()?)
3410                .map_err(|_| VmError::ExpectedInt(export_value_lossy(&args[2], None)))?;
3411            let insert = control_list_value(&args[3])?;
3412            list.splice(start, end, insert.clone())
3413                .map(ControlValue::List)
3414                .ok_or_else(|| VmError::ExpectedList(export_value_lossy(&args[0], None)))
3415        }
3416        typed_ir::PrimitiveOp::ListViewRaw => match control_list_value(&args[0])?.view() {
3417            ListView::Empty => Ok(ControlValue::Variant {
3418                tag: typed_ir::Name("empty".to_string()),
3419                value: None,
3420            }),
3421            ListView::Leaf(single) => Ok(ControlValue::Variant {
3422                tag: typed_ir::Name("leaf".to_string()),
3423                value: Some(Box::new((*single).clone())),
3424            }),
3425            ListView::Node { left, right, .. } => Ok(ControlValue::Variant {
3426                tag: typed_ir::Name("node".to_string()),
3427                value: Some(Box::new(ControlValue::Tuple(vec![
3428                    ControlValue::List(left),
3429                    ControlValue::List(right),
3430                ]))),
3431            }),
3432        },
3433        _ => apply_primitive(
3434            op,
3435            &args
3436                .iter()
3437                .map(|value| export_value(value, None))
3438                .collect::<Result<Vec<_>, _>>()?,
3439        )
3440        .and_then(|value| import_value(&value)),
3441    }
3442}
3443
3444fn control_int_value(value: &ControlValue) -> Result<&ControlInt, VmError> {
3445    match value {
3446        ControlValue::Int(value) => Ok(value),
3447        other => Err(VmError::ExpectedInt(export_value_lossy(other, None))),
3448    }
3449}
3450
3451fn control_bool_value(value: &ControlValue) -> Result<bool, VmError> {
3452    match value {
3453        ControlValue::Bool(value) => Ok(*value),
3454        other => Err(VmError::ExpectedBool(export_value_lossy(other, None))),
3455    }
3456}
3457
3458fn control_float_value(value: &ControlValue) -> Result<f64, VmError> {
3459    match value {
3460        ControlValue::Float(value) => value
3461            .parse()
3462            .map_err(|_| VmError::ExpectedFloat(VmValue::Float(value.clone()))),
3463        other => Err(VmError::ExpectedFloat(export_value_lossy(other, None))),
3464    }
3465}
3466
3467fn control_list_value(value: &ControlValue) -> Result<&ListTree<Rc<ControlValue>>, VmError> {
3468    match value {
3469        ControlValue::List(value) => Ok(value),
3470        other => Err(VmError::ExpectedList(export_value_lossy(other, None))),
3471    }
3472}
3473
3474fn control_string_value(value: &ControlValue) -> Result<&StringTree, VmError> {
3475    match value {
3476        ControlValue::String(value) => Ok(value),
3477        other => Err(VmError::ExpectedString(export_value_lossy(other, None))),
3478    }
3479}
3480
3481fn control_grapheme_value(value: &ControlValue) -> Result<String, VmError> {
3482    match value {
3483        ControlValue::String(value) if value.len() == 1 => Ok(value.to_flat_string()),
3484        other => Err(VmError::ExpectedChar(export_value_lossy(other, None))),
3485    }
3486}
3487
3488fn export_value(value: &ControlValue, module: Option<&ControlModule>) -> Result<VmValue, VmError> {
3489    Ok(match value {
3490        ControlValue::Int(value) => VmValue::Int(value.to_vm_string()),
3491        ControlValue::Float(value) => VmValue::Float(value.clone()),
3492        ControlValue::String(value) => VmValue::String(value.clone()),
3493        ControlValue::Bytes(value) => VmValue::Bytes(value.clone()),
3494        ControlValue::Path(value) => VmValue::Path(value.clone()),
3495        ControlValue::FileHandle(value) => VmValue::FileHandle(value.clone()),
3496        ControlValue::Bool(value) => VmValue::Bool(*value),
3497        ControlValue::Unit => VmValue::Unit,
3498        ControlValue::List(value) => {
3499            let mut items = Vec::with_capacity(value.len());
3500            value.for_each_ref(&mut |item| {
3501                items.push(Rc::new(export_value_lossy(item, module)));
3502            });
3503            VmValue::List(ListTree::from_items(items))
3504        }
3505        ControlValue::Tuple(items) => VmValue::Tuple(
3506            items
3507                .iter()
3508                .map(|value| export_value(value, module))
3509                .collect::<Result<Vec<_>, _>>()?,
3510        ),
3511        ControlValue::Record(fields) => VmValue::Record(
3512            fields
3513                .iter()
3514                .map(|(name, value)| Ok((name.clone(), export_value(value, module)?)))
3515                .collect::<Result<BTreeMap<_, _>, VmError>>()?,
3516        ),
3517        ControlValue::Variant { tag, value } => VmValue::Variant {
3518            tag: tag.clone(),
3519            value: value
3520                .as_ref()
3521                .map(|value| export_value(value, module).map(Box::new))
3522                .transpose()?,
3523        },
3524        ControlValue::EffectOp(symbol) => VmValue::EffectOp(
3525            module
3526                .map(|module| module.symbol_path(*symbol).clone())
3527                .unwrap_or_default(),
3528        ),
3529        ControlValue::PrimitiveOp(primitive) => VmValue::PrimitiveOp(Rc::new(VmPrimitive {
3530            op: primitive.op,
3531            args: primitive
3532                .args
3533                .iter()
3534                .map(|value| export_value(value, module))
3535                .collect::<Result<Vec<_>, _>>()?,
3536        })),
3537        ControlValue::EffectId(id) => VmValue::EffectId(*id),
3538        ControlValue::Closure(_) | ControlValue::Thunk(_) | ControlValue::Resume(_) => {
3539            return Err(VmError::ExpectedList(VmValue::Unit));
3540        }
3541    })
3542}
3543
3544fn export_value_lossy(value: &ControlValue, module: Option<&ControlModule>) -> VmValue {
3545    export_value(value, module).unwrap_or(VmValue::Unit)
3546}
3547
3548fn import_value(value: &VmValue) -> Result<ControlValue, VmError> {
3549    Ok(match value {
3550        VmValue::Int(value) => ControlValue::Int(ControlInt::from_text(value.clone())?),
3551        VmValue::Float(value) => ControlValue::Float(value.clone()),
3552        VmValue::String(value) => ControlValue::String(value.clone()),
3553        VmValue::Bytes(value) => ControlValue::Bytes(value.clone()),
3554        VmValue::Path(value) => ControlValue::Path(value.clone()),
3555        VmValue::FileHandle(value) => ControlValue::FileHandle(value.clone()),
3556        VmValue::Bool(value) => ControlValue::Bool(*value),
3557        VmValue::Unit => ControlValue::Unit,
3558        VmValue::List(value) => {
3559            let mut items = Vec::with_capacity(value.len());
3560            value.for_each_ref(&mut |item| {
3561                items.push(Rc::new(import_value(item).unwrap_or(ControlValue::Unit)));
3562            });
3563            ControlValue::List(ListTree::from_items(items))
3564        }
3565        VmValue::Tuple(items) => ControlValue::Tuple(
3566            items
3567                .iter()
3568                .map(import_value)
3569                .collect::<Result<Vec<_>, _>>()?,
3570        ),
3571        VmValue::Record(fields) => ControlValue::Record(
3572            fields
3573                .iter()
3574                .map(|(name, value)| Ok((name.clone(), import_value(value)?)))
3575                .collect::<Result<BTreeMap<_, _>, VmError>>()?,
3576        ),
3577        VmValue::Variant { tag, value } => ControlValue::Variant {
3578            tag: tag.clone(),
3579            value: value
3580                .as_ref()
3581                .map(|value| import_value(value).map(Box::new))
3582                .transpose()?,
3583        },
3584        VmValue::EffectId(id) => ControlValue::EffectId(*id),
3585        VmValue::EffectOp(_) => return Err(VmError::ExpectedClosure(value.clone())),
3586        VmValue::PrimitiveOp(primitive) => {
3587            ControlValue::PrimitiveOp(ControlHeap::new(ControlPrimitive {
3588                op: primitive.op,
3589                args: primitive
3590                    .args
3591                    .iter()
3592                    .map(import_value)
3593                    .collect::<Result<Vec<_>, _>>()?,
3594            }))
3595        }
3596        VmValue::Closure(_) | VmValue::Thunk(_) | VmValue::Resume(_) => {
3597            return Err(VmError::ExpectedList(VmValue::Unit));
3598        }
3599    })
3600}
3601
3602impl PartialEq for ControlValue {
3603    fn eq(&self, other: &Self) -> bool {
3604        match (self, other) {
3605            (Self::Int(left), Self::Int(right)) => left == right,
3606            (Self::Float(left), Self::Float(right)) => left == right,
3607            (Self::String(left), Self::String(right)) => left == right,
3608            (Self::Bytes(left), Self::Bytes(right)) => left == right,
3609            (Self::Path(left), Self::Path(right)) => left == right,
3610            (Self::FileHandle(left), Self::FileHandle(right)) => left == right,
3611            (Self::Bool(left), Self::Bool(right)) => left == right,
3612            (Self::Unit, Self::Unit) => true,
3613            (
3614                Self::Variant {
3615                    tag: left_tag,
3616                    value: left_value,
3617                },
3618                Self::Variant {
3619                    tag: right_tag,
3620                    value: right_value,
3621                },
3622            ) => left_tag == right_tag && left_value == right_value,
3623            (Self::Tuple(left), Self::Tuple(right)) => left == right,
3624            _ => false,
3625        }
3626    }
3627}
3628
3629#[cfg(test)]
3630mod tests {
3631    use super::*;
3632
3633    #[test]
3634    fn split_handle_continuations_uses_innermost_duplicate_handler_id() {
3635        let continuation = ControlContinuation {
3636            frames: VecDeque::from(vec![
3637                handle_frame(2),
3638                handle_frame(5),
3639                handle_frame(2),
3640                ControlFrame::BindHere,
3641            ]),
3642            guard_stack: GuardStack::default(),
3643        };
3644
3645        let (outer, inner) = split_handle_continuations(&continuation, 2);
3646
3647        assert_eq!(outer.frames.len(), 2);
3648        assert!(matches!(
3649            outer.frames.get(0),
3650            Some(ControlFrame::Handle { id: 2, .. })
3651        ));
3652        assert!(matches!(
3653            outer.frames.get(1),
3654            Some(ControlFrame::Handle { id: 5, .. })
3655        ));
3656        assert_eq!(inner.frames.len(), 1);
3657        assert!(matches!(inner.frames.front(), Some(ControlFrame::BindHere)));
3658    }
3659
3660    fn handle_frame(id: u64) -> ControlFrame {
3661        ControlFrame::Handle {
3662            id,
3663            arms: ControlHandleArmsId(0),
3664            env: ControlEnv::new(),
3665            guard_stack: GuardStack::default(),
3666            result_wraps_thunk: false,
3667        }
3668    }
3669}