Init
This commit is contained in:
184
tests/forth/quotations.rs
Normal file
184
tests/forth/quotations.rs
Normal file
@@ -0,0 +1,184 @@
|
||||
use super::harness::*;
|
||||
|
||||
#[test]
|
||||
fn quotation_on_stack() {
|
||||
// Quotation should be pushable to stack
|
||||
let f = forth();
|
||||
let result = f.evaluate("{ 1 2 + }", &default_ctx());
|
||||
assert!(result.is_ok());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn when_true_executes() {
|
||||
let f = run("{ 42 } 1 ?");
|
||||
assert_eq!(stack_int(&f), 42);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn when_false_skips() {
|
||||
let f = run("99 { 42 } 0 ?");
|
||||
// Stack should still have 99, quotation not executed
|
||||
assert_eq!(stack_int(&f), 99);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn when_with_arithmetic() {
|
||||
let f = run("10 { 5 + } 1 ?");
|
||||
assert_eq!(stack_int(&f), 15);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn when_with_every() {
|
||||
// iter=0, every 2 should be true
|
||||
let ctx = ctx_with(|c| c.iter = 0);
|
||||
let f = run_ctx("{ 100 } 2 every ?", &ctx);
|
||||
assert_eq!(stack_int(&f), 100);
|
||||
|
||||
// iter=1, every 2 should be false
|
||||
let ctx = ctx_with(|c| c.iter = 1);
|
||||
let f = run_ctx("50 { 100 } 2 every ?", &ctx);
|
||||
assert_eq!(stack_int(&f), 50); // quotation not executed
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn when_with_chance_deterministic() {
|
||||
// 1.0 chance always executes quotation
|
||||
let f = run("{ 42 } 1.0 chance");
|
||||
assert_eq!(stack_int(&f), 42);
|
||||
|
||||
// 0.0 chance never executes quotation
|
||||
let f = run("99 { 42 } 0.0 chance");
|
||||
assert_eq!(stack_int(&f), 99);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn nested_quotations() {
|
||||
let f = run("{ { 42 } 1 ? } 1 ?");
|
||||
assert_eq!(stack_int(&f), 42);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn quotation_with_param() {
|
||||
let outputs = expect_outputs(r#""kick" s { 2 distort } 1 ? emit"#, 1);
|
||||
assert!(outputs[0].contains("distort/2"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn quotation_skips_param() {
|
||||
let outputs = expect_outputs(r#""kick" s { 2 distort } 0 ? emit"#, 1);
|
||||
assert!(!outputs[0].contains("distort"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn quotation_with_emit() {
|
||||
// When true, emit should fire
|
||||
let outputs = expect_outputs(r#""kick" s { emit } 1 ?"#, 1);
|
||||
assert!(outputs[0].contains("kick"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn quotation_skips_emit() {
|
||||
// When false, emit should not fire
|
||||
let f = forth();
|
||||
let outputs = f
|
||||
.evaluate(r#""kick" s { emit } 0 ?"#, &default_ctx())
|
||||
.unwrap();
|
||||
// Should have 1 output from implicit emit at end (since cmd is set but not emitted)
|
||||
assert_eq!(outputs.len(), 1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn missing_quotation_error() {
|
||||
expect_error("42 1 ?", "expected quotation");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unclosed_quotation_error() {
|
||||
expect_error("{ 1 2", "missing }");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unexpected_close_error() {
|
||||
expect_error("1 2 }", "unexpected }");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn every_with_quotation_integration() {
|
||||
// Simulating: { 2 distort } 2 every ?
|
||||
// On even iterations, distort is applied
|
||||
for iter in 0..4 {
|
||||
let ctx = ctx_with(|c| c.iter = iter);
|
||||
let f = forth();
|
||||
let outputs = f
|
||||
.evaluate(r#""kick" s { 2 distort } 2 every ? emit"#, &ctx)
|
||||
.unwrap();
|
||||
if iter % 2 == 0 {
|
||||
assert!(
|
||||
outputs[0].contains("distort/2"),
|
||||
"iter {} should have distort",
|
||||
iter
|
||||
);
|
||||
} else {
|
||||
assert!(
|
||||
!outputs[0].contains("distort"),
|
||||
"iter {} should not have distort",
|
||||
iter
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Unless (!?) tests
|
||||
|
||||
#[test]
|
||||
fn unless_false_executes() {
|
||||
let f = run("{ 42 } 0 !?");
|
||||
assert_eq!(stack_int(&f), 42);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unless_true_skips() {
|
||||
let f = run("99 { 42 } 1 !?");
|
||||
assert_eq!(stack_int(&f), 99);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unless_with_every() {
|
||||
// iter=0, every 2 is true, so unless skips
|
||||
let ctx = ctx_with(|c| c.iter = 0);
|
||||
let f = run_ctx("50 { 100 } 2 every !?", &ctx);
|
||||
assert_eq!(stack_int(&f), 50);
|
||||
|
||||
// iter=1, every 2 is false, so unless executes
|
||||
let ctx = ctx_with(|c| c.iter = 1);
|
||||
let f = run_ctx("{ 100 } 2 every !?", &ctx);
|
||||
assert_eq!(stack_int(&f), 100);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn when_and_unless_complementary() {
|
||||
// Using both ? and !? for if-else like behavior
|
||||
for iter in 0..4 {
|
||||
let ctx = ctx_with(|c| c.iter = iter);
|
||||
let f = forth();
|
||||
let outputs = f
|
||||
.evaluate(
|
||||
r#""kick" s { 2 distort } 2 every ? { 4 distort } 2 every !? emit"#,
|
||||
&ctx,
|
||||
)
|
||||
.unwrap();
|
||||
if iter % 2 == 0 {
|
||||
assert!(
|
||||
outputs[0].contains("distort/2"),
|
||||
"iter {} should have distort/2",
|
||||
iter
|
||||
);
|
||||
} else {
|
||||
assert!(
|
||||
outputs[0].contains("distort/4"),
|
||||
"iter {} should have distort/4",
|
||||
iter
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user