sim_lib_control/
nonlocal.rs1use sim_kernel::{
2 Cx, Error, Ref, Result, Symbol,
3 control::{ControlAbort, abort, default_control_result_shape},
4};
5
6use crate::ControlResultValue;
7
8#[derive(Clone, Copy, Debug, PartialEq, Eq)]
10pub enum NonLocalExitKind {
11 Break,
13 Next,
15 Return,
17}
18
19#[derive(Clone, Debug, PartialEq, Eq)]
24pub struct LabeledPrompt {
25 label: Symbol,
26 prompt: Ref,
27}
28
29impl LabeledPrompt {
30 pub fn new(label: Symbol, prompt: Ref) -> Self {
32 Self { label, prompt }
33 }
34
35 pub fn label(&self) -> &Symbol {
37 &self.label
38 }
39
40 pub fn prompt(&self) -> &Ref {
42 &self.prompt
43 }
44}
45
46#[derive(Clone, Debug, PartialEq, Eq)]
51pub struct NonLocalExit {
52 kind: NonLocalExitKind,
53 label: Symbol,
54 value: Ref,
55}
56
57impl NonLocalExit {
58 pub fn new(kind: NonLocalExitKind, label: Symbol, value: Ref) -> Self {
61 Self { kind, label, value }
62 }
63
64 pub fn break_to(label: Symbol, value: Ref) -> Self {
66 Self::new(NonLocalExitKind::Break, label, value)
67 }
68
69 pub fn next_to(label: Symbol, value: Ref) -> Self {
71 Self::new(NonLocalExitKind::Next, label, value)
72 }
73
74 pub fn return_to(label: Symbol, value: Ref) -> Self {
76 Self::new(NonLocalExitKind::Return, label, value)
77 }
78
79 pub fn kind(&self) -> NonLocalExitKind {
81 self.kind
82 }
83
84 pub fn label(&self) -> &Symbol {
86 &self.label
87 }
88
89 pub fn value(&self) -> &Ref {
91 &self.value
92 }
93}
94
95pub fn escape_to_label(
101 cx: &mut Cx,
102 prompts: &[LabeledPrompt],
103 exit: NonLocalExit,
104) -> Result<ControlResultValue> {
105 let prompt = prompts
106 .iter()
107 .rev()
108 .find(|prompt| prompt.label() == exit.label())
109 .ok_or_else(|| Error::Eval(format!("no labeled prompt for {}", exit.label())))?;
110 let result = abort(
111 cx,
112 ControlAbort::new(
113 prompt.prompt().clone(),
114 exit.value().clone(),
115 default_control_result_shape(),
116 ),
117 )?;
118 Ok(ControlResultValue::new(result))
119}