[BREAKING] Feat: quotation is now using ()

This commit is contained in:
2026-02-28 20:25:59 +01:00
parent f88691c09c
commit 1ba946ebe6
30 changed files with 218 additions and 169 deletions

View File

@@ -54,7 +54,7 @@ Four basic types of values can live on the stack:
- **Integers**: `42`, `-7`, `0`
- **Floats**: `0.5`, `3.14`, `-1.0`
- **Strings**: `"kick"`, `"hello"`
- **Quotations**: `{ dup + }` (code as data)
- **Quotations**: `( dup + )` (code as data)
Floats can omit the leading zero: `.25` is the same as `0.25`, and `-.5` is `-0.5`.

View File

@@ -29,22 +29,22 @@ These are compiled directly into branch instructions. For that reason, these wor
When you already have a quotation, `?` executes it if the condition is truthy:
```forth
{ 0.4 verb } coin ?
( 0.4 verb ) coin ?
saw s c4 note 0.5 gain . ;; reverb on half the hits
```
`!?` is the opposite — executes when falsy:
```forth
{ 0.2 gain } coin !?
( 0.2 gain ) coin !?
saw s c4 note . ;; quiet on half the hits
```
These pair well with `chance`, `prob`, and the other probability words:
```forth
{ 0.5 verb } 0.3 chance ? ;; occasional reverb wash
{ 12 + } fill ? ;; octave up during fills
( 0.5 verb ) 0.3 chance ? ;; occasional reverb wash
( 12 + ) fill ? ;; octave up during fills
```
## ifelse
@@ -52,14 +52,14 @@ These pair well with `chance`, `prob`, and the other probability words:
Two quotations, one condition. The true branch comes first:
```forth
{ c3 note } { c4 note } coin ifelse
( c3 note ) ( c4 note ) coin ifelse
saw s 0.6 gain . ;; bass or lead, coin flip
```
Reads naturally: "c3 or c4, depending on the coin."
```forth
{ 0.8 gain } { 0.3 gain } fill ifelse
( 0.8 gain ) ( 0.3 gain ) fill ifelse
tri s c4 note 0.2 decay . ;; loud during fills, quiet otherwise
```
@@ -68,7 +68,7 @@ tri s c4 note 0.2 decay . ;; loud during fills, quiet otherwise
Choose the nth option from a list of quotations:
```forth
{ c4 } { e4 } { g4 } { b4 } iter 4 mod select
( c4 ) ( e4 ) ( g4 ) ( b4 ) iter 4 mod select
note sine s 0.5 decay .
```
@@ -79,7 +79,7 @@ Four notes cycling through a major seventh chord, one per pattern iteration. The
When you have a quotation and want to execute it unconditionally, use `apply`:
```forth
{ dup + } apply ;; doubles the top value
( dup + ) apply ;; doubles the top value
```
This is simpler than `?` when there is no condition to check. It pops the quotation and runs it.
@@ -115,14 +115,14 @@ saw s c4 note .
Repeat a quotation n times. The variable `@i` is automatically set to the current iteration index (starting from 0):
```forth
3 { c4 @i 4 * + note } times
3 ( c4 @i 4 * + note ) times
sine s 0.4 gain 0.5 verb . ;; c4, e4, g#4 a chord
```
Subdivide with `at`:
```forth
4 { @i 4 / at sine s c4 note 0.3 gain . } times
4 ( @i 4 / at sine s c4 note 0.3 gain . ) times
```
Four evenly spaced notes within the step.
@@ -130,11 +130,11 @@ Four evenly spaced notes within the step.
Vary intensity per iteration:
```forth
8 {
8 (
@i 8 / at
@i 4 mod 0 = if 0.7 else 0.2 then gain
tri s c5 note 0.1 decay .
} times
) times
```
Eight notes per step. Every fourth one louder.

View File

@@ -22,10 +22,10 @@ Everything after `;;` until the end of the line is ignored.
Classic Forth has no quotations. Code is not a value you can pass around.
Cagire has first-class quotations using curly braces:
Cagire has first-class quotations using parentheses:
```forth
{ dup + }
( dup + )
```
This pushes a block of code onto the stack. You can store it, pass it to other words, and execute it later. Quotations enable conditionals, probability, and cycling.
@@ -41,14 +41,14 @@ x 0 > IF 1 ELSE -1 THEN
Cagire supports this syntax but also provides quotation-based conditionals:
```forth
{ 1 } { -1 } x 0 > ifelse
( 1 ) ( -1 ) x 0 > ifelse
```
The words `?` and `!?` execute a quotation based on a condition:
```forth
{ "kick" s . } coin ? ;; execute if coin is 1
{ "snare" s . } coin !? ;; execute if coin is 0
( "kick" s . ) coin ? ;; execute if coin is 1
( "snare" s . ) coin !? ;; execute if coin is 0
```
## Strings
@@ -116,21 +116,21 @@ Classic Forth has `DO ... LOOP`:
Cagire uses a quotation-based loop with `times`:
```forth
4 { @i . } times ;; prints 0 1 2 3
4 ( @i . ) times ;; prints 0 1 2 3
```
The loop counter is stored in the variable `i`, accessed with `@i`. This fits Cagire's style where control flow uses quotations.
```forth
4 { @i 4 / at hat s . } times ;; hat at 0, 0.25, 0.5, 0.75
4 { c4 @i + note sine s . } times ;; ascending notes
4 ( @i 4 / at hat s . ) times ;; hat at 0, 0.25, 0.5, 0.75
4 ( c4 @i + note sine s . ) times ;; ascending notes
```
For generating sequences without side effects, use `..` or `gen`:
```forth
1 5 .. ;; pushes 1 2 3 4 5
{ dup * } 4 gen ;; pushes 0 1 4 9 (squares)
( dup * ) 4 gen ;; pushes 0 1 4 9 (squares)
```
## The Command Register
@@ -167,11 +167,11 @@ These have no equivalent in classic Forth. They connect your script to the seque
Classic Forth is deterministic. Cagire has built-in randomness:
```forth
{ "snare" s . } 50 prob ;; 50% chance
{ "clap" s . } 0.25 chance ;; 25% chance
{ "hat" s . } often ;; 75% chance
{ "rim" s . } sometimes ;; 50% chance
{ "tom" s . } rarely ;; 25% chance
( "snare" s . ) 50 prob ;; 50% chance
( "clap" s . ) 0.25 chance ;; 25% chance
( "hat" s . ) often ;; 75% chance
( "rim" s . ) sometimes ;; 50% chance
( "tom" s . ) rarely ;; 25% chance
```
These words take a quotation and execute it probabilistically.
@@ -181,9 +181,9 @@ These words take a quotation and execute it probabilistically.
Execute a quotation on specific iterations:
```forth
{ "snare" s . } 4 every ;; every 4th pattern iteration
{ "hat" s . } 3 8 bjork ;; Euclidean: 3 hits across 8 step runs
{ "hat" s . } 5 8 pbjork ;; Euclidean: 5 hits across 8 pattern iterations
( "snare" s . ) 4 every ;; every 4th pattern iteration
( "hat" s . ) 3 8 bjork ;; Euclidean: 3 hits across 8 step runs
( "hat" s . ) 5 8 pbjork ;; Euclidean: 5 hits across 8 pattern iterations
```
`every` checks the pattern iteration count. On iteration 0, 4, 8, 12... the quotation runs. On all other iterations it is skipped.
@@ -203,7 +203,7 @@ Each time the step runs, a different note is selected. The `3` tells `cycle` how
You can also use quotations if you need to execute code:
```forth
{ c4 note } { e4 note } { g4 note } 3 cycle
( c4 note ) ( e4 note ) ( g4 note ) 3 cycle
```
When the selected value is a quotation, it gets executed. When it is a plain value, it gets pushed onto the stack.