Skip to content

Commit 603b264

Browse files
committed
feat: wip added Lazy and Eager functions to ìmplement if-else logic
1 parent ef0e5c6 commit 603b264

File tree

7 files changed

+160
-128
lines changed

7 files changed

+160
-128
lines changed

src/context/argument.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
#[derive(Clone, Debug)]
2+
pub enum Argument {
3+
// Eval => Evaluated Value
4+
// - can be consumed directly by a function
5+
Eval(tucana::shared::Value),
6+
// Thunk of NodeFunction identifier
7+
// - used for lazy execution of nodes
8+
Thunk(i64)
9+
}
10+
11+
#[derive(Clone, Copy, Debug)]
12+
pub enum ParameterNode {
13+
Eager,
14+
Lazy
15+
}

src/context/executor.rs

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
use crate::context::Context;
2+
use crate::context::signal::Signal;
3+
use crate::error::RuntimeError;
4+
use std::collections::HashMap;
5+
use tucana::shared::{NodeFunction, NodeParameter};
6+
use crate::context::argument::{Argument, ParameterNode};
7+
use crate::context::registry::FunctionStore;
8+
9+
pub struct Executor<'a> {
10+
functions: &'a FunctionStore,
11+
nodes: HashMap<i64, NodeFunction>,
12+
context: Context,
13+
}
14+
15+
type HandleNodeParameterFn = fn(&mut Executor, node_parameter: &NodeParameter) -> Signal;
16+
17+
impl<'a> Executor<'a> {
18+
pub fn new(
19+
functions: &'a FunctionStore,
20+
nodes: HashMap<i64, NodeFunction>,
21+
context: Context,
22+
) -> Self {
23+
Executor {
24+
functions,
25+
nodes,
26+
context,
27+
}
28+
}
29+
30+
pub fn execute(&mut self, starting_node_id: i64) -> Signal {
31+
let mut current_node_id = starting_node_id;
32+
33+
loop {
34+
let node = match self.nodes.get(&current_node_id) {
35+
None => {
36+
return Signal::Failure(RuntimeError::simple_str(
37+
"NodeNotFound",
38+
"The node with the id was not found",
39+
));
40+
}
41+
Some(n) => n.clone(),
42+
};
43+
44+
45+
let entry = match self.functions.get(node.runtime_function_id.as_str()) {
46+
None => {
47+
return Signal::Failure(RuntimeError::simple_str("FunctionNotFound","The function was not found"))
48+
},
49+
Some(f) => f,
50+
};
51+
52+
let mut args: Vec<Argument> = Vec::with_capacity(node.parameters.len());
53+
for parameter in &node.parameters {
54+
let node_value = match &parameter.value {
55+
Some(v) => v,
56+
None => return Signal::Failure(RuntimeError::simple_str("NodeValueNotFound","Missing parameter value")),
57+
};
58+
let value = match &node_value.value {
59+
Some(v) => v,
60+
None => return Signal::Failure(RuntimeError::simple_str("NodeValueNotFound","Missing inner value")),
61+
};
62+
63+
match value {
64+
tucana::shared::node_value::Value::LiteralValue(val) => {
65+
args.push(Argument::Eval(val.clone()))
66+
}
67+
tucana::shared::node_value::Value::ReferenceValue(_r) => {
68+
unimplemented!("ReferenceValue")
69+
}
70+
tucana::shared::node_value::Value::NodeFunctionId(id) => {
71+
args.push(Argument::Thunk(*id))
72+
}
73+
}
74+
}
75+
76+
77+
// Eagerly evaluate args that the function *declares* as Eager
78+
for (i, a) in args.iter_mut().enumerate() {
79+
let mode = entry.param_modes.get(i).copied().unwrap_or(ParameterNode::Eager);
80+
if matches!(mode, ParameterNode::Eager) {
81+
if let Argument::Thunk(id) = *a {
82+
match self.execute(id) {
83+
Signal::Success(v) => *a = Argument::Eval(v),
84+
// propagate control flow immediately
85+
s @ (Signal::Failure(_) | Signal::Return(_) | Signal::Respond(_) | Signal::Stop) => return s,
86+
}
87+
}
88+
}
89+
}
90+
91+
// Provide a runner for Lazy params
92+
let mut run = |node_id: i64| self.execute(node_id);
93+
94+
// Call the handler (no special cases anywhere)
95+
let result = (entry.handler)(&args, &mut self.context, &mut run);
96+
97+
match result {
98+
Signal::Success(value) => {
99+
if let Some(next_node_id) = node.next_node_id {
100+
current_node_id = next_node_id;
101+
continue;
102+
} else {
103+
return Signal::Success(value);
104+
}
105+
}
106+
Signal::Failure(e) => return Signal::Failure(e),
107+
Signal::Return(v) => return Signal::Return(v),
108+
Signal::Respond(v) => return Signal::Respond(v),
109+
Signal::Stop => return Signal::Stop,
110+
}
111+
}
112+
}
113+
}

src/context/mod.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
pub mod context;
22
pub mod signal;
3+
pub mod argument;
4+
pub mod executor;
5+
mod registry;
36

47
use crate::error::RuntimeError;
58
use std::{
Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,26 @@
11
use crate::context::Context;
2+
use crate::context::argument::{Argument, ParameterNode};
23
use crate::context::signal::Signal;
34
use std::collections::HashMap;
4-
use tucana::shared::Value;
55

6-
pub type HandlerFn = fn(&[Value], &mut Context) -> Signal;
6+
/// HandlerFm
7+
/// - For eager params, the executor will already convert them to Argument::Eval(Value).
8+
/// - For lazy params, the executor will pass Argument::Thunk(node_id).
9+
/// - If a handler wants to execute a lazy arg, it calls run(node_id).
10+
pub type HandlerFn = fn(
11+
args: &[Argument],
12+
ctx: &mut Context,
13+
run: &mut dyn FnMut(i64) -> Signal,
14+
) -> Signal;
15+
16+
pub struct HandlerFunctionEntry {
17+
pub handler: HandlerFn,
18+
pub param_modes: Vec<ParameterNode>,
19+
}
720

821
/// Holds all registered handlers.
922
pub struct FunctionStore {
10-
functions: HashMap<String, HandlerFn>,
23+
functions: HashMap<String, HandlerFunctionEntry>,
1124
}
1225

1326
impl Default for FunctionStore {
@@ -25,12 +38,12 @@ impl FunctionStore {
2538
}
2639

2740
/// Look up a handler by its ID.
28-
pub fn get(&self, id: &str) -> Option<&HandlerFn> {
41+
pub fn get(&self, id: &str) -> Option<&HandlerFunctionEntry> {
2942
self.functions.get(id)
3043
}
3144

3245
/// Execute all the registration closures to populate the map.
33-
pub fn populate(&mut self, regs: Vec<(&'static str, HandlerFn)>) {
46+
pub fn populate(&mut self, regs: Vec<(&'static str, HandlerFunctionEntry)>) {
3447
for (id, func) in regs {
3548
self.functions.insert(id.to_string(), func);
3649
}

src/executor/mod.rs

Lines changed: 0 additions & 114 deletions
This file was deleted.

src/implementation/control.rs

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ fn r#if(values: &[Value], _ctx: &mut Context) -> Signal {
3131
let [
3232
Value {
3333
kind: Some(Kind::StringValue(text)),
34-
},
34+
}
3535
] = values
3636
else {
3737
return Signal::Failure(RuntimeError::simple(
@@ -51,17 +51,19 @@ fn r#if(values: &[Value], _ctx: &mut Context) -> Signal {
5151
};
5252

5353
if bool {
54-
unimplemented!()
54+
// Signal::Skip(vec![0])
5555
} else {
56-
unimplemented!()
56+
// Signal::Return(Value {
57+
// kind: Some(Kind::NullValue(0)),
58+
// })
5759
}
5860
}
5961

6062
fn if_else(values: &[Value], _ctx: &mut Context) -> Signal {
6163
let [
6264
Value {
6365
kind: Some(Kind::StringValue(text)),
64-
},
66+
}
6567
] = values
6668
else {
6769
return Signal::Failure(RuntimeError::simple(
@@ -81,8 +83,8 @@ fn if_else(values: &[Value], _ctx: &mut Context) -> Signal {
8183
};
8284

8385
if bool {
84-
unimplemented!()
86+
// Signal::Skip(vec![1])
8587
} else {
86-
unimplemented!()
88+
// Signal::Skip(vec![0])
8789
}
88-
}
90+
}

src/implementation/number.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,9 @@ use std::f64;
33
use tucana::shared::{Value, value::Kind};
44

55
use crate::context::signal::Signal;
6-
use crate::{context::Context, error::RuntimeError, registry::HandlerFn};
6+
use crate::{context::Context, error::RuntimeError};
77

8-
pub fn collect_number_functions() -> Vec<(&'static str, HandlerFn)> {
8+
pub fn collect_number_functions() -> Vec<(&'static str, )> {
99
vec![
1010
("std::number::add", add),
1111
("std::number::multiply", multiply),

0 commit comments

Comments
 (0)