use super::harness::*; #[test] fn choose_word_from_list() { // 1 2 [ + - ] choose: picks + or -, applies to 1 2 // With seed 42, choose picks one deterministically let f = forth(); let ctx = default_ctx(); f.evaluate("1 2 [ + - ] choose", &ctx).unwrap(); let val = stack_int(&f); assert!(val == 3 || val == -1, "expected 3 or -1, got {}", val); } #[test] fn cycle_word_from_list() { // At runs=0, picks first word (dup) let ctx = ctx_with(|c| c.runs = 0); let f = run_ctx("5 < dup nip >", &ctx); assert_eq!(stack_int(&f), 5); // dup leaves 5 5, but stack check takes top // At runs=1, picks second word (2 *) let f = forth(); let ctx = ctx_with(|c| c.runs = 1); f.evaluate(": double 2 * ; 5 < dup double >", &ctx).unwrap(); assert_eq!(stack_int(&f), 10); } #[test] fn user_word_in_list() { let f = forth(); let ctx = ctx_with(|c| c.runs = 0); f.evaluate(": add3 3 + ; : add5 5 + ; 10 < add3 add5 >", &ctx).unwrap(); assert_eq!(stack_int(&f), 13); // runs=0 picks add3 } #[test] fn user_word_in_list_second() { let f = forth(); let ctx = ctx_with(|c| c.runs = 1); f.evaluate(": add3 3 + ; : add5 5 + ; 10 < add3 add5 >", &ctx).unwrap(); assert_eq!(stack_int(&f), 15); // runs=1 picks add5 } #[test] fn values_in_list_still_work() { // Numbers inside lists should still push as values (not quotations) let ctx = ctx_with(|c| c.runs = 0); let f = run_ctx("< 10 20 30 >", &ctx); assert_eq!(stack_int(&f), 10); } #[test] fn values_in_list_cycle() { let ctx = ctx_with(|c| c.runs = 2); let f = run_ctx("< 10 20 30 >", &ctx); assert_eq!(stack_int(&f), 30); } #[test] fn mixed_values_and_words() { // Values stay as values, words become quotations // [ 10 20 ] choose just picks a number let f = forth(); let ctx = default_ctx(); f.evaluate("[ 10 20 ] choose", &ctx).unwrap(); let val = stack_int(&f); assert!(val == 10 || val == 20, "expected 10 or 20, got {}", val); } #[test] fn word_with_sound_params() { let f = forth(); let ctx = ctx_with(|c| c.runs = 0); let outputs = f.evaluate( ": myverb 0.5 verb ; \"sine\" s 440 freq < myverb > .", &ctx ).unwrap(); assert_eq!(outputs.len(), 1); assert!(outputs[0].contains("verb/0.5"), "expected verb/0.5 in {}", outputs[0]); } #[test] fn arithmetic_word_in_list() { // 3 4 [ + ] choose -> picks + (only option), applies to 3 4 = 7 let ctx = ctx_with(|c| c.runs = 0); let f = run_ctx("3 4 < + >", &ctx); assert_eq!(stack_int(&f), 7); } #[test] fn pcycle_word_from_list() { let ctx = ctx_with(|c| c.iter = 0); let f = run_ctx("10 << dup 2 * >>", &ctx); // iter=0 picks dup: 10 10 let stack = f.stack(); assert_eq!(stack.len(), 2); assert_eq!(stack_int(&f), 10); } #[test] fn pcycle_word_second() { let ctx = ctx_with(|c| c.iter = 1); let f = run_ctx("10 << dup 2 * >>", &ctx); // iter=1 picks "2 *" — but wait, each token is its own element // so << dup 2 * >> has 3 elements: {dup}, 2, {*} // iter=1 picks element index 1 which is value 2 assert_eq!(stack_int(&f), 2); } #[test] fn multi_op_quotation_in_list() { // Use { } for multi-op quotations inside lists let ctx = ctx_with(|c| c.runs = 0); let f = run_ctx("10 < { 2 * } { 3 + } >", &ctx); assert_eq!(stack_int(&f), 20); // runs=0 picks {2 *} } #[test] fn multi_op_quotation_second() { let ctx = ctx_with(|c| c.runs = 1); let f = run_ctx("10 < { 2 * } { 3 + } >", &ctx); assert_eq!(stack_int(&f), 13); // runs=1 picks {3 +} }