[BREAKING] Feat: quotation is now using ()

This commit is contained in:
2026-02-28 20:25:59 +01:00
parent ec98274dfe
commit 651ed1219d
24 changed files with 182 additions and 169 deletions

View File

@@ -4,26 +4,26 @@ use super::harness::*;
fn quotation_on_stack() {
// Quotation should be pushable to stack
let f = forth();
let result = f.evaluate("{ 1 2 + }", &default_ctx());
let result = f.evaluate("( 1 2 + )", &default_ctx());
assert!(result.is_ok());
}
#[test]
fn when_true_executes() {
let f = run("{ 42 } 1 ?");
let f = run("( 42 ) 1 ?");
assert_eq!(stack_int(&f), 42);
}
#[test]
fn when_false_skips() {
let f = run("99 { 42 } 0 ?");
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 ?");
let f = run("10 ( 5 + ) 1 ?");
assert_eq!(stack_int(&f), 15);
}
@@ -31,48 +31,48 @@ fn when_with_arithmetic() {
fn when_with_every() {
// iter=0, every 2 executes quotation
let ctx = ctx_with(|c| c.iter = 0);
let f = run_ctx("{ 100 } 2 every", &ctx);
let f = run_ctx("( 100 ) 2 every", &ctx);
assert_eq!(stack_int(&f), 100);
// iter=1, every 2 skips quotation
let ctx = ctx_with(|c| c.iter = 1);
let f = run_ctx("50 { 100 } 2 every", &ctx);
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");
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");
let f = run("99 ( 42 ) 0.0 chance");
assert_eq!(stack_int(&f), 99);
}
#[test]
fn nested_quotations() {
let f = run("{ { 42 } 1 ? } 1 ?");
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 ? ."#, 1);
let outputs = expect_outputs(r#""kick" s ( 2 distort ) 1 ? ."#, 1);
assert!(outputs[0].contains("distort/2"));
}
#[test]
fn quotation_skips_param() {
let outputs = expect_outputs(r#""kick" s { 2 distort } 0 ? ."#, 1);
let outputs = expect_outputs(r#""kick" s ( 2 distort ) 0 ? ."#, 1);
assert!(!outputs[0].contains("distort"));
}
#[test]
fn quotation_with_emit() {
// When true, . should fire
let outputs = expect_outputs(r#""kick" s { . } 1 ?"#, 1);
let outputs = expect_outputs(r#""kick" s ( . ) 1 ?"#, 1);
assert!(outputs[0].contains("kick"));
}
@@ -81,7 +81,7 @@ fn quotation_skips_emit() {
// When false, . should not fire
let f = forth();
let outputs = f
.evaluate(r#""kick" s { . } 0 ?"#, &default_ctx())
.evaluate(r#""kick" s ( . ) 0 ?"#, &default_ctx())
.unwrap();
// No output since . was skipped and no implicit emit
assert_eq!(outputs.len(), 0);
@@ -94,22 +94,22 @@ fn missing_quotation_error() {
#[test]
fn unclosed_quotation_error() {
expect_error("{ 1 2", "missing }");
expect_error("( 1 2", "missing )");
}
#[test]
fn unexpected_close_error() {
expect_error("1 2 }", "unexpected }");
expect_error("1 2 )", "unexpected )");
}
#[test]
fn every_with_quotation_integration() {
// { 2 distort } 2 every — on even iterations, distort is applied
// ( 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 ."#, &ctx)
.evaluate(r#""kick" s ( 2 distort ) 2 every ."#, &ctx)
.unwrap();
if iter % 2 == 0 {
assert!(
@@ -134,7 +134,7 @@ fn bjork_with_sound() {
let ctx = ctx_with(|c| c.runs = 2); // position 2 is a hit for (3,8)
let f = forth();
let outputs = f
.evaluate(r#""kick" s { 2 distort } 3 8 bjork ."#, &ctx)
.evaluate(r#""kick" s ( 2 distort ) 3 8 bjork ."#, &ctx)
.unwrap();
assert!(outputs[0].contains("distort/2"));
}
@@ -143,13 +143,13 @@ fn bjork_with_sound() {
#[test]
fn unless_false_executes() {
let f = run("{ 42 } 0 !?");
let f = run("( 42 ) 0 !?");
assert_eq!(stack_int(&f), 42);
}
#[test]
fn unless_true_skips() {
let f = run("99 { 42 } 1 !?");
let f = run("99 ( 42 ) 1 !?");
assert_eq!(stack_int(&f), 99);
}
@@ -161,7 +161,7 @@ fn when_and_unless_complementary() {
let f = forth();
let outputs = f
.evaluate(
r#""kick" s { 2 distort } iter 2 mod 0 = ? { 4 distort } iter 2 mod 0 = !? ."#,
r#""kick" s ( 2 distort ) iter 2 mod 0 = ? ( 4 distort ) iter 2 mod 0 = !? ."#,
&ctx,
)
.unwrap();