use super::harness::*; #[test] fn choose_from_stack() { let f = forth(); let ctx = default_ctx(); f.evaluate("1 2 3 3 choose", &ctx).unwrap(); let val = stack_int(&f); assert!(val >= 1 && val <= 3, "expected 1, 2, or 3, got {}", val); } #[test] fn cycle_by_runs() { let ctx = ctx_with(|c| c.runs = 0); let f = run_ctx("10 20 30 3 cycle", &ctx); assert_eq!(stack_int(&f), 10); let ctx = ctx_with(|c| c.runs = 1); let f = run_ctx("10 20 30 3 cycle", &ctx); assert_eq!(stack_int(&f), 20); let ctx = ctx_with(|c| c.runs = 2); let f = run_ctx("10 20 30 3 cycle", &ctx); assert_eq!(stack_int(&f), 30); let ctx = ctx_with(|c| c.runs = 3); let f = run_ctx("10 20 30 3 cycle", &ctx); assert_eq!(stack_int(&f), 10); } #[test] fn pcycle_by_iter() { let ctx = ctx_with(|c| c.iter = 0); let f = run_ctx("10 20 30 3 pcycle", &ctx); assert_eq!(stack_int(&f), 10); let ctx = ctx_with(|c| c.iter = 1); let f = run_ctx("10 20 30 3 pcycle", &ctx); assert_eq!(stack_int(&f), 20); let ctx = ctx_with(|c| c.iter = 2); let f = run_ctx("10 20 30 3 pcycle", &ctx); assert_eq!(stack_int(&f), 30); } #[test] fn cycle_with_quotations() { let ctx = ctx_with(|c| c.runs = 0); let f = run_ctx("5 { dup } { 2 * } 2 cycle", &ctx); let stack = f.stack(); assert_eq!(stack.len(), 2); assert_eq!(stack_int(&f), 5); let ctx = ctx_with(|c| c.runs = 1); let f = run_ctx("5 { dup } { 2 * } 2 cycle", &ctx); assert_eq!(stack_int(&f), 10); } #[test] fn cycle_executes_quotation() { let ctx = ctx_with(|c| c.runs = 0); let f = run_ctx("10 { 3 + } { 5 + } 2 cycle", &ctx); assert_eq!(stack_int(&f), 13); } #[test] fn dupn_basic() { // 5 3 dupn -> 5 5 5, then + + -> 15 expect_int("5 3 dupn + +", 15); } #[test] fn dupn_alias() { expect_int("5 3 ! + +", 15); } #[test] fn cycle_zero_count_error() { expect_error("1 2 3 0 cycle", "cycle count must be > 0"); } #[test] fn choose_zero_count_error() { expect_error("1 2 3 0 choose", "choose count must be > 0"); } // Bracket syntax tests #[test] fn bracket_cycle() { let ctx = ctx_with(|c| c.runs = 0); let f = run_ctx("[ 10 20 30 ] cycle", &ctx); assert_eq!(stack_int(&f), 10); let ctx = ctx_with(|c| c.runs = 1); let f = run_ctx("[ 10 20 30 ] cycle", &ctx); assert_eq!(stack_int(&f), 20); let ctx = ctx_with(|c| c.runs = 2); let f = run_ctx("[ 10 20 30 ] cycle", &ctx); assert_eq!(stack_int(&f), 30); let ctx = ctx_with(|c| c.runs = 3); let f = run_ctx("[ 10 20 30 ] cycle", &ctx); assert_eq!(stack_int(&f), 10); } #[test] fn bracket_with_quotations() { let ctx = ctx_with(|c| c.runs = 0); let f = run_ctx("5 [ { 3 + } { 5 + } ] cycle", &ctx); assert_eq!(stack_int(&f), 8); let ctx = ctx_with(|c| c.runs = 1); let f = run_ctx("5 [ { 3 + } { 5 + } ] cycle", &ctx); assert_eq!(stack_int(&f), 10); } #[test] fn bracket_nested() { let ctx = ctx_with(|c| { c.runs = 0; c.iter = 0; }); let f = run_ctx("[ [ 10 20 ] cycle [ 30 40 ] cycle ] pcycle", &ctx); assert_eq!(stack_int(&f), 10); let ctx = ctx_with(|c| { c.runs = 0; c.iter = 1; }); let f = run_ctx("[ [ 10 20 ] cycle [ 30 40 ] cycle ] pcycle", &ctx); assert_eq!(stack_int(&f), 30); } #[test] fn bracket_with_generator() { let ctx = ctx_with(|c| c.runs = 0); let f = run_ctx("[ 1 4 .. ] cycle", &ctx); assert_eq!(stack_int(&f), 1); let ctx = ctx_with(|c| c.runs = 3); let f = run_ctx("[ 1 4 .. ] cycle", &ctx); assert_eq!(stack_int(&f), 4); } #[test] fn stray_bracket_error() { expect_error("10 ] cycle", "unexpected ]"); } #[test] fn unclosed_bracket_error() { expect_error("[ 10 20", "missing ]"); } // Index tests #[test] fn index_basic() { expect_int("10 20 30 3 1 index", 20); } #[test] fn index_with_brackets() { expect_int("[ 10 20 30 ] 1 index", 20); } #[test] fn index_modulo_wraps() { expect_int("[ 10 20 30 ] 5 index", 30); } #[test] fn index_negative_wraps() { expect_int("[ 10 20 30 ] -1 index", 30); } #[test] fn index_with_quotation() { expect_int("5 [ { 3 + } { 5 + } ] 0 index", 8); } #[test] fn index_zero_count_error() { expect_error("0 0 index", "index count must be > 0"); }