Skip to main content

sim_lib_lang_ruby/
runtime.rs

1use sim_kernel::{Cx, Ref, Result, Symbol};
2use sim_lib_control::{ControlResultValue, LabeledPrompt, NonLocalExit, escape_to_label};
3
4/// A labeled Ruby block scope targeted by `break` and `next` exits.
5///
6/// Lowers Ruby block control onto the control organ's labeled-prompt contract:
7/// the scope pairs a label with the control prompt that bounds it.
8#[derive(Clone, Debug, PartialEq, Eq)]
9pub struct RubyBlockScope {
10    label: Symbol,
11    prompt: Ref,
12}
13
14impl RubyBlockScope {
15    /// Creates a block scope for `label`, deriving its control prompt.
16    pub fn new(label: Symbol) -> Self {
17        let prompt = Ref::Symbol(Symbol::qualified("ruby/block-prompt", label.to_string()));
18        Self { label, prompt }
19    }
20
21    /// Returns the scope's label.
22    pub fn label(&self) -> &Symbol {
23        &self.label
24    }
25
26    /// Returns the control prompt that bounds this scope.
27    pub fn prompt(&self) -> &Ref {
28        &self.prompt
29    }
30
31    /// Returns the [`LabeledPrompt`] pairing this scope's label and prompt.
32    pub fn labeled_prompt(&self) -> LabeledPrompt {
33        LabeledPrompt::new(self.label.clone(), self.prompt.clone())
34    }
35}
36
37/// Performs a Ruby `break`, escaping the block scope with `value`.
38///
39/// Delegates to the control organ's labeled non-local exit rather than defining
40/// bespoke control behavior.
41pub fn ruby_break(cx: &mut Cx, scope: &RubyBlockScope, value: Ref) -> Result<ControlResultValue> {
42    escape_to_label(
43        cx,
44        &[scope.labeled_prompt()],
45        NonLocalExit::break_to(scope.label.clone(), value),
46    )
47}
48
49/// Performs a Ruby `next`, advancing the block scope with `value`.
50///
51/// Delegates to the control organ's labeled non-local exit rather than defining
52/// bespoke control behavior.
53pub fn ruby_next(cx: &mut Cx, scope: &RubyBlockScope, value: Ref) -> Result<ControlResultValue> {
54    escape_to_label(
55        cx,
56        &[scope.labeled_prompt()],
57        NonLocalExit::next_to(scope.label.clone(), value),
58    )
59}