use crate::stack_machine::{StackState, add, new_stack, pop, push, swap};
use state_macro::with_state;
mod nested {
use super::*;
pub fn push(state: &StackState, value: i32) {
super::push(state, value * 2); }
}
fn test_program(state: &StackState, x: i32, y: i32) -> i32 {
with_state! { state;
::push(x);
::push(y);
::add();
::pop()
}
}
#[test]
fn test_basic_with_state() {
let stack = new_stack();
let result = test_program(&stack, 3, 5);
assert_eq!(result, 8);
assert_eq!(stack.borrow().len(), 0);
}
#[test]
fn test_with_state_namespaced_functions() {
let stack = new_stack();
with_state! { &stack;
::push(10);
::nested::push(5); ::add();
}
let result = pop(&stack);
assert_eq!(result, 20);
assert_eq!(stack.borrow().len(), 0);
}
#[test]
fn test_with_state_nested_function_calls() {
let stack = new_stack();
with_state! { &stack;
::push(10);
::push(::pop() + 5); ::push(20);
::swap(); ::add(); }
let result = pop(&stack);
assert_eq!(result, 35);
assert_eq!(stack.borrow().len(), 0);
}
#[test]
fn test_with_state_conditional() {
let stack = new_stack();
push(&stack, 10);
with_state! {
if ::pop() > 0 { true } else { false };
}
}
#[test]
fn test_with_state_nested_expressions() {
let stack = new_stack();
with_state! { &stack;
let x = {
::push(5);
::push(7);
::pop() + ::pop() };
::push(x);
if ::pop() > 10 {
::push(100);
} else {
::push(0);
}
}
let result = pop(&stack);
assert_eq!(result, 100); assert_eq!(stack.borrow().len(), 0);
}
#[test]
fn test_with_state_loops() {
let stack = new_stack();
with_state! { &stack;
::push(0);
for i in 1..=5 {
::push(i);
::add(); }
}
let result = pop(&stack);
assert_eq!(result, 15); assert_eq!(stack.borrow().len(), 0);
}
#[test]
fn test_complex_program() {
let stack = new_stack();
with_state! { &stack;
::push(10);
::push(20);
::swap();
let product = {
let a = ::pop(); let b = ::pop(); a * b };
::push(product);
let mut result = ::pop(); while result >= 50 {
result /= 2; ::push(result); }
}
let result = pop(&stack);
assert_eq!(result, 25);
assert_eq!(stack.borrow().len(), 2);
}