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(¶m);
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}