-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcontrol.rs
More file actions
108 lines (99 loc) · 3.18 KB
/
Copy pathcontrol.rs
File metadata and controls
108 lines (99 loc) · 3.18 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
//! Control-flow handlers (`if`, `if_else`, `return`, `stop`).
//!
//! `if`/`if_else` execute branch nodes via runtime callbacks and forward their resulting signals.
//! This is required for block-style return semantics where `return` exits only the current call frame.
use crate::handler::argument::Argument;
use crate::handler::argument::ParameterNode::{Eager, Lazy};
use crate::handler::macros::args;
use crate::handler::registry::FunctionRegistration;
use crate::runtime::execution::value_store::ValueStore;
use crate::types::errors::runtime_error::RuntimeError;
use crate::types::signal::Signal;
use tucana::shared::Value;
use tucana::shared::value::Kind;
pub(crate) const FUNCTIONS: &[FunctionRegistration] = &[
FunctionRegistration::eager("std::control::stop", stop, 0),
FunctionRegistration::eager("std::control::return", r#return, 1),
FunctionRegistration::eager("std::control::value", value, 1),
FunctionRegistration::modes("std::control::if", r#if, &[Eager, Lazy]),
FunctionRegistration::modes("std::control::if_else", if_else, &[Eager, Lazy, Lazy]),
];
fn stop(
_args: &[Argument],
_ctx: &mut ValueStore,
_run: &mut dyn FnMut(i64, &mut ValueStore) -> Signal,
) -> Signal {
Signal::Stop
}
fn value(
args: &[Argument],
_ctx: &mut ValueStore,
_run: &mut dyn FnMut(i64, &mut ValueStore) -> Signal,
) -> Signal {
args!(args => value: Value);
Signal::Success(value)
}
fn r#return(
args: &[Argument],
_ctx: &mut ValueStore,
_run: &mut dyn FnMut(i64, &mut ValueStore) -> Signal,
) -> Signal {
args!(args => value: Value);
// The executor decides how far this return unwinds (one frame).
Signal::Return(value)
}
fn r#if(
args: &[Argument],
ctx: &mut ValueStore,
run: &mut dyn FnMut(i64, &mut ValueStore) -> Signal,
) -> Signal {
let [
Argument::Eval(Value {
kind: Some(Kind::BoolValue(bool)),
}),
Argument::Thunk(if_pointer),
] = args
else {
return Signal::Failure(RuntimeError::new(
"T-STD-00001",
"InvalidArgumentRuntimeError",
format!("Expected a bool value but received {:?}", args),
));
};
if *bool {
// Branch execution is delegated to the executor through `run`.
ctx.push_runtime_trace_label("branch=if".to_string());
run(*if_pointer, ctx)
} else {
Signal::Success(Value {
kind: Some(Kind::NullValue(0)),
})
}
}
fn if_else(
args: &[Argument],
ctx: &mut ValueStore,
run: &mut dyn FnMut(i64, &mut ValueStore) -> Signal,
) -> Signal {
let [
Argument::Eval(Value {
kind: Some(Kind::BoolValue(bool)),
}),
Argument::Thunk(if_pointer),
Argument::Thunk(else_pointer),
] = args
else {
return Signal::Failure(RuntimeError::new(
"T-STD-00001",
"InvalidArgumentRuntimeError",
format!("Expected a bool value but received {:?}", args),
));
};
if *bool {
ctx.push_runtime_trace_label("branch=if".to_string());
run(*if_pointer, ctx)
} else {
ctx.push_runtime_trace_label("branch=else".to_string());
run(*else_pointer, ctx)
}
}