use crate::stack_machine::{StackState, add, new_stack, pop, push};
use state_macro::stateful;
#[stateful(&StackState)]
fn test_program(x: i32, y: i32) -> i32 {
::push(x);
::push(y);
::add();
::pop()
}
#[test]
fn test_basic_stateful() {
let stack = new_stack();
let result = test_program(&stack, 7, 3);
assert_eq!(result, 10);
assert_eq!(stack.borrow().len(), 0);
}
mod operations {
use super::*;
#[stateful(&StackState)]
pub fn multiply(x: i32, y: i32) -> i32 {
let mut result = 0;
for _ in 0..y {
::push(x);
::push(result);
::add();
result = ::pop();
}
result
}
}
#[test]
fn test_stateful_with_namespaced_functions() {
let stack = new_stack();
let result = operations::multiply(&stack, 5, 4);
assert_eq!(result, 20);
assert_eq!(stack.borrow().len(), 0);
}
#[stateful(&StackState)]
fn nested_calls(x: i32, y: i32) -> i32 {
let sum = ::test_program(x, y);
::push(sum);
::push(sum);
::add();
::pop() }
#[test]
fn test_stateful_nested_calls() {
let stack = new_stack();
let result = nested_calls(&stack, 5, 7);
assert_eq!(result, 24);
assert_eq!(stack.borrow().len(), 0);
}
#[stateful(&StackState)]
fn complex_stateful(x: i32) -> i32 {
let doubled = {
::push(x);
::push(x);
::add();
::pop()
};
if doubled > 10 {
::push(doubled);
::push(5);
::add();
} else {
::push(doubled);
::push(2);
::add();
}
::pop()
}
#[test]
fn test_stateful_with_expressions_and_conditionals() {
let stack = new_stack();
let result1 = complex_stateful(&stack, 3);
assert_eq!(result1, 8);
let result2 = complex_stateful(&stack, 8);
assert_eq!(result2, 21);
assert_eq!(stack.borrow().len(), 0);
}