use gantz_core::{
Edge, ROOT_STATE,
compile::push_eval_fn_name,
node::{self, GraphNode, Node, WithPushEval},
};
use std::fmt::Debug;
use steel::{SteelVal, steel_vm::engine::Engine};
fn node_push() -> node::Push<node::Expr> {
node::expr("'()").unwrap().with_push_eval()
}
fn node_int(i: i32) -> node::Expr {
node::expr(format!("(begin $push {})", i)).unwrap()
}
fn node_mul() -> node::Expr {
node::expr("(* $l $r)").unwrap()
}
fn node_assert_eq() -> node::Expr {
node::expr("(begin (assert! (equal? $l $r)))").unwrap()
}
fn node_number() -> node::Expr {
node::expr(
"
(let ((x $x))
(set! state (if (number? x) x state))
state)
",
)
.unwrap()
}
trait DebugNode: Debug + Node {}
impl<T> DebugNode for T where T: Debug + Node {}
#[test]
fn test_graph_nested_stateless() {
env_logger::init();
let mut ga = GraphNode::default();
let inlet_a = ga.add_node(Box::new(node::graph::Inlet) as Box<dyn DebugNode>);
let inlet_b = ga.add_node(Box::new(node::graph::Inlet) as Box<_>);
let mul = ga.add_node(Box::new(node_mul()) as Box<_>);
let outlet = ga.add_node(Box::new(node::graph::Outlet) as Box<_>);
ga.add_edge(inlet_a, mul, Edge::from((0, 0)));
ga.add_edge(inlet_b, mul, Edge::from((0, 1)));
ga.add_edge(mul, outlet, Edge::from((0, 0)));
let mut gb = petgraph::graph::DiGraph::new();
let push = gb.add_node(Box::new(node_push()) as Box<dyn DebugNode>);
let six = gb.add_node(Box::new(node_int(6)) as Box<_>);
let seven = gb.add_node(Box::new(node_int(7)) as Box<_>);
let graph_a = gb.add_node(Box::new(ga) as Box<_>);
let forty_two = gb.add_node(Box::new(node_int(42)) as Box<_>);
let assert_eq = gb.add_node(Box::new(node_assert_eq()) as Box<_>);
gb.add_edge(push, six, Edge::from((0, 0)));
gb.add_edge(push, seven, Edge::from((0, 0)));
gb.add_edge(push, forty_two, Edge::from((0, 0)));
gb.add_edge(six, graph_a, Edge::from((0, 0)));
gb.add_edge(seven, graph_a, Edge::from((0, 1)));
gb.add_edge(graph_a, assert_eq, Edge::from((0, 0)));
gb.add_edge(forty_two, assert_eq, Edge::from((0, 1)));
let module = gantz_core::compile::module(&gb);
let mut vm = Engine::new_base();
vm.register_value(ROOT_STATE, SteelVal::empty_hashmap());
gantz_core::graph::register(&gb, &[], &mut vm);
for f in module {
vm.run(f.to_pretty(100)).unwrap();
}
vm.call_function_by_name_with_args(&push_eval_fn_name(&[push.index()]), vec![])
.unwrap();
}
#[test]
fn test_graph_nested_counter() {
let counter = node::expr(
"
(begin
$bang
(set! state
(if (number? state) (+ state 1) 0))
state)
",
)
.unwrap();
let mut ga = GraphNode::default();
let inlet = ga.add_node(Box::new(node::graph::Inlet) as Box<dyn DebugNode>);
let counter = ga.add_node(Box::new(counter) as Box<_>);
let outlet = ga.add_node(Box::new(node::graph::Outlet) as Box<_>);
ga.add_edge(inlet, counter, Edge::from((0, 0)));
ga.add_edge(counter, outlet, Edge::from((0, 0)));
let mut gb = petgraph::graph::DiGraph::new();
let push = gb.add_node(Box::new(node_push()) as Box<dyn DebugNode>);
let graph_a = gb.add_node(Box::new(ga) as Box<_>);
let number = gb.add_node(Box::new(node_number()) as Box<_>);
gb.add_edge(push, graph_a, Edge::from((0, 0)));
gb.add_edge(graph_a, number, Edge::from((0, 0)));
let module = gantz_core::compile::module(&gb);
let mut vm = Engine::new_base();
vm.register_value(ROOT_STATE, SteelVal::empty_hashmap());
gantz_core::graph::register(&gb, &[], &mut vm);
for f in module {
println!("{}\n", f.to_pretty(100));
vm.run(f.to_pretty(100)).unwrap();
}
vm.call_function_by_name_with_args(&push_eval_fn_name(&[push.index()]), vec![])
.unwrap();
vm.call_function_by_name_with_args(&push_eval_fn_name(&[push.index()]), vec![])
.unwrap();
let counter_state = node::state::extract::<u32>(&vm, &[graph_a.index(), counter.index()])
.expect("failed to extract counter state")
.expect("counter state was `None`");
assert_eq!(counter_state, 1);
let outlet_state = node::state::extract::<u32>(&vm, &[graph_a.index(), outlet.index()])
.expect("failed to extract outlet state")
.expect("outlet state was `None`");
assert_eq!(outlet_state, 1);
let number_state = node::state::extract::<u32>(&vm, &[number.index()])
.expect("failed to extract number state")
.expect("number state was `None`");
assert_eq!(number_state, 1);
}
#[test]
#[ignore = "requires #78, #77"]
fn test_graph_nested_push_eval() {
let mut ga = GraphNode::default();
let push = ga.add_node(Box::new(node_push()) as Box<dyn DebugNode>);
let int = ga.add_node(Box::new(node_int(42)) as Box<_>);
let outlet = ga.add_node(Box::new(node::graph::Outlet) as Box<_>);
ga.add_edge(push, int, Edge::from((0, 0)));
ga.add_edge(int, outlet, Edge::from((0, 0)));
let mut gb = petgraph::graph::DiGraph::new();
let graph_a = gb.add_node(Box::new(ga) as Box<dyn DebugNode>);
let number = gb.add_node(Box::new(node_number()) as Box<_>);
gb.add_edge(graph_a, number, Edge::from((0, 0)));
let module = gantz_core::compile::module(&gb);
let mut vm = Engine::new_base();
vm.register_value(ROOT_STATE, SteelVal::empty_hashmap());
gantz_core::graph::register(&gb, &[], &mut vm);
for f in module {
println!("{}\n", f.to_pretty(100));
vm.run(f.to_pretty(100)).unwrap();
}
let push_path = [graph_a.index(), push.index()];
vm.call_function_by_name_with_args(&push_eval_fn_name(&push_path), vec![])
.unwrap();
let outlet_state = node::state::extract::<u32>(&vm, &[graph_a.index(), outlet.index()])
.expect("failed to extract outlet state")
.expect("outlet state was `None`");
assert_eq!(outlet_state, 42);
let number_state = node::state::extract::<u32>(&vm, &[number.index()])
.expect("failed to extract number state")
.expect("number state was `None`");
assert_eq!(number_state, 42);
}