From 7ae3f255b0b5805ea94d150984a23cde23e26fb5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Forment?= Date: Sat, 28 Feb 2026 02:37:09 +0100 Subject: [PATCH] Feat: add slicing words --- crates/forth/src/words/compile.rs | 2 +- crates/forth/src/words/core.rs | 4 ++-- crates/forth/src/words/sound.rs | 20 ++++++++++++++++++++ docs/forth/control_flow.md | 4 ++-- tests/forth/comparison.rs | 16 ++++++++-------- tests/forth/sound.rs | 13 +++++++++++++ 6 files changed, 46 insertions(+), 13 deletions(-) diff --git a/crates/forth/src/words/compile.rs b/crates/forth/src/words/compile.rs index 8e75d46..8ee55fa 100644 --- a/crates/forth/src/words/compile.rs +++ b/crates/forth/src/words/compile.rs @@ -58,7 +58,7 @@ pub(super) fn simple_op(name: &str) -> Option { "nand" => Op::Nand, "nor" => Op::Nor, "ifelse" => Op::IfElse, - "pick" => Op::Pick, + "select" => Op::Pick, "sound" => Op::NewCmd, "." => Op::Emit, "rand" => Op::Rand(None), diff --git a/crates/forth/src/words/core.rs b/crates/forth/src/words/core.rs index a7306a1..6c8cf9a 100644 --- a/crates/forth/src/words/core.rs +++ b/crates/forth/src/words/core.rs @@ -507,12 +507,12 @@ pub(super) const WORDS: &[Word] = &[ varargs: false, }, Word { - name: "pick", + name: "select", aliases: &[], category: "Logic", stack: "(..quots n --)", desc: "Execute nth quotation (0-indexed)", - example: "{ 1 } { 2 } { 3 } 2 pick => 3", + example: "{ 1 } { 2 } { 3 } 2 select => 3", compile: Simple, varargs: true, }, diff --git a/crates/forth/src/words/sound.rs b/crates/forth/src/words/sound.rs index 3a3e7b9..cbfac9e 100644 --- a/crates/forth/src/words/sound.rs +++ b/crates/forth/src/words/sound.rs @@ -186,6 +186,26 @@ pub(super) const WORDS: &[Word] = &[ compile: Param, varargs: true, }, + Word { + name: "slice", + aliases: &[], + category: "Sample", + stack: "(v.. --)", + desc: "Divide sample into N equal slices", + example: r#""break" s 8 slice 3 pick ."#, + compile: Param, + varargs: true, + }, + Word { + name: "pick", + aliases: &[], + category: "Sample", + stack: "(v.. --)", + desc: "Select which slice to play (0-indexed, wraps)", + example: r#""break" s 8 slice 3 pick ."#, + compile: Param, + varargs: true, + }, Word { name: "voice", aliases: &[], diff --git a/docs/forth/control_flow.md b/docs/forth/control_flow.md index 0ab1070..1d20c12 100644 --- a/docs/forth/control_flow.md +++ b/docs/forth/control_flow.md @@ -63,12 +63,12 @@ Reads naturally: "c3 or c4, depending on the coin." tri s c4 note 0.2 decay . ;; loud during fills, quiet otherwise ``` -## pick +## select Choose the nth option from a list of quotations: ```forth -{ c4 } { e4 } { g4 } { b4 } iter 4 mod pick +{ c4 } { e4 } { g4 } { b4 } iter 4 mod select note sine s 0.5 decay . ``` diff --git a/tests/forth/comparison.rs b/tests/forth/comparison.rs index 7f7f37b..055c363 100644 --- a/tests/forth/comparison.rs +++ b/tests/forth/comparison.rs @@ -196,21 +196,21 @@ fn ifelse_false() { } #[test] -fn pick_first() { - expect_int("{ 10 } { 20 } { 30 } 0 pick", 10); +fn select_first() { + expect_int("{ 10 } { 20 } { 30 } 0 select", 10); } #[test] -fn pick_second() { - expect_int("{ 10 } { 20 } { 30 } 1 pick", 20); +fn select_second() { + expect_int("{ 10 } { 20 } { 30 } 1 select", 20); } #[test] -fn pick_third() { - expect_int("{ 10 } { 20 } { 30 } 2 pick", 30); +fn select_third() { + expect_int("{ 10 } { 20 } { 30 } 2 select", 30); } #[test] -fn pick_preserves_stack() { - expect_int("5 { 10 } { 20 } 0 pick +", 15); +fn select_preserves_stack() { + expect_int("5 { 10 } { 20 } 0 select +", 15); } diff --git a/tests/forth/sound.rs b/tests/forth/sound.rs index 265453c..b8f4ce5 100644 --- a/tests/forth/sound.rs +++ b/tests/forth/sound.rs @@ -255,3 +255,16 @@ fn all_replaces_previous_global() { assert_eq!(outputs.len(), 1); assert!(outputs[0].contains("lpf/2000"), "latest lpf should be 2000: {}", outputs[0]); } + +#[test] +fn slice_param() { + let outputs = expect_outputs(r#""break" s 8 slice ."#, 1); + assert!(outputs[0].contains("slice/8")); +} + +#[test] +fn pick_param() { + let outputs = expect_outputs(r#""break" s 8 slice 3 pick ."#, 1); + assert!(outputs[0].contains("slice/8")); + assert!(outputs[0].contains("pick/3")); +}