#separator:tab #html:true #tags column:3 #deck:Forth 2012 + WAFER DUP ( x -- x x )
Copy top of stack. The workhorse of Forth — sets up operand reuse.
5 DUP * . \ 25 — classic square idiom
DUP 0< IF NEGATE THEN \ ABS pattern
WAFER: IR [Dup]. Peephole: OVER OVER → 2DUP. Eligible for stack-to-local promotion.
See: ?DUP 2DUP OVER core stack ir-primitive DROP ( x -- )
Discard TOS. Used to consume unwanted results.
/MOD DROP \ keep only remainder = MOD
/MOD NIP \ keep only quotient = /
WAFER: IR [Drop]. Peephole: DROP DROP → 2DROP.
See: NIP 2DROP core stack ir-primitive SWAP ( x1 x2 -- x2 x1 )
Exchange top two items. Reorders operands for non-commutative ops.
3 5 SWAP - . \ 2 (5-3)
WAFER: IR [Swap]. Common peephole target: SWAP DROP → NIP.
See: ROT 2SWAP core stack ir-primitive OVER ( x1 x2 -- x1 x2 x1 )
Copy second item to top. Lets you access NOS without destroying stack order.
: MAX 2DUP < IF SWAP THEN DROP ;
WAFER: IR [Over]. Peephole: OVER OVER → 2DUP.
See: PICK TUCK DUP core stack ir-primitive ROT ( x1 x2 x3 -- x2 x3 x1 )
Rotate third item to top. Brings buried item up; rarely elegant — consider refactoring if used heavily.
: -ROT ROT ROT ; \ reverse rotate idiom
WAFER: IR [Rot].
See: 2ROT -ROT core stack ir-primitive ?DUP ( x -- 0 | x x )
Duplicate only if nonzero. Eliminates a common DUP IF … DROP THEN pattern.
: SAFE/ ?DUP IF / ELSE DROP 0 THEN ;
WAFER: IR [QDup]. Single opcode, not a macro.
See: DUP IF core stack ir-primitive PICK ( xu…x1 x0 u -- xu…x1 x0 xu )
Copy u-th item (0-indexed). 0 PICK = DUP, 1 PICK = OVER. Deep picks signal stack abuse — refactor with locals or return stack.
2 PICK \ copies third item to top
WAFER: Host function. Runtime bounds check.
See: DUP OVER core stack host-function DEPTH ( -- +n )
Number of single-cell values on the data stack before DEPTH executed.
1 2 3 DEPTH . \ 3
WAFER: Host function. Computes (STACK_TOP - DSP) / 4.
See: FDEPTH .S core stack host-function 2DUP ( x1 x2 -- x1 x2 x1 x2 )
Duplicate top cell pair. Essential before consuming comparisons.
: MAX 2DUP < IF SWAP THEN DROP ;
WAFER: IR [TwoDup]. Peephole target: OVER OVER optimized to 2DUP.
See: DUP 2OVER 2DROP core stack ir-primitive 2DROP ( x1 x2 -- )
Drop top cell pair. Cleans up after double-cell operations.
S" hello" 2DROP \ discard c-addr u
WAFER: IR [TwoDrop]. Peephole: DROP DROP → 2DROP.
See: DROP 2DUP core stack ir-primitive 2SWAP ( x1 x2 x3 x4 -- x3 x4 x1 x2 )
Exchange top two cell pairs. Used with double-cell numbers or string descriptors (c-addr u).
1 2 3 4 2SWAP \ leaves 3 4 1 2
WAFER: Host function.
See: SWAP 2OVER 2ROT core stack host-function 2OVER ( x1 x2 x3 x4 -- x1 x2 x3 x4 x1 x2 )
Copy second cell pair over top pair. Mirror of OVER for double-width values.
WAFER: Host function.
See: OVER 2DUP 2SWAP core stack host-function + ( n1|u1 n2|u2 -- n3|u3 )
Add. Works identically for signed and unsigned (two's complement).
3 4 + . \ 7
WAFER: IR [Add]. Peephole: LIT(1) + → 1+. Strength reduction: LIT(2) * → 2*.
See: - 1+ D+ M+ core arithmetic ir-primitive - ( n1|u1 n2|u2 -- n3|u3 )
Subtract (n1 minus n2).
10 3 - . \ 7
WAFER: IR [Sub]. Peephole: LIT(1) - → 1-.
See: + NEGATE D- core arithmetic ir-primitive * ( n1|u1 n2|u2 -- n3|u3 )
Multiply. Result is the low-order cell of the double-cell product; use M* for full double result.
6 7 * . \ 42
WAFER: IR [Mul]. Strength reduction: LIT(2) * → LSHIFT(1), LIT(4) * → LSHIFT(2), etc.
See: M* UM* */ 2* core arithmetic ir-primitive / ( n1 n2 -- n3 )
Signed division. Implementation-defined rounding (symmetric in most systems). WAFER uses symmetric (truncate toward zero).
7 2 / . \ 3
-7 2 / . \ -3 (symmetric)
WAFER: IR [DivMod, Nip] — /MOD then keep quotient.
See: MOD /MOD FM/MOD SM/REM core arithmetic ir-primitive MOD ( n1 n2 -- n3 )
Signed remainder. Sign follows division semantics (symmetric in WAFER).
7 3 MOD . \ 1
-7 3 MOD . \ -1 (symmetric)
WAFER: IR [DivMod, Drop] — /MOD then keep remainder.
See: / /MOD FM/MOD core arithmetic ir-primitive /MOD ( n1 n2 -- n-rem n-quot )
Signed division with remainder. Remainder on top of quotient. Division semantics are implementation-defined.
7 3 /MOD . . \ 2 1 (quot=2, rem=1)
WAFER: IR [DivMod]. Maps to WASM i32.div_s + i32.rem_s. Core building block for / and MOD.
See: / MOD FM/MOD SM/REM UM/MOD core arithmetic ir-primitive */ ( n1 n2 n3 -- n4 )
Multiply then divide: (n1*n2)/n3. Intermediate result is double-cell, avoiding overflow. Essential for scaling and fixed-point.
355 113 */ \ approximates pi ratio
WAFER: Host function. Uses i64 intermediate.
See: */MOD M* core arithmetic host-function */MOD ( n1 n2 n3 -- n-rem n-quot )
Multiply then divmod: n1*n2 divided by n3, double-cell intermediate.
7 3 2 */MOD . . \ quot=10, rem=1
WAFER: Host function. Uses i64 intermediate.
See: */ /MOD core arithmetic host-function NEGATE ( n -- -n )
Two's complement negation. Note: NEGATE of the most negative number overflows silently.
5 NEGATE . \ -5
-1 NEGATE . \ 1
WAFER: IR [Negate]. Implemented as 0 SWAP SUB in WASM.
See: ABS DNEGATE FNEGATE core arithmetic ir-primitive ABS ( n -- u )
Absolute value. ABS of MIN-INT (most negative) returns MIN-INT (overflow).
-42 ABS . \ 42
WAFER: IR [Abs].
See: NEGATE DABS FABS core arithmetic ir-primitive MIN ( n1 n2 -- n3 )
Signed minimum. For unsigned minimum, use custom logic with U<.
3 7 MIN . \ 3
WAFER: Host function.
See: MAX FMIN DMIN core arithmetic host-function MAX ( n1 n2 -- n3 )
Signed maximum.
3 7 MAX . \ 7
WAFER: Host function.
See: MIN FMAX DMAX core arithmetic host-function 1+ ( n -- n+1 )
Increment by one. Faster than 1 +; common in address arithmetic and counters.
VARIABLE CTR : BUMP CTR @ 1+ CTR ! ;
WAFER: IR [PushI32(1), Add]. Peephole target: LIT(1) + → 1+.
See: 1- CELL+ CHAR+ core arithmetic ir-primitive 1- ( n -- n-1 )
Decrement by one.
10 BEGIN DUP . 1- DUP 0= UNTIL DROP
WAFER: IR [PushI32(1), Sub]. Peephole target: LIT(1) - → 1-.
See: 1+ core arithmetic ir-primitive 2* ( x -- x*2 )
Arithmetic left shift by 1. Equivalent to 1 LSHIFT. Works on both signed and unsigned.
WAFER: IR [PushI32(1), Lshift]. Strength reduction target: LIT(2) * → 2*.
See: 2/ LSHIFT D2* core arithmetic ir-primitive 2/ ( x -- x/2 )
Arithmetic right shift by 1 (sign-extending). NOT equivalent to 1 RSHIFT for negative numbers — RSHIFT is logical (zero-fill), 2/ preserves sign.
-7 2/ . \ -4 (rounds toward negative infinity)
WAFER: IR [ArithRshift]. Uses WASM i32.shr_s.
See: 2* RSHIFT D2/ core arithmetic ir-primitive M* ( n1 n2 -- d )
Signed multiply producing double-cell result. No overflow possible. Foundation for */ and */MOD.
100000 100000 M* D. \ 10000000000
WAFER: Host function. Uses Rust i64 multiply, splits into lo/hi i32.
See: UM* * D+ M*/ core arithmetic host-function UM* ( u1 u2 -- ud )
Unsigned multiply producing unsigned double-cell result.
WAFER: Host function. Uses Rust u64 multiply.
See: M* * core arithmetic host-function UM/MOD ( ud u1 -- u-rem u-quot )
Unsigned double-cell by single-cell division. Foundation for pictured numeric output (#).
0 10 3 UM/MOD . . \ 3 1
WAFER: Host function.
See: FM/MOD SM/REM /MOD core arithmetic host-function FM/MOD ( d n1 -- n-rem n-quot )
Floored division: quotient rounded toward negative infinity. Remainder has same sign as divisor. Preferred for modular arithmetic.
-7. 2 FM/MOD . . \ -4 1 (not -3 -1)
WAFER: Host function. Adjusts SM/REM result when signs differ.
See: SM/REM /MOD UM/MOD core arithmetic host-function SM/REM ( d n1 -- n-rem n-quot )
Symmetric division: quotient truncated toward zero. Remainder has same sign as dividend. C-like semantics.
-7. 2 SM/REM . . \ -3 -1
WAFER: Host function. Direct WASM i32 div/rem.
See: FM/MOD /MOD UM/MOD core arithmetic host-function S>D ( n -- d )
Sign-extend single to double. Pushes sign word (0 or -1) above n.
-1 S>D D. \ -1
5 S>D D. \ 5
WAFER: IR [StoD]. Uses WASM i32.shr_s by 31 for sign extension.
See: D>S D>F core conversion ir-primitive = ( x1 x2 -- flag )
True if equal. Returns well-formed flag (-1 or 0).
3 3 = . \ -1
3 4 = . \ 0
WAFER: IR [Eq]. Compiles to WASM i32.eq.
See: <> D= F= core comparison ir-primitive < ( n1 n2 -- flag )
Signed less-than. Treats values as signed 32-bit integers.
3 5 < . \ -1
-1 0 < . \ -1
WAFER: IR [Lt]. Compiles to WASM i32.lt_s.
See: > U< 0< D< core comparison ir-primitive > ( n1 n2 -- flag )
Signed greater-than.
5 3 > . \ -1
WAFER: IR [Gt]. Compiles to WASM i32.gt_s.
See: < U> 0> core comparison ir-primitive U< ( u1 u2 -- flag )
Unsigned less-than. Treats values as unsigned. Critical: -1 (0xFFFFFFFF) is the largest unsigned value.
-1 0 U< . \ 0 (unsigned: -1 is max)
WAFER: IR [LtUnsigned]. Compiles to WASM i32.lt_u.
See: < U> DU< core comparison ir-primitive 0= ( x -- flag )
True if zero. Also serves as logical NOT for well-formed flags.
0 0= . \ -1
FALSE 0= . \ -1 (logical NOT)
WAFER: IR [ZeroEq]. Compiles to WASM i32.eqz.
See: 0< 0<> 0> core comparison ir-primitive 0< ( n -- flag )
True if negative (sign bit set).
-5 0< . \ -1
0 0< . \ 0
WAFER: IR [ZeroLt]. Tests sign bit.
See: 0= 0> 0<> core comparison ir-primitive WITHIN ( n lo hi -- flag )
True if lo ≤ n < hi (unsigned comparison after subtracting lo). Works correctly even when range wraps around.
5 3 10 WITHIN . \ -1
3 3 10 WITHIN . \ -1 (inclusive low)
10 3 10 WITHIN . \ 0 (exclusive high)
WAFER: Host function.
See: < > U< core-ext comparison host-function AND ( x1 x2 -- x3 )
Bitwise AND. For logical AND with flags, this works because -1 AND -1 = -1. Also used for masking bits.
0xFF 0x0F AND . \ 15
TRUE TRUE AND . \ -1
WAFER: IR [And]. Compiles to WASM i32.and.
See: OR XOR INVERT core logic ir-primitive OR ( x1 x2 -- x3 )
Bitwise OR. Combines flag values and bit masks.
0xF0 0x0F OR . \ 255
WAFER: IR [Or]. Compiles to WASM i32.or.
See: AND XOR INVERT core logic ir-primitive XOR ( x1 x2 -- x3 )
Bitwise exclusive OR. x x XOR yields 0. Useful for toggling bits.
0xFF 0x0F XOR . \ 240
WAFER: IR [Xor]. Compiles to WASM i32.xor.
See: AND OR INVERT core logic ir-primitive INVERT ( x -- x' )
Bitwise NOT (one's complement). For flags: inverts all bits, so TRUE INVERT = FALSE and vice versa. NOT equivalent to logical NOT — use 0= for that.
0 INVERT . \ -1
WAFER: IR [Invert].
See: NEGATE 0= core logic ir-primitive LSHIFT ( x1 u -- x2 )
Logical left shift by u bits. Undefined for u ≥ cell-width (32).
1 8 LSHIFT . \ 256
WAFER: IR [Lshift]. Compiles to WASM i32.shl.
See: RSHIFT 2* D2* core logic ir-primitive RSHIFT ( x1 u -- x2 )
Logical right shift (zero-fill). NOT arithmetic shift — does not preserve sign. Use 2/ for signed division by 2.
256 8 RSHIFT . \ 1
-1 1 RSHIFT . \ 2147483647 (not -1!)
WAFER: IR [Rshift]. Compiles to WASM i32.shr_u.
See: LSHIFT 2/ core logic ir-primitive @ ( a-addr -- x )
Fetch cell from aligned address. Address must be cell-aligned (4-byte in WAFER). Unaligned access is undefined.
VARIABLE X 42 X ! X @ . \ 42
WAFER: IR [Fetch]. Compiles to WASM i32.load. Address is byte offset into linear memory.
See: ! C@ 2@ F@ core memory-ops ir-primitive ! ( x a-addr -- )
Store cell to aligned address.
99 X !
WAFER: IR [Store]. Compiles to WASM i32.store.
See: @ C! 2! +! F! core memory-ops ir-primitive C@ ( c-addr -- char )
Fetch single byte (zero-extended to cell).
S" ABC" DROP C@ . \ 65 (ASCII 'A')
WAFER: IR [CFetch]. Compiles to WASM i32.load8_u.
See: C! @ COUNT core memory-ops ir-primitive C! ( char c-addr -- )
Store single byte (low 8 bits of char).
65 PAD C! PAD C@ . \ 65
WAFER: IR [CStore]. Compiles to WASM i32.store8.
See: C@ ! core memory-ops ir-primitive +! ( n a-addr -- )
Add n to the cell at a-addr. Atomic read-modify-write idiom.
VARIABLE CTR 0 CTR ! 5 CTR +! CTR @ . \ 5
WAFER: IR [PlusStore]. Compiles to load + add + store sequence.
See: @ ! 1+ core memory-ops ir-primitive 2@ ( a-addr -- x1 x2 )
Fetch cell pair. x2 is from a-addr, x1 from a-addr+cell. Note: high cell is at lower address (big-endian pair order).
WAFER: Host function.
See: 2! @ 2DUP core memory-ops host-function 2! ( x1 x2 a-addr -- )
Store cell pair. x2 stored at a-addr, x1 at a-addr+cell.
WAFER: Host function.
See: 2@ ! 2DROP core memory-ops host-function HERE ( -- addr )
Address of next available dictionary space. Moves as you ALLOT or comma.
HERE . \ shows current dictionary pointer
WAFER: Host function. Reads system variable at address 0x0C.
See: ALLOT , C, UNUSED core memory-ops host-function ALLOT ( n -- )
Reserve n address units (bytes) at HERE. Negative values reclaim space.
CREATE BUFFER 100 ALLOT \ allocate 100 bytes
WAFER: Host function. Advances HERE pointer.
See: HERE CREATE , core memory-ops host-function , (comma) ( x -- )
Compile cell value at HERE and advance HERE by one cell. Used to build data structures.
CREATE TABLE 1 , 2 , 3 ,
WAFER: Host function.
See: C, HERE ALLOT core memory-ops host-function C, ( char -- )
Compile byte at HERE and advance HERE by one byte.
WAFER: Host function.
See: , HERE core memory-ops host-function CELLS ( n -- n*cell )
Convert cell count to address units. Cell = 4 bytes in WAFER (32-bit).
10 CELLS . \ 40
WAFER: IR [PushI32(4), Mul]. Strength-reduced to 2 LSHIFT.
See: CELL+ CHARS FLOATS core memory-ops ir-primitive CELL+ ( a-addr -- a-addr' )
Add one cell size. Steps to next cell in memory.
WAFER: IR [PushI32(4), Add].
See: CELLS CHAR+ core memory-ops ir-primitive CHARS ( n -- n*char )
Convert character count to address units. In WAFER (byte-addressed), this is a no-op (1 char = 1 byte).
WAFER: IR [] (identity). CHARS is zero IR ops.
See: CHAR+ CELLS core memory-ops ir-primitive CHAR+ ( c-addr -- c-addr' )
Add one character size (1 byte).
WAFER: IR [PushI32(1), Add].
See: CHARS CELL+ core memory-ops ir-primitive ALIGNED ( addr -- a-addr )
Round up to next cell-aligned address. (addr + 3) AND NOT 3.
5 ALIGNED . \ 8
WAFER: IR [PushI32(3), Add, PushI32(3), Invert, And].
See: ALIGN FALIGNED core memory-ops ir-primitive ALIGN ( -- )
Align HERE to cell boundary. Always call after storing non-cell data with C,.
WAFER: Host function. Sets HERE = ALIGNED(HERE).
See: ALIGNED FALIGN core memory-ops host-function MOVE ( addr1 addr2 u -- )
Copy u bytes from addr1 to addr2. Handles overlapping regions correctly (like C memmove).
WAFER: Host function. Rust memcpy with overlap detection.
See: CMOVE CMOVE> FILL core memory-ops host-function FILL ( c-addr u char -- )
Fill u bytes starting at c-addr with char.
PAD 10 42 FILL \ fill PAD with '*'
WAFER: Host function.
See: ERASE BLANK MOVE core memory-ops host-function >R ( x -- ) ( R: -- x )
Push to return stack. Must be balanced with R> within same definition. Cannot cross control-flow boundaries (IF/THEN, DO/LOOP).
: 3RD >R >R DUP R> R> ROT ; \ copy third item
WAFER: IR [ToR]. Return stack at 0x1540-0x2540.
See: R> R@ 2>R core return-stack ir-primitive R> ( -- x ) ( R: x -- )
Pop from return stack to data stack. Every >R must have a matching R>.
WAFER: IR [FromR].
See: >R R@ core return-stack ir-primitive R@ ( -- x ) ( R: x -- x )
Copy top of return stack without consuming. Same as I inside a DO loop.
WAFER: IR [RFetch].
See: >R R> I core return-stack ir-primitive IF Compilation: ( -- orig )
Runtime: ( x -- )

Conditional branch. Consumes flag; branches to ELSE or THEN if zero. Non-zero = true (any bits set).
: SIGN DUP 0< IF ." negative" ELSE ." non-negative" THEN ;
WAFER: Special token. Compiles to IR If{then,else} block. Nests arbitrarily.
See: ELSE THEN ?DUP core control-flow special-token ELSE Compilation: ( orig1 -- orig2 )
Optional false branch of IF. Execution continues at THEN.
WAFER: Special token. Part of If{then,else} IR structure.
See: IF THEN core control-flow special-token THEN Compilation: ( orig -- )
Resolve forward reference from IF or ELSE. Every IF needs exactly one THEN.
WAFER: Special token.
See: IF ELSE core control-flow special-token DO Runtime: ( n1|u1 n2|u2 -- ) ( R: -- loop-sys )
Begin counted loop. n2 is initial index, n1 is limit. Executes body at least once even if limit=index (use ?DO to skip).
10 0 DO I . LOOP \ prints 0 1 2 ... 9
WAFER: Special token. Compiles to IR DoLoop{body, is_plus:false}. Loop params on return stack.
See: LOOP +LOOP I J ?DO LEAVE UNLOOP core control-flow special-token LOOP Runtime: ( -- ) ( R: loop-sys -- )
Increment index by 1. If index crosses the limit boundary, exit loop; otherwise branch to DO.
WAFER: Special token. End of DoLoop IR block.
See: DO +LOOP core control-flow special-token +LOOP Runtime: ( n -- ) ( R: loop-sys -- )
Add n to index. Exits when index crosses limit boundary. Works with negative increments for counting down.
100 0 DO I . 10 +LOOP \ 0 10 20 ... 90
0 10 DO I . -1 +LOOP \ 10 9 8 ... 0
WAFER: Special token. Compiles DoLoop{is_plus:true}.
See: DO LOOP core control-flow special-token I ( -- n ) ( R: loop-sys -- loop-sys )
Current loop index. Same as R@ inside DO…LOOP. Zero overhead — reads return stack directly.
5 0 DO I . LOOP \ 0 1 2 3 4
WAFER: IR [RFetch] (alias of R@).
See: J R@ LEAVE core control-flow ir-primitive J ( -- n ) ( R: loop-sys1 loop-sys2 -- loop-sys1 loop-sys2 )
Outer loop index in nested DO loops. Accesses third item on return stack.
3 0 DO 3 0 DO I J * . LOOP LOOP
WAFER: Host function. Peeks 3 cells deep into return stack.
See: I core control-flow host-function UNLOOP ( -- ) ( R: loop-sys -- )
Discard loop parameters from return stack. Required before EXIT inside a DO loop, otherwise return stack is corrupted.
: FIND-FIRST 10 0 DO I 5 = IF I UNLOOP EXIT THEN LOOP -1 ;
WAFER: IR [UnloopOp]. Drops 3 return stack cells (index, limit, leave-addr).
See: LEAVE EXIT core control-flow ir-primitive LEAVE ( -- ) ( R: loop-sys -- )
Exit DO loop immediately. Execution continues after LOOP/+LOOP.
100 0 DO I 50 > IF LEAVE THEN LOOP
WAFER: Host function. Sets index = limit to force loop exit.
See: UNLOOP EXIT core control-flow host-function BEGIN Compilation: ( -- dest )
Mark loop beginning. Used with UNTIL, WHILE/REPEAT, or AGAIN.
WAFER: Special token. Marks start of IR loop block.
See: UNTIL WHILE REPEAT AGAIN core control-flow special-token UNTIL Runtime: ( x -- )
Loop back to BEGIN if false. Exit when true. Post-test loop (body executes at least once).
BEGIN DUP . 1- DUP 0= UNTIL DROP
WAFER: Special token. Compiles to IR BeginUntil{body}.
See: BEGIN WHILE REPEAT core control-flow special-token WHILE Runtime: ( x -- )
Test condition mid-loop. If false, exit to after REPEAT. Pre-test when placed at start of loop body.
BEGIN DUP WHILE DUP . 1- REPEAT DROP
WAFER: Special token. Part of IR BeginWhileRepeat{test, body}.
See: BEGIN REPEAT UNTIL core control-flow special-token REPEAT Compilation: ( -- )
Unconditional branch back to BEGIN. Loop continues at the WHILE test.
WAFER: Special token.
See: BEGIN WHILE core control-flow special-token RECURSE Compilation: ( -- )
Compile a call to the currently-being-defined word. Because the word is HIDDEN during compilation, you can't use its name.
: FACTORIAL DUP 1 > IF DUP 1- RECURSE * ELSE DROP 1 THEN ;
WAFER: Special token. Emits IR Call(current_word_id). Eligible for tail-call optimization when last operation.
See: EXIT core control-flow special-token EXIT ( -- )
Return from current word immediately. Inside DO loops, UNLOOP first! After EXIT, remaining code in the word is dead.
WAFER: Special token. Compiles IR Exit. DCE removes code after unconditional EXIT.
See: RECURSE UNLOOP ; LEAVE core control-flow special-token : (colon) ( C: "<spaces>name" -- colon-sys )
Begin new word definition. Enters compile mode. The word is HIDDEN until ; reveals it.
: SQUARE DUP * ;
WAFER: Special token. Creates dictionary entry (HIDDEN), switches to compile mode, allocates new WordId.
See: ; :NONAME IMMEDIATE core defining special-token ; (semicolon) Compilation: ( colon-sys -- )
End word definition. Compiles EXIT, optimizes IR, generates WASM module, reveals word, returns to interpret mode.
WAFER: Special token. Triggers full pipeline: IR → optimize → codegen → wasmtime instantiate → reveal.
See: : EXIT core defining special-token VARIABLE ( "<spaces>name" -- )
Create word that pushes address of a cell. Initialized to 0 in WAFER. Usage: VARIABLE X 42 X ! X @ .
WAFER: Special token. Allocates 4 bytes in user data space (starts at 0x10000). Word pushes the address.
See: CONSTANT VALUE CREATE 2VARIABLE core defining special-token CONSTANT ( x "<spaces>name" -- )
Create word that pushes x. Immutable after creation — use VALUE if you need mutability.
42 CONSTANT ANSWER ANSWER . \ 42
WAFER: Special token. Compiled as IR PushI32(x). Inlined by optimizer.
See: VARIABLE VALUE 2CONSTANT FCONSTANT core defining special-token CREATE ( "<spaces>name" -- )
Create a word that pushes the address of its data field. Foundation for all defining words. Use with DOES> for custom defining words.
CREATE TABLE 10 , 20 , 30 ,
TABLE 2 CELLS + @ . \ 30
WAFER: Special token. Allocates dictionary header, word pushes parameter field address.
See: DOES> ALLOT , VARIABLE core defining special-token DOES> ( -- a-addr )
Define runtime behavior for words created by the enclosing defining word. Code after DOES> runs when a CREATE'd word executes, with the data address on stack.
: ARRAY CREATE CELLS ALLOT DOES> SWAP CELLS + ;
5 ARRAY X 42 3 X ! 3 X @ . \ 42
WAFER: Special token + host function (_DOES_PATCH_). Patches the child word's code field to run the DOES> body. Supports double-DOES>.
See: CREATE core defining special-token IMMEDIATE ( -- )
Mark most recently defined word as immediate. Immediate words execute during compilation instead of being compiled. Used for compile-time computation and syntax extensions.
: [MOD] MOD ; IMMEDIATE
WAFER: Host function. Sets IMMEDIATE flag (0x80) in dictionary entry.
See: POSTPONE [ ] core defining host-function . (dot) ( n -- )
Print signed integer followed by a space. Uses current BASE.
42 . \ prints "42 "
HEX 255 . \ prints "FF "
WAFER: Host function. Formats via Rust, appends to output buffer.
See: U. .R D. F. core io host-function U. ( u -- )
Print unsigned integer followed by a space. Critical difference from . for values > MAX-INT.
-1 U. \ prints "4294967295 " (on 32-bit)
WAFER: Host function.
See: . U.R core io host-function EMIT ( x -- )
Output character with code x. Low 8 bits used.
65 EMIT \ prints 'A'
: STARS 0 DO 42 EMIT LOOP ;
WAFER: IR [Emit]. Compiles to host call for output.
See: TYPE CR KEY core io ir-primitive CR ( -- )
Output newline character.
WAFER: IR [Cr].
See: EMIT SPACE core io ir-primitive SPACE ( -- )
Output single space (BL EMIT).
WAFER: IR [PushI32(32), Emit].
See: SPACES BL CR core io ir-primitive SPACES ( n -- )
Output n spaces. If n ≤ 0, does nothing.
WAFER: Host function. Loop of EMIT(32).
See: SPACE core io host-function TYPE ( c-addr u -- )
Output u characters starting at c-addr.
S" Hello" TYPE \ prints Hello
WAFER: IR [Type] / Host function.
See: EMIT ." S" core io host-function ." (dot-quote) Compilation: ( "ccc<quote>" -- )
Runtime: ( -- )

Compile and display string literal. In interpret mode, displays immediately.
: GREET ." Hello, World!" CR ;
WAFER: Special token. In compile mode, stores string in data space and compiles Type IR. In interpret mode, outputs immediately.
See: S" TYPE core io special-token S" (s-quote) Compilation: ( "ccc<quote>" -- )
Runtime: ( -- c-addr u )

String literal. Pushes address and length. In interpret mode, string is transient (valid until next S" or buffer reuse).
S" Hello" TYPE
WAFER: Special token. Compile mode: stores in data space, compiles PushI32 pair. Interpret mode: stores at HERE temporarily.
See: ." S\" C" SLITERAL core io special-token ACCEPT ( c-addr +n1 -- +n2 )
Read up to n1 characters into buffer at c-addr. Returns actual count n2. Implementation-defined line editing.
WAFER: Host function. Reads from input source.
See: KEY REFILL SOURCE core io host-function KEY ( -- char )
Receive one character. Blocks until available. No echo.
WAFER: Host function.
See: KEY? ACCEPT EMIT core io host-function .R ( n1 n2 -- )
Print n1 right-justified in field of n2 characters. Uses current BASE.
42 10 .R \ prints " 42"
WAFER: Host function.
See: . U.R D.R core-ext io host-function CHAR ( "<spaces>name" -- char )
Parse word and push ASCII value of first character. Interpretation-time only.
CHAR A . \ 65
WAFER: Special token (interpret mode).
See: [CHAR] BL core parsing special-token [CHAR] Compilation: ( "<spaces>name" -- )
Compile character literal. Immediate word — executes during compilation to push ASCII code.
: EMIT-A [CHAR] A EMIT ;
WAFER: Special token. Compiles IR PushI32(char_code).
See: CHAR LITERAL core parsing special-token WORD ( char "<chars>ccc<char>" -- c-addr )
Parse using delimiter char. Returns counted string at HERE. Obsolescent — prefer PARSE-NAME.
CHAR | WORD COUNT TYPE \ parses until |
WAFER: Host function. Stores counted string at HERE.
See: PARSE PARSE-NAME FIND core parsing host-function FIND ( c-addr -- c-addr 0 | xt 1 | xt -1 )
Search dictionary for counted string. Returns xt and 1 (immediate) or -1 (normal), or original addr and 0 if not found.
WAFER: Host function. Uses hash index for O(1) lookup.
See: ' WORD SEARCH-WORDLIST core parsing host-function COUNT ( c-addr -- c-addr+1 u )
Convert counted string to addr-length pair. First byte is length.
WAFER: Host function.
See: WORD S" core parsing host-function >NUMBER ( ud1 c-addr1 u1 -- ud2 c-addr2 u2 )
Accumulate digits from string into double ud. Stops at first non-digit. u2=0 means entire string consumed.
0. S" 123" >NUMBER 2DROP D. \ 123
WAFER: Host function. Respects current BASE.
See: BASE core parsing host-function EXECUTE ( i*x xt -- j*x )
Execute the word identified by execution token xt. Foundation for callbacks, dispatch tables, and deferred execution.
' DUP EXECUTE \ same as DUP
WAFER: IR [Execute]. Compiles to WASM call_indirect. The function table index is the xt.
See: ' ['] DEFER COMPILE, core compilation ir-primitive ' (tick) ( "<spaces>name" -- xt )
Parse word name and return its execution token. Interpretation-time only — use ['] in compile mode. Throws -13 if word not found.
' DUP EXECUTE \ executes DUP
WAFER: Host function. xt = function table index (WordId).
See: ['] EXECUTE >BODY FIND core compilation host-function ['] (bracket-tick) Compilation: ( "<spaces>name" -- )
Compile xt of next word as a literal. Immediate. Use inside definitions where ' would execute at compile time.
: DO-DUP ['] DUP EXECUTE ;
WAFER: Special token. Compiles IR PushI32(xt).
See: ' LITERAL POSTPONE core compilation special-token >BODY ( xt -- a-addr )
Convert execution token to data-field address. Only valid for CREATE'd words. Result undefined for : definitions.
CREATE X 42 , ' X >BODY @ . \ 42
WAFER: Host function. Reads parameter field address from dictionary entry.
See: CREATE ' EXECUTE core compilation host-function LITERAL Compilation: ( x -- )
Runtime: ( -- x )

Compile TOS as a literal. Immediate. Used in macros and [ ] sequences.
: CACHE-SIZE [ 64 1024 * ] LITERAL ;
WAFER: Special token. Compiles IR PushI32(x). Constant folding may further optimize.
See: 2LITERAL FLITERAL SLITERAL ['] core compilation special-token POSTPONE Compilation: ( "<spaces>name" -- )
Defer compilation of next word. For immediate words: compiles their code. For non-immediate: compiles code that will compile them. The key mechanism for writing compile-time words.
: MY-IF POSTPONE IF ; IMMEDIATE
: [+] POSTPONE + ; IMMEDIATE
WAFER: Special token. Emits IR for immediate words directly; for non-immediate, emits LITERAL(xt) + COMPILE, sequence.
See: IMMEDIATE COMPILE, [COMPILE] core compilation special-token [ (left-bracket) ( -- )
Switch to interpret mode during compilation. Lets you compute values at compile time.
: X [ 6 7 * ] LITERAL ; X . \ 42
WAFER: Special token. Sets STATE to 0. Immediate.
See: ] LITERAL STATE core compilation special-token ] (right-bracket) ( -- )
Switch to compile mode.
WAFER: Special token. Sets STATE to -1.
See: [ STATE core compilation special-token EVALUATE ( i*x c-addr u -- j*x )
Interpret/compile the string as Forth source. Saves and restores input source specification. Powerful but dangerous — runtime code generation.
S" 2 3 +" EVALUATE . \ 5
WAFER: Host function. Recursively calls outer interpreter on the string.
See: SOURCE >IN core compilation host-function ABORT ( i*x -- ) ( R: j*x -- )
Clear stacks and return to outer interpreter. Equivalent to -1 THROW.
WAFER: Host function.
See: ABORT" THROW QUIT core compilation host-function ABORT" Compilation: ( "ccc<quote>" -- )
Runtime: ( i*x x -- | i*x )

If x is non-zero, display string and abort. Conditional abort with message.
: CHECK DUP 0< ABORT" negative!" ;
WAFER: Special token. Compiles as IF + string + ABORT sequence.
See: ABORT THROW core compilation special-token QUIT ( -- )
Clear return stack, set interpret mode, enter outer interpreter loop. Does not clear data stack (unlike ABORT).
WAFER: Host function.
See: ABORT BYE core compilation host-function STATE ( -- a-addr )
Address of compilation state flag. 0 = interpreting, non-zero = compiling. Do NOT use STATE to write mode-dependent words — use POSTPONE instead.
WAFER: IR primitive. Returns address of system variable at offset 0x00.
See: [ ] POSTPONE core compilation ir-primitive BASE ( -- a-addr )
Address of current number base. Default 10 (decimal). Valid range 2-36.
HEX BASE @ . \ 10 (printed in hex = 16)
WAFER: IR primitive. System variable at offset 0x04.
See: DECIMAL HEX core compilation ir-primitive >IN ( -- a-addr )
Address of input parse position. Offset into current input buffer. Manipulating >IN allows re-parsing (e.g., for POSTPONE).
WAFER: IR primitive. System variable at offset 0x08.
See: SOURCE WORD PARSE core compilation ir-primitive SOURCE ( -- c-addr u )
Current input source buffer and length.
WAFER: Host function. Returns input buffer address and length.
See: >IN EVALUATE REFILL core compilation host-function DECIMAL ( -- )
Set BASE to 10.
WAFER: Host function. Stores 10 to BASE variable.
See: HEX BASE core compilation host-function BL ( -- char )
Push space character (32).
BL EMIT \ same as SPACE
WAFER: IR [PushI32(32)].
See: SPACE CHAR core compilation ir-primitive TRUE ( -- true )
Well-formed true flag: -1 (all bits set). Any non-zero is logically true, but only -1 is canonical TRUE.
WAFER: IR [PushI32(-1)].
See: FALSE 0= AND OR core compilation ir-primitive FALSE ( -- false )
Canonical false flag: 0.
WAFER: IR [PushI32(0)].
See: TRUE 0= core compilation ir-primitive ENVIRONMENT? ( c-addr u -- false | i*x true )
Query implementation environment. Returns info about system capabilities.
S" MAX-N" ENVIRONMENT? IF . THEN
WAFER: Host function. Supports queries like MAX-N, MAX-U, ADDRESS-UNIT-BITS, STACK-CELLS, RETURN-STACK-CELLS. core compilation host-function <# ( -- )
Begin pictured numeric output. Initializes the output buffer (grows right to left from PAD end).
: U. 0 <# #S #> TYPE SPACE ;
WAFER: Host function. Sets HLD pointer to end of PAD area.
See: # #S #> HOLD SIGN core pictured-numeric host-function # (number-sign) ( ud1 -- ud2 )
Convert one digit of ud, prepend to pictured output. Divides ud by BASE, converts remainder to ASCII digit.
0 42 <# # # #> TYPE \ "42"
WAFER: Host function. Uses UM/MOD internally.
See: #S <# #> core pictured-numeric host-function #S ( ud -- 0 0 )
Convert all remaining digits. Calls # repeatedly until ud is zero. Always generates at least one digit.
0 0 <# #S #> TYPE \ "0"
WAFER: Host function.
See: # <# #> core pictured-numeric host-function #> ( xd -- c-addr u )
End pictured output. Drops the double number, returns buffer address and length. Buffer is transient.
WAFER: Host function.
See: <# # #S TYPE core pictured-numeric host-function HOLD ( char -- )
Prepend character to pictured output. Used between <# and #> for custom formatting (decimal points, separators).
: D. TUCK DABS <# #S ROT SIGN #> TYPE SPACE ;
WAFER: Host function.
See: HOLDS SIGN <# core pictured-numeric host-function SIGN ( n -- )
If n is negative, prepend '-' to pictured output. Must be called after #S (since output builds right to left, sign goes last).
WAFER: Host function.
See: HOLD <# #S core pictured-numeric host-function NIP ( x1 x2 -- x2 )
Remove second item. Equivalent to SWAP DROP. Cleans up after you've extracted what you need from NOS.
/MOD NIP \ keep only quotient
WAFER: IR [Nip]. Peephole target: SWAP DROP → NIP.
See: DROP TUCK core-ext stack ir-primitive TUCK ( x1 x2 -- x2 x1 x2 )
Copy TOS below second item. Equivalent to SWAP OVER. Useful when you need to save TOS before a consuming operation.
: !+ TUCK ! CELL+ ; \ store and advance
WAFER: IR [Tuck]. Peephole target: SWAP OVER → TUCK.
See: NIP OVER core-ext stack ir-primitive 0<> ( x -- flag )
True if not zero. Logical identity for non-canonical flags: normalizes any non-zero to TRUE.
42 0<> . \ -1
WAFER: IR [ZeroEq, ZeroEq] (double negate). Normalizes to well-formed flag.
See: 0= <> core-ext comparison ir-primitive 0> ( n -- flag )
True if strictly positive (greater than zero).
1 0> . \ -1
0 0> . \ 0
WAFER: IR [PushI32(0), Gt].
See: 0< 0= 0<> core-ext comparison ir-primitive <> ( x1 x2 -- flag )
True if not equal. Complement of =.
WAFER: IR [NotEq].
See: = 0<> core-ext comparison ir-primitive U> ( u1 u2 -- flag )
Unsigned greater-than.
WAFER: IR [LtUnsigned with swapped operands] or host function.
See: U< > core-ext comparison 2>R ( x1 x2 -- ) ( R: -- x1 x2 )
Push cell pair to return stack. Useful for saving double-cell values.
WAFER: IR [TwoToR].
See: 2R> 2R@ >R core-ext return-stack ir-primitive 2R> ( -- x1 x2 ) ( R: x1 x2 -- )
Pop cell pair from return stack.
WAFER: IR [TwoFromR].
See: 2>R 2R@ R> core-ext return-stack ir-primitive 2R@ ( -- x1 x2 ) ( R: x1 x2 -- x1 x2 )
Copy cell pair from return stack.
WAFER: IR [TwoRFetch].
See: 2>R 2R> R@ core-ext return-stack ir-primitive VALUE ( x "<spaces>name" -- )
Create word that pushes x. Unlike CONSTANT, can be changed with TO. Cleaner than VARIABLE for simple storage.
42 VALUE ANSWER ANSWER . \ 42
99 TO ANSWER ANSWER . \ 99
WAFER: Special token. Stores in data space; TO modifies the stored value.
See: TO CONSTANT VARIABLE 2VALUE FVALUE core-ext defining special-token TO Interpretation: ( x "<spaces>name" -- )
Compilation: ( "<spaces>name" -- )

Change a VALUE. Works at both interpret and compile time.
99 TO MY-VALUE
WAFER: Special token. Compiles store to VALUE's data address.
See: VALUE 2VALUE FVALUE core-ext defining special-token DEFER ( "<spaces>name" -- )
Create word with deferred execution. Initially calls ABORT. Set with DEFER! or IS. Enables late binding and forward references.
DEFER GREET : SAY-HI ." Hi!" ; ' SAY-HI IS GREET
WAFER: Special token. Word calls through a stored xt.
See: DEFER! DEFER@ IS ACTION-OF core-ext defining special-token DEFER! ( xt2 xt1 -- )
Store xt2 as the behavior of deferred word xt1.
' NEW-BEHAVIOR ' MY-DEFER DEFER!
WAFER: Host function.
See: DEFER DEFER@ IS core-ext defining host-function DEFER@ ( xt1 -- xt2 )
Fetch the current xt stored in deferred word xt1.
WAFER: Host function.
See: DEFER DEFER! ACTION-OF core-ext defining host-function IS Interpretation: ( xt "<spaces>name" -- )
Compilation: ( "<spaces>name" -- )

Set DEFER'd word or VALUE. Syntactic sugar for DEFER! with name lookup.
' NEW-IMPL IS MY-DEFER
WAFER: Special token. Resolves name, calls DEFER!.
See: DEFER TO ACTION-OF core-ext defining special-token ACTION-OF Interpretation: ( "<spaces>name" -- xt )
Compilation: ( "<spaces>name" -- )

Get the xt currently assigned to a DEFER'd word. Compile-time: compiles code to push it at runtime.
WAFER: Special token.
See: DEFER@ IS core-ext defining special-token ?DO Runtime: ( n1|u1 n2|u2 -- ) ( R: -- loop-sys )
Like DO but skips body if limit=index. Compiles as IF check + DO. Always prefer ?DO unless you know limit ≠ index.
: STARS 0 ?DO [CHAR] * EMIT LOOP ; \ 0 STARS does nothing
WAFER: Special token. Compiles as 2DUP = IF 2DROP ELSE DO ... LOOP THEN.
See: DO LOOP +LOOP core-ext control-flow special-token AGAIN Compilation: ( -- )
Unconditional loop back to BEGIN. Infinite loop — exit with LEAVE, EXIT, or THROW.
: FOREVER BEGIN ." loop " AGAIN ; \ never returns
WAFER: Special token. Compiles to IR BeginAgain{body}.
See: BEGIN UNTIL WHILE core-ext control-flow special-token CASE Compilation: ( -- case-sys )
Begin CASE structure. Multi-way conditional — Forth's switch statement.
: CHECK CASE
1 OF ." one" ENDOF
2 OF ." two" ENDOF
." other"
ENDCASE ;
WAFER: Special token. Compiles to nested IF/ELSE/THEN.
See: OF ENDOF ENDCASE core-ext control-flow special-token OF Runtime: ( x1 x2 -- | x1 )
Compare TOS to case value. If equal, drop both and execute clause. If not, keep x1 and skip to ENDOF.
WAFER: Special token.
See: CASE ENDOF ENDCASE core-ext control-flow special-token ENDOF Compilation: ( case-sys -- case-sys )
End an OF clause. Branches to after ENDCASE.
WAFER: Special token.
See: OF CASE ENDCASE core-ext control-flow special-token ENDCASE Runtime: ( x -- )
End CASE structure. Drops the selector value.
WAFER: Special token.
See: CASE OF ENDOF core-ext control-flow special-token PAD ( -- c-addr )
Address of transient scratch buffer (256 bytes in WAFER). Separate from dictionary and stacks. Used for string formatting.
WAFER: IR [PushI32(0x0440)]. Address is a compile-time constant.
See: HERE <# S" core-ext memory-ops ir-primitive ERASE ( addr u -- )
Fill u bytes with zero. Equivalent to 0 FILL.
WAFER: Host function.
See: FILL BLANK core-ext memory-ops host-function MARKER ( "<spaces>name" -- )
Create a snapshot. Executing the marker word restores dictionary to the state before the marker was created. Useful for development: redefine everything by calling the marker first.
MARKER CLEAN : FOO ." test" ; CLEAN \ FOO is forgotten
WAFER: Host function. Saves HERE and LATEST, restores on execution.
See: ALLOT HERE core-ext defining host-function BUFFER: ( u "<spaces>name" -- )
Create word that pushes address of u-byte buffer. Like CREATE n ALLOT but more portable.
256 BUFFER: LINE-BUF
WAFER: Special token.
See: CREATE ALLOT VARIABLE core-ext defining special-token :NONAME ( -- xt )
Begin anonymous word definition. Returns execution token. No dictionary entry created.
:NONAME DUP * ; CONSTANT SQUARE-XT
5 SQUARE-XT EXECUTE . \ 25
WAFER: Special token. Allocates WordId but no dictionary header.
See: : DEFER EXECUTE core-ext defining special-token COMPILE, ( xt -- )
Append call to xt to current definition. Runtime compilation. Used by POSTPONE for non-immediate words.
WAFER: Host function. Appends IR Call(word_id) to compiling_ir.
See: POSTPONE LITERAL EXECUTE core-ext compilation host-function C" Compilation: ( "ccc<quote>" -- )
Runtime: ( -- c-addr )

Counted string literal. First byte is length, followed by characters. Max 255 chars.
WAFER: Special token.
See: S" COUNT core-ext io special-token S\" (s-backslash-quote) Compilation: ( "ccc<quote>" -- )
Runtime: ( -- c-addr u )

String literal with escape sequences: \n (newline), \t (tab), \\ (backslash), \" (quote), \0 (null), \x41 (hex byte).
S\" Hello\nWorld" TYPE
WAFER: Special token. Parses escape sequences at compile time.
See: S" core-ext io special-token .( (dot-paren) ( "ccc<paren>" -- )
Display string immediately (delimited by closing paren). Immediate — works in both modes. Useful for compile-time messages.
.( Compiling... )
WAFER: Special token.
See: ." TYPE core-ext io special-token \ (backslash) ( -- )
Line comment — skip rest of input line. Immediate.
: FOO DUP * ; \ this is a comment
WAFER: Special token. Sets >IN to end of input buffer.
See: ( core-ext parsing special-token ( (paren) ( "ccc<paren>" -- )
Block comment — skip until closing paren. Immediate. Can span multiple lines (if input provides them). Convention: stack comments in parentheses.
: FOO ( n -- n*n ) DUP * ;
WAFER: Special token.
See: \ core parsing special-token PARSE ( char "ccc<char>" -- c-addr u )
Parse input delimited by char. Does not skip leading delimiters (unlike WORD). Returns pointer into input buffer.
WAFER: Host function.
See: PARSE-NAME WORD core-ext parsing host-function PARSE-NAME ( "<spaces>name" -- c-addr u )
Parse whitespace-delimited name. Skips leading whitespace. Preferred over WORD for modern Forth.
WAFER: Host function.
See: PARSE WORD core-ext parsing host-function REFILL ( -- flag )
Attempt to refill the input buffer. Returns TRUE if successful. Returns FALSE for string input (EVALUATE).
WAFER: Host function.
See: SOURCE EVALUATE core-ext parsing host-function HOLDS ( c-addr u -- )
Prepend string to pictured numeric output. Like HOLD but for multiple characters at once.
WAFER: Host function.
See: HOLD <# #> core-ext pictured-numeric host-function HEX ( -- )
Set BASE to 16.
HEX FF . \ 255 (in hex output: FF)
WAFER: Host function.
See: DECIMAL BASE core-ext compilation host-function UNUSED ( -- u )
Number of address units remaining in data space.
WAFER: Host function.
See: HERE ALLOT core-ext memory-ops host-function SOURCE-ID ( -- 0 | -1 )
Input source identifier: 0 for user input, -1 for EVALUATE string.
WAFER: Host function.
See: SOURCE EVALUATE core-ext compilation host-function [COMPILE] Compilation: ( "<spaces>name" -- )
Obsolescent. Compile the immediately-following word even if it's immediate. Replaced by POSTPONE in modern Forth.
Not recommended. Use POSTPONE instead.
See: POSTPONE core-ext compilation 2CONSTANT ( x1 x2 "<spaces>name" -- )
Create word that pushes double-cell constant.
1000000. 2CONSTANT BIG
WAFER: Special token.
See: CONSTANT 2VARIABLE DCONSTANT core-ext defining special-token 2VARIABLE ( "<spaces>name" -- )
Create word that pushes address of double-cell variable.
WAFER: Special token. Allocates 8 bytes.
See: VARIABLE 2CONSTANT core-ext defining special-token 2VALUE ( x1 x2 "<spaces>name" -- )
Create word that pushes double-cell value. Change with TO.
WAFER: Special token.
See: VALUE 2CONSTANT TO double-ext defining special-token 2LITERAL Compilation: ( x1 x2 -- )
Runtime: ( -- x1 x2 )

Compile double-cell literal. Immediate.
WAFER: Special token. Compiles two IR PushI32 ops.
See: LITERAL FLITERAL double compilation special-token D+ ( d1 d2 -- d3 )
Double-cell addition. Handles carry between low and high cells.
1. 2. D+ D. \ 3
WAFER: Host function. Uses Rust i64 arithmetic.
See: D- + M+ double arithmetic host-function D- ( d1 d2 -- d3 )
Double-cell subtraction.
WAFER: Host function.
See: D+ - DNEGATE double arithmetic host-function D. ( d -- )
Print signed double-cell number followed by space.
-1. D. \ -1
WAFER: Host function.
See: D.R . U. double io host-function D.R ( d n -- )
Print double-cell number right-justified in n-character field.
WAFER: Host function.
See: D. .R double io host-function D0= ( d -- flag )
True if double is zero. Both cells must be zero.
WAFER: Host function.
See: D0< 0= D= double comparison host-function D0< ( d -- flag )
True if double is negative. Tests sign bit of high cell.
WAFER: Host function.
See: D0= 0< double comparison host-function D= ( d1 d2 -- flag )
True if two doubles are equal.
WAFER: Host function.
See: D< = D0= double comparison host-function D< ( d1 d2 -- flag )
Signed double less-than.
WAFER: Host function.
See: D= DU< < double comparison host-function DU< ( ud1 ud2 -- flag )
Unsigned double less-than.
WAFER: Host function.
See: D< U< double comparison host-function DNEGATE ( d -- -d )
Negate double-cell number. Two's complement across both cells.
WAFER: Host function.
See: NEGATE DABS double arithmetic host-function DABS ( d -- ud )
Double-cell absolute value.
WAFER: Host function.
See: DNEGATE ABS double arithmetic host-function D2* ( d -- d*2 )
Double-cell left shift by 1. Shifts carry between cells.
WAFER: Host function.
See: D2/ 2* double arithmetic host-function D2/ ( d -- d/2 )
Double-cell arithmetic right shift by 1. Preserves sign.
WAFER: Host function.
See: D2* 2/ double arithmetic host-function DMAX ( d1 d2 -- d3 )
Signed double-cell maximum.
WAFER: Host function.
See: DMIN MAX double arithmetic host-function DMIN ( d1 d2 -- d3 )
Signed double-cell minimum.
WAFER: Host function.
See: DMAX MIN double arithmetic host-function D>S ( d -- n )
Convert double to single by dropping high cell. Result is undefined if d doesn't fit in a single cell.
WAFER: IR primitive. Just drops the high cell.
See: S>D double-ext conversion ir-primitive M+ ( d n -- d' )
Add single-cell to double-cell.
WAFER: Host function. Sign-extends n, then D+.
See: D+ + double arithmetic host-function M*/ ( d1 n1 +n2 -- d2 )
Multiply double d1 by n1, divide by +n2. Triple-cell intermediate avoids overflow. n2 must be positive.
WAFER: Host function. Uses Rust i128 intermediate.
See: */ M* double arithmetic host-function 2ROT ( x1 x2 x3 x4 x5 x6 -- x3 x4 x5 x6 x1 x2 )
Rotate third cell pair to top. The double-width version of ROT.
WAFER: Host function.
See: ROT 2SWAP 2OVER double stack host-function CATCH ( i*x xt -- j*x 0 | i*x n )
Execute xt, catching any THROW. Returns 0 if no exception, or the throw code n. Saves and restores stacks on exception.
: SAFE ['] RISKY CATCH IF ." error!" THEN ;
WAFER: Host function. Saves DSP/RSP/FSP. Nested CATCH supported.
See: THROW ABORT exception control-flow host-function THROW ( k*x n -- k*x | i*x n )
Throw exception n. If n=0, does nothing. If no matching CATCH, behaves as ABORT. Standard codes: -1 ABORT, -2 ABORT", -4 stack underflow, -13 undefined word.
: CHECK DUP 0< IF -24 THROW THEN ;
WAFER: Host function. Unwinds to nearest CATCH, restoring stacks.
See: CATCH ABORT ABORT" exception control-flow host-function COMPARE ( c-addr1 u1 c-addr2 u2 -- n )
Compare two strings. Returns 0 if equal, -1 if first is less, +1 if first is greater. Lexicographic, case-sensitive.
S" ABC" S" ABD" COMPARE . \ -1
WAFER: Host function.
See: SEARCH S= string comparison host-function SEARCH ( c-addr1 u1 c-addr2 u2 -- c-addr3 u3 flag )
Search string1 for string2. If found: c-addr3 points to match, flag=true. If not: original string1, flag=false.
S" Hello World" S" World" SEARCH . TYPE \ -1 World
WAFER: Host function.
See: COMPARE /STRING string parsing host-function /STRING ( c-addr u n -- c-addr' u' )
Advance string by n characters. Adds n to c-addr, subtracts n from u.
S" Hello" 2 /STRING TYPE \ llo
WAFER: Host function.
See: SEARCH -TRAILING string memory-ops host-function BLANK ( c-addr u -- )
Fill u bytes with spaces (BL). Equivalent to BL FILL.
WAFER: Host function.
See: FILL ERASE string memory-ops host-function -TRAILING ( c-addr u1 -- c-addr u2 )
Remove trailing spaces. Adjusts length; address unchanged.
S" hello " -TRAILING TYPE . \ "hello" 5
WAFER: Host function.
See: /STRING BLANK string parsing host-function CMOVE ( c-addr1 c-addr2 u -- )
Copy u bytes from addr1 to addr2, low address to high. Use when destination is lower than source (or non-overlapping).
WAFER: Host function.
See: CMOVE> MOVE string memory-ops host-function CMOVE> ( c-addr1 c-addr2 u -- )
Copy u bytes from addr1 to addr2, high address to low. Use when destination is higher than source (overlapping).
WAFER: Host function.
See: CMOVE MOVE string memory-ops host-function SLITERAL Compilation: ( c-addr u -- )
Runtime: ( -- c-addr u )

Compile string literal from stack. Immediate. Used in macros that produce strings at compile time.
WAFER: Special token.
See: S" LITERAL 2LITERAL string compilation special-token FDROP ( F: r -- )
Drop top of float stack.
WAFER: Host function. Decrements FSP.
See: FDUP FSWAP DROP float stack host-function FDUP ( F: r -- r r )
Duplicate top of float stack.
3.14e FDUP F* F. \ 9.8596 (pi squared approx)
WAFER: Host function.
See: FDROP FOVER DUP float stack host-function FSWAP ( F: r1 r2 -- r2 r1 )
Exchange top two float stack items.
WAFER: Host function.
See: FROT FOVER SWAP float stack host-function FOVER ( F: r1 r2 -- r1 r2 r1 )
Copy second float to top.
WAFER: Host function.
See: FDUP FSWAP OVER float stack host-function FROT ( F: r1 r2 r3 -- r2 r3 r1 )
Rotate third float to top.
WAFER: Host function.
See: FSWAP ROT float stack host-function FNIP ( F: r1 r2 -- r2 )
Remove second float.
WAFER: Host function.
See: FDROP NIP float stack host-function FTUCK ( F: r1 r2 -- r2 r1 r2 )
Tuck top float below second.
WAFER: Host function.
See: FSWAP TUCK float stack host-function FDEPTH ( -- +n )
Number of values on the float stack.
WAFER: Host function.
See: DEPTH float stack host-function F+ ( F: r1 r2 -- r3 )
Float addition.
1.5e 2.5e F+ F. \ 4.0
WAFER: Host function. Uses f64 add.
See: F- F* D+ float arithmetic host-function F- ( F: r1 r2 -- r3 )
Float subtraction (r1 minus r2).
WAFER: Host function.
See: F+ FNEGATE float arithmetic host-function F* ( F: r1 r2 -- r3 )
Float multiplication.
3.0e 4.0e F* F. \ 12.0
WAFER: Host function.
See: F/ F** float arithmetic host-function F/ ( F: r1 r2 -- r3 )
Float division. Division by zero produces ±Infinity per IEEE 754.
22.0e 7.0e F/ F. \ 3.142857
WAFER: Host function.
See: F* / float arithmetic host-function FNEGATE ( F: r -- -r )
Negate float. Flips sign bit; works on ±0, ±Inf, NaN.
WAFER: Host function.
See: FABS NEGATE float arithmetic host-function FABS ( F: r -- |r| )
Float absolute value.
WAFER: Host function.
See: FNEGATE ABS float arithmetic host-function FMAX ( F: r1 r2 -- r3 )
Float maximum. NaN propagation is implementation-defined.
WAFER: Host function. Uses Rust f64::max.
See: FMIN MAX float arithmetic host-function FMIN ( F: r1 r2 -- r3 )
Float minimum.
WAFER: Host function.
See: FMAX MIN float arithmetic host-function FSQRT ( F: r -- r' )
Square root. Negative input produces NaN.
2.0e FSQRT F. \ 1.41421356...
WAFER: Host function. Uses Rust f64::sqrt.
See: F** FABS float-ext arithmetic host-function FLOOR ( F: r -- r' )
Round toward negative infinity. Returns float, not integer.
3.7e FLOOR F. \ 3.0
-3.2e FLOOR F. \ -4.0
WAFER: Host function.
See: FROUND F>S float arithmetic host-function FROUND ( F: r -- r' )
Round to nearest (banker's rounding: ties to even). Returns float.
2.5e FROUND F. \ 2.0 (ties to even)
3.5e FROUND F. \ 4.0
WAFER: Host function.
See: FLOOR F>S float arithmetic host-function F** ( F: r1 r2 -- r3 )
Float exponentiation: r1 raised to r2.
2.0e 10.0e F** F. \ 1024.0
WAFER: Host function. Uses Rust f64::powf.
See: FSQRT FEXP float-ext arithmetic host-function F0= ( F: r -- ) ( -- flag )
True if float is zero (positive or negative zero).
WAFER: Host function.
See: F0< F= 0= float comparison host-function F0< ( F: r -- ) ( -- flag )
True if float is negative. Negative zero returns false.
WAFER: Host function.
See: F0= 0< float comparison host-function F= ( F: r1 r2 -- ) ( -- flag )
True if floats are exactly equal. Beware: floating-point comparison with == is usually wrong. Prefer F~ for approximate comparison.
WAFER: Host function.
See: F~ F< = float comparison host-function F< ( F: r1 r2 -- ) ( -- flag )
True if r1 < r2. NaN comparisons return false.
WAFER: Host function.
See: F= < float comparison host-function F~ ( F: r1 r2 r3 -- ) ( -- flag )
Approximate float comparison. Three modes: r3>0: |r1-r2| < r3 (absolute). r3=0: exact bitwise equality. r3<0: |r1-r2| < |r3|*(|r1|+|r2|) (relative).
1.0e 3.0e F/ 3.0e F* 1.0e 1e-15 F~ . \ -1 (close enough)
WAFER: Host function.
See: F= F0= float-ext comparison host-function F@ ( f-addr -- ) ( F: -- r )
Fetch 64-bit float from memory to float stack.
FVARIABLE X 3.14e X F! X F@ F.
WAFER: Host function. Reads 8 bytes as f64.
See: F! @ SF@ DF@ float memory-ops host-function F! ( f-addr -- ) ( F: r -- )
Store 64-bit float from float stack to memory.
WAFER: Host function. Writes 8 bytes.
See: F@ ! SF! DF! float memory-ops host-function SF@ ( sf-addr -- ) ( F: -- r )
Fetch 32-bit single-precision float, widen to f64.
WAFER: Host function.
See: SF! F@ DF@ float-ext memory-ops host-function SF! ( sf-addr -- ) ( F: r -- )
Store float as 32-bit single-precision (truncating).
WAFER: Host function.
See: SF@ F! DF! float-ext memory-ops host-function DF@ ( df-addr -- ) ( F: -- r )
Fetch 64-bit double-precision float. Same as F@ in WAFER (native float = f64).
WAFER: Host function. Identical to F@ since WAFER floats are f64.
See: DF! F@ SF@ float-ext memory-ops host-function DF! ( df-addr -- ) ( F: r -- )
Store 64-bit double-precision float. Same as F! in WAFER.
WAFER: Host function.
See: DF@ F! SF! float-ext memory-ops host-function FALIGNED ( addr -- f-addr )
Align address to float boundary (8 bytes).
WAFER: Host function.
See: FALIGN ALIGNED SFALIGNED DFALIGNED float memory-ops host-function FALIGN ( -- )
Align HERE to float boundary.
WAFER: Host function.
See: FALIGNED ALIGN float memory-ops host-function FLOAT+ ( f-addr -- f-addr' )
Add one float size (8 bytes) to address.
WAFER: Host function.
See: FLOATS CELL+ SFLOAT+ DFLOAT+ float memory-ops host-function FLOATS ( n -- n*float )
Convert float count to address units. Multiplies by 8.
WAFER: Host function.
See: FLOAT+ CELLS float memory-ops host-function SFALIGNED ( addr -- sf-addr )
Align to single-float boundary (4 bytes).
WAFER: Host function.
See: SFALIGN FALIGNED float-ext memory-ops host-function SFALIGN ( -- )
Align HERE to single-float boundary.
WAFER: Host function.
See: SFALIGNED FALIGN float-ext memory-ops host-function SFLOAT+ ( sf-addr -- sf-addr' )
Add single-float size (4 bytes).
WAFER: Host function.
See: SFLOATS FLOAT+ float-ext memory-ops host-function SFLOATS ( n -- n*sfloat )
Convert single-float count to address units (×4).
WAFER: Host function.
See: SFLOAT+ FLOATS float-ext memory-ops host-function DFALIGNED ( addr -- df-addr )
Align to double-float boundary (8 bytes).
WAFER: Host function.
See: DFALIGN FALIGNED float-ext memory-ops host-function DFALIGN ( -- )
Align HERE to double-float boundary.
WAFER: Host function.
See: DFALIGNED FALIGN float-ext memory-ops host-function DFLOAT+ ( df-addr -- df-addr' )
Add double-float size (8 bytes).
WAFER: Host function.
See: DFLOATS FLOAT+ float-ext memory-ops host-function DFLOATS ( n -- n*dfloat )
Convert double-float count to address units (×8).
WAFER: Host function.
See: DFLOAT+ FLOATS float-ext memory-ops host-function D>F ( d -- ) ( F: -- r )
Convert double-cell integer to float.
1000000. D>F F. \ 1000000.0
WAFER: Host function. Combines two i32 cells → i64 → f64.
See: F>D S>F float-ext conversion host-function F>D ( F: r -- ) ( -- d )
Convert float to double-cell integer (truncate toward zero).
3.99e F>D D. \ 3
WAFER: Host function.
See: D>F F>S float-ext conversion host-function S>F ( n -- ) ( F: -- r )
Convert single-cell signed integer to float.
42 S>F F. \ 42.0
WAFER: Host function.
See: F>S D>F S>D float-ext conversion host-function F>S ( F: r -- ) ( -- n )
Convert float to single-cell integer (truncate toward zero). Undefined if out of range.
3.7e F>S . \ 3
WAFER: Host function.
See: S>F F>D FLOOR float-ext conversion host-function >FLOAT ( c-addr u -- flag ) ( F: -- r | )
Parse string as float. If successful, push float and return true. Otherwise just return false. Accepts E notation.
S" 3.14" >FLOAT . F. \ -1 3.14
WAFER: Host function. Uses Rust f64 parser.
See: >NUMBER S>F float conversion host-function FSIN ( F: r -- r' )
Sine (radians).
3.14159265e 2.0e F/ FSIN F. \ ≈1.0
WAFER: Host function. Uses Rust f64::sin.
See: FCOS FTAN FASIN FSINCOS float-ext trig host-function FCOS ( F: r -- r' )
Cosine (radians).
0.0e FCOS F. \ 1.0
WAFER: Host function.
See: FSIN FTAN FACOS float-ext trig host-function FTAN ( F: r -- r' )
Tangent (radians).
WAFER: Host function.
See: FSIN FCOS FATAN float-ext trig host-function FASIN ( F: r -- r' )
Arc sine. Input range [-1, 1], output [-π/2, π/2].
WAFER: Host function.
See: FSIN FACOS FATAN float-ext trig host-function FACOS ( F: r -- r' )
Arc cosine. Input [-1, 1], output [0, π].
WAFER: Host function.
See: FCOS FASIN float-ext trig host-function FATAN ( F: r -- r' )
Arc tangent. Output (-π/2, π/2).
WAFER: Host function.
See: FATAN2 FTAN float-ext trig host-function FATAN2 ( F: r1 r2 -- r3 )
Two-argument arc tangent: atan2(r1, r2). Returns angle in (-π, π]. Handles all quadrants correctly. r1 is y, r2 is x.
1.0e 0.0e FATAN2 F. \ ≈1.5708 (π/2)
WAFER: Host function.
See: FATAN FSIN FCOS float-ext trig host-function FSINCOS ( F: r -- r-sin r-cos )
Compute both sine and cosine. More efficient than calling FSIN and FCOS separately.
WAFER: Host function.
See: FSIN FCOS float-ext trig host-function FEXP ( F: r -- r' )
Natural exponential e^r.
1.0e FEXP F. \ ≈2.71828
WAFER: Host function.
See: FLN FEXPM1 FALOG float-ext arithmetic host-function FEXPM1 ( F: r -- r' )
e^r - 1. More accurate than FEXP 1.0 F- for small r (avoids catastrophic cancellation).
1e-15 FEXPM1 F. \ ≈1e-15 (not 0.0)
WAFER: Host function.
See: FEXP FLNP1 float-ext arithmetic host-function FLN ( F: r -- r' )
Natural logarithm. Domain: r > 0.
2.71828e FLN F. \ ≈1.0
WAFER: Host function.
See: FEXP FLOG FLNP1 float-ext arithmetic host-function FLNP1 ( F: r -- r' )
ln(1+r). More accurate than 1.0 F+ FLN for small r.
WAFER: Host function.
See: FLN FEXPM1 float-ext arithmetic host-function FLOG ( F: r -- r' )
Base-10 logarithm.
100.0e FLOG F. \ 2.0
WAFER: Host function.
See: FALOG FLN float-ext arithmetic host-function FALOG ( F: r -- r' )
Base-10 antilogarithm: 10^r.
3.0e FALOG F. \ 1000.0
WAFER: Host function.
See: FLOG FEXP float-ext arithmetic host-function FSINH ( F: r -- r' )
Hyperbolic sine.
WAFER: Host function. Uses Rust f64::sinh.
See: FCOSH FTANH FASINH float-ext trig host-function FCOSH ( F: r -- r' )
Hyperbolic cosine. Always ≥ 1.
WAFER: Host function.
See: FSINH FTANH FACOSH float-ext trig host-function FTANH ( F: r -- r' )
Hyperbolic tangent. Output range (-1, 1).
WAFER: Host function.
See: FSINH FCOSH FATANH float-ext trig host-function FASINH ( F: r -- r' )
Inverse hyperbolic sine.
WAFER: Host function.
See: FSINH float-ext trig host-function FACOSH ( F: r -- r' )
Inverse hyperbolic cosine. Domain: r ≥ 1.
WAFER: Host function.
See: FCOSH float-ext trig host-function FATANH ( F: r -- r' )
Inverse hyperbolic tangent. Domain: |r| < 1.
WAFER: Host function.
See: FTANH float-ext trig host-function F. (f-dot) ( F: r -- )
Print float in free-format with trailing space. Precision controlled by SET-PRECISION (default 6).
3.14159e F. \ 3.14159
WAFER: Host function. Uses Rust formatting.
See: FE. FS. PRECISION float-ext io host-function FE. ( F: r -- )
Print float in engineering notation (exponent is multiple of 3).
12345.0e FE. \ 12.345E3
WAFER: Host function.
See: F. FS. float-ext io host-function FS. ( F: r -- )
Print float in scientific notation (one digit before decimal).
12345.0e FS. \ 1.2345E4
WAFER: Host function.
See: F. FE. float-ext io host-function PRECISION ( -- u )
Current number of significant digits for F. FE. FS. output.
WAFER: Host function. Default 6.
See: SET-PRECISION float-ext io host-function SET-PRECISION ( u -- )
Set number of significant digits for float output.
15 SET-PRECISION 3.14159265358979e F.
WAFER: Host function.
See: PRECISION float-ext io host-function REPRESENT ( c-addr u -- n flag1 flag2 ) ( F: r -- )
Convert float to digit string. Low-level building block for custom float formatting. n = decimal exponent, flag1 = valid, flag2 = negative.
WAFER: Host function.
See: F. <# float io host-function FVARIABLE ( "<spaces>name" -- )
Create float variable (8 bytes). Access with F@ and F!.
FVARIABLE PI 3.14159265e PI F!
WAFER: Special token. Allocates 8 bytes in data space.
See: FCONSTANT FVALUE VARIABLE float defining special-token FCONSTANT ( F: r -- ) ( "<spaces>name" -- )
Create float constant.
3.14159265358979e FCONSTANT PI
WAFER: Special token.
See: FVARIABLE FVALUE CONSTANT float defining special-token FVALUE ( F: r -- ) ( "<spaces>name" -- )
Create float value. Change with TO.
0.0e FVALUE RESULT 3.14e TO RESULT
WAFER: Special token.
See: FCONSTANT FVARIABLE VALUE TO float-ext defining special-token FLITERAL Compilation: ( F: r -- )
Runtime: ( F: -- r )

Compile float literal. Immediate. Used for compile-time float computation.
: PI [ 355e 113e F/ ] FLITERAL ;
WAFER: Special token. Compiles IR PushF64(r).
See: LITERAL 2LITERAL float compilation special-token AT-XY ( u1 u2 -- )
Set cursor position. u1 = column, u2 = row (0-indexed). Sends ANSI escape sequence.
0 0 AT-XY ." top-left"
WAFER: Host function (if implemented). Facility word set. facility io host-function KEY? ( -- flag )
True if a character is available from the input device (non-blocking check).
WAFER: Host function. Facility word set.
See: KEY EKEY? facility io host-function PAGE ( -- )
Clear screen and move cursor to top-left. Implementation-specific escape sequence.
WAFER: Host function. Facility word set.
See: AT-XY CR facility io host-function EKEY ( -- u )
Receive keyboard event (may include function keys, arrows). Extended key — wider than CHAR range.
WAFER: Host function. Facility EXT.
See: KEY EKEY? EKEY>CHAR facility-ext io host-function EKEY>CHAR ( u -- u false | char true )
Convert extended key to character. Returns false if key has no character representation (function key).
WAFER: Host function. Facility EXT.
See: EKEY facility-ext io host-function EKEY? ( -- flag )
Non-blocking check for extended key availability.
WAFER: Host function. Facility EXT.
See: KEY? EKEY facility-ext io host-function EMIT? ( -- flag )
True if the output device is ready to accept a character.
WAFER: Host function. Facility EXT.
See: EMIT KEY? facility-ext io host-function MS ( u -- )
Wait at least u milliseconds.
1000 MS \ pause 1 second
Facility EXT. facility-ext io BEGIN-STRUCTURE ( "<spaces>name" -- addr 0 )
Begin defining a structure type. Pushes initial offset 0.
BEGIN-STRUCTURE POINT FIELD: X FIELD: Y END-STRUCTURE
Facility EXT. Enables type-safe struct-like memory layouts.
See: END-STRUCTURE FIELD: +FIELD facility-ext defining END-STRUCTURE ( addr n -- )
Complete structure definition. Stores total size as a constant.
POINT . \ prints structure size (8 for two cells)
Facility EXT.
See: BEGIN-STRUCTURE FIELD: facility-ext defining FIELD: ( n1 "<spaces>name" -- n2 )
Create cell-width field. Adds CELL to offset. Created word: ( addr -- addr' ).
BEGIN-STRUCTURE COLOR FIELD: R FIELD: G FIELD: B END-STRUCTURE
Facility EXT.
See: +FIELD CFIELD: facility-ext defining +FIELD ( n1 n2 "<spaces>name" -- n3 )
Create field of arbitrary size n2 bytes. Most general field creator.
BEGIN-STRUCTURE FOO 8 +FIELD F1 END-STRUCTURE
Facility EXT.
See: FIELD: CFIELD: facility-ext defining CFIELD: ( n1 "<spaces>name" -- n2 )
Create single-byte field. Like FIELD: but only 1 byte wide.
Facility EXT.
See: FIELD: +FIELD facility-ext defining {: (open-brace-colon) ( -- )
Begin local variable declaration. Forth 2012 locals syntax. Items before | are initialized from stack; items after | are uninitialized.
: QUAD {: a b c x -- res :} a x * x * b x * + c + ;
WAFER: Special token. Locals word set. Names become local variables.
See: (LOCAL) locals defining special-token (LOCAL) ( c-addr u -- )
Low-level local variable creation. Used by {: implementation. Rarely used directly.
Locals EXT. Implementation primitive for the locals subsystem.
See: {: locals-ext defining ALLOCATE ( u -- a-addr ior )
Allocate u bytes of memory. Returns address and I/O result (0 = success). Memory is not in dictionary space.
100 ALLOCATE THROW \ a-addr on success
WAFER: Host function. Memory-Allocation word set. Uses Rust allocator.
See: FREE RESIZE memory memory-ops host-function FREE ( a-addr -- ior )
Free previously allocated memory. ior 0 = success.
100 ALLOCATE THROW DUP ... FREE THROW
WAFER: Host function.
See: ALLOCATE RESIZE memory memory-ops host-function RESIZE ( a-addr u -- a-addr' ior )
Resize allocated memory block. May move the block. Like C realloc.
WAFER: Host function.
See: ALLOCATE FREE memory memory-ops host-function .S ( -- )
Non-destructive stack display. Shows all items on data stack without consuming them. Format: <n> x1 x2 ...
1 2 3 .S \ <3> 1 2 3
WAFER: Host function. Programming-Tools word set.
See: DEPTH . tools io host-function ? (question) ( a-addr -- )
Display contents of address. Short for @ .
VARIABLE X 42 X ! X ? \ 42
Programming-Tools word set.
See: @ . tools io DUMP ( addr u -- )
Display u bytes of memory starting at addr in hex dump format.
HERE 64 DUMP
Programming-Tools word set.
See: .S ? tools io SEE ( "<spaces>name" -- )
Decompile/disassemble word. Shows source-level or implementation-level representation.
SEE DUP
Programming-Tools EXT.
See: WORDS ' tools-ext io WORDS ( -- )
List all words in current search order. Implementation-defined format.
WAFER: Host function. Programming-Tools EXT.
See: SEE ORDER tools-ext io host-function BYE ( -- )
Exit Forth system. Returns to operating system.
WAFER: Handled in CLI REPL. Programming-Tools EXT.
See: QUIT ABORT tools-ext compilation [IF] Compilation: ( flag -- )
Conditional compilation. If flag is false, skip to [ELSE] or [THEN]. Works at compile AND interpret time. Not nestable (unlike #ifdef).
TRUE [IF] : FOO ." yes" ; [THEN]
Programming-Tools EXT. Immediate.
See: [ELSE] [THEN] [DEFINED] tools-ext compilation [ELSE] Compilation: ( -- )
Alternative branch for [IF].
Programming-Tools EXT. Immediate.
See: [IF] [THEN] tools-ext compilation [THEN] Compilation: ( -- )
End conditional compilation block.
Programming-Tools EXT. Immediate.
See: [IF] [ELSE] tools-ext compilation [DEFINED] ( "<spaces>name" -- flag )
True if word is defined. Used with [IF] for conditional compilation.
[DEFINED] FSIN [IF] .( Float math available ) [THEN]
Programming-Tools EXT. Immediate.
See: [UNDEFINED] [IF] tools-ext compilation [UNDEFINED] ( "<spaces>name" -- flag )
True if word is NOT defined. Complement of [DEFINED].
[UNDEFINED] MY-WORD [IF] : MY-WORD ." default" ; [THEN]
Programming-Tools EXT. Immediate.
See: [DEFINED] [IF] tools-ext compilation AHEAD Compilation: ( -- orig )
Unconditional forward branch. Resolved by THEN. Used in complex control structures.
Programming-Tools EXT.
See: IF THEN tools-ext control-flow N>R ( i*n +n -- ) ( R: -- i*n +n )
Move n items plus count to return stack. Useful for saving/restoring variable-depth stack segments.
Programming-Tools EXT.
See: NR> >R tools-ext return-stack NR> ( -- i*n +n ) ( R: i*n +n -- )
Restore items from return stack (reverse of N>R).
Programming-Tools EXT.
See: N>R R> tools-ext return-stack SYNONYM ( "<spaces>newname" "<spaces>oldname" -- )
Create newname as an alias for oldname.
SYNONYM THIRD 2 PICK
Programming-Tools EXT.
See: DEFER tools-ext defining FORTH-WORDLIST ( -- wid )
Return the wordlist ID of the FORTH vocabulary.
WAFER: Host function. Search-Order word set.
See: WORDLIST GET-ORDER search-order compilation host-function WORDLIST ( -- wid )
Create a new empty wordlist. Returns its identifier.
WAFER: Host function. Search-Order word set.
See: FORTH-WORDLIST SET-ORDER search-order defining host-function GET-ORDER ( -- widn...wid1 n )
Get the current search order as a stack of wordlist IDs and count.
WAFER: Host function.
See: SET-ORDER ORDER search-order compilation host-function SET-ORDER ( widn...wid1 n -- )
Set the search order. n = -1 sets default (FORTH-WORDLIST only).
WAFER: Host function.
See: GET-ORDER ALSO ONLY search-order compilation host-function GET-CURRENT ( -- wid )
Get the compilation wordlist (where new definitions go).
WAFER: Host function.
See: SET-CURRENT DEFINITIONS search-order compilation host-function SET-CURRENT ( wid -- )
Set the compilation wordlist.
WAFER: Host function.
See: GET-CURRENT DEFINITIONS search-order compilation host-function SEARCH-WORDLIST ( c-addr u wid -- 0 | xt 1 | xt -1 )
Search specific wordlist. Returns same as FIND but takes wordlist ID.
WAFER: Host function.
See: FIND FORTH-WORDLIST search-order parsing host-function DEFINITIONS ( -- )
Set compilation wordlist to first in search order. Common after ALSO to direct definitions into a specific vocabulary.
WAFER: Host function.
See: SET-CURRENT GET-ORDER search-order compilation host-function ALSO ( -- )
Duplicate first wordlist in search order. Typically followed by a vocabulary name to add it to search order.
ALSO MY-VOCAB
WAFER: Host function. Search-Order EXT.
See: ONLY PREVIOUS FORTH search-order-ext compilation host-function ONLY ( -- )
Set search order to minimum (implementation-defined default). Usually just FORTH-WORDLIST.
WAFER: Host function. Search-Order EXT.
See: ALSO FORTH search-order-ext compilation host-function FORTH ( -- )
Replace first wordlist in search order with FORTH-WORDLIST.
WAFER: Host function. Search-Order EXT.
See: ONLY ALSO search-order-ext compilation host-function PREVIOUS ( -- )
Remove first wordlist from search order (reverse of ALSO).
WAFER: Host function. Search-Order EXT.
See: ALSO search-order-ext compilation host-function ORDER ( -- )
Display current search order and compilation wordlist.
WAFER: Host function. Search-Order EXT.
See: GET-ORDER .S search-order-ext io host-function BIN ( fam -- fam' )
Modify file access method for binary (no line-ending translation).
S" data.bin" R/O BIN OPEN-FILE THROW
File-Access word set. WAFER: Not implemented (requires WASI).
See: R/O R/W W/O file io not-implemented R/O ( -- fam )
Read-only file access method.
File-Access. WAFER: Not implemented.
See: R/W W/O BIN file io not-implemented R/W ( -- fam )
Read-write file access method.
File-Access. WAFER: Not implemented.
See: R/O W/O file io not-implemented W/O ( -- fam )
Write-only file access method.
File-Access. WAFER: Not implemented.
See: R/O R/W file io not-implemented OPEN-FILE ( c-addr u fam -- fileid ior )
Open existing file. Returns file ID and I/O result.
S" input.txt" R/O OPEN-FILE THROW
File-Access. WAFER: Not implemented.
See: CREATE-FILE CLOSE-FILE file io not-implemented CREATE-FILE ( c-addr u fam -- fileid ior )
Create file (or truncate existing). Returns file ID.
File-Access. WAFER: Not implemented.
See: OPEN-FILE DELETE-FILE file io not-implemented CLOSE-FILE ( fileid -- ior )
Close file.
File-Access. WAFER: Not implemented.
See: OPEN-FILE file io not-implemented READ-FILE ( c-addr u1 fileid -- u2 ior )
Read up to u1 characters into buffer. u2 = actual chars read.
File-Access. WAFER: Not implemented.
See: WRITE-FILE READ-LINE file io not-implemented READ-LINE ( c-addr u1 fileid -- u2 flag ior )
Read one line. flag = true if line read successfully (false at EOF).
File-Access. WAFER: Not implemented.
See: READ-FILE WRITE-LINE file io not-implemented WRITE-FILE ( c-addr u fileid -- ior )
Write u characters to file.
File-Access. WAFER: Not implemented.
See: READ-FILE WRITE-LINE file io not-implemented WRITE-LINE ( c-addr u fileid -- ior )
Write characters followed by line terminator.
File-Access. WAFER: Not implemented.
See: WRITE-FILE READ-LINE file io not-implemented DELETE-FILE ( c-addr u -- ior )
Delete named file.
File-Access. WAFER: Not implemented.
See: CREATE-FILE file io not-implemented FILE-POSITION ( fileid -- ud ior )
Get current file position as double-cell unsigned.
File-Access. WAFER: Not implemented.
See: REPOSITION-FILE FILE-SIZE file io not-implemented FILE-SIZE ( fileid -- ud ior )
Get file size as double-cell unsigned.
File-Access. WAFER: Not implemented.
See: FILE-POSITION file io not-implemented REPOSITION-FILE ( ud fileid -- ior )
Set file position (seek).
File-Access. WAFER: Not implemented.
See: FILE-POSITION file io not-implemented RESIZE-FILE ( ud fileid -- ior )
Change file size. Truncates or extends.
File-Access. WAFER: Not implemented.
See: FILE-SIZE file io not-implemented FLUSH-FILE ( fileid -- ior )
Flush file buffers to storage.
File-Access EXT. WAFER: Not implemented.
See: CLOSE-FILE file io not-implemented INCLUDE-FILE ( i*x fileid -- j*x )
Interpret Forth source from file. Nests: included file can include others.
File-Access. WAFER: Not implemented.
See: INCLUDED REQUIRE file compilation not-implemented INCLUDED ( i*x c-addr u -- j*x )
Open and interpret named file. Combines OPEN-FILE and INCLUDE-FILE.
S" library.fth" INCLUDED
File-Access. WAFER: Not implemented.
See: INCLUDE-FILE REQUIRE file compilation not-implemented REQUIRE ( i*x "name" -- j*x )
Include file only if not already included. Prevents double-loading.
REQUIRE utils.fth
File-Access EXT. WAFER: Not implemented.
See: INCLUDED REQUIRED file-ext compilation not-implemented REQUIRED ( i*x c-addr u -- j*x )
Stack-based version of REQUIRE.
File-Access EXT. WAFER: Not implemented.
See: REQUIRE INCLUDED file-ext compilation not-implemented What is WAFER's compilation pipeline? Forth source → Outer interpreter → Vec<IrOp> → Optimizer (6 passes) → WASM codegen (wasm-encoder) → wasmtime instantiation
Each colon definition becomes its own WASM module. The module is instantiated immediately, and its function is added to the shared function table.
: SQUARE DUP * ; \ creates entire WASM module
Key insight: no bytecode interpreter. Every word runs as native machine code via Cranelift JIT. wafer architecture What are WAFER's two kinds of primitives? IR primitives (~80 words): Defined as Vec<IrOp>, compiled to WASM like user words. Subject to all optimizations.
Host primitives (~120+ words): Rust closures with direct memory access via wasmtime Func::new. Used for I/O, complex logic, float ops.
register_primitive("DUP", false, vec![IrOp::Dup])?; // IR
register_host_primitive(".", false, func)?; // Host
IR primitives are faster (inlined, optimized). Host functions are more flexible (full Rust power). wafer architecture What is WAFER's memory layout? 1 MiB initial (16 pages), 16 MiB max (256 pages)
0x0000 System vars (64B): STATE, BASE, >IN, HERE, LATEST, HLD
0x0040 Input buffer (1024B)
0x0440 PAD (256B)
0x0540 Data stack (4096B) — grows ↓ from 0x1540
0x1540 Return stack (4096B) — grows ↓ from 0x2540
0x2540 Float stack (2048B) — grows ↓ from 0x2D40
0x2D40 Dictionary (variable) — grows ↑
0x10000 User data space — grows ↑
All stacks grow downward. Cell = 4 bytes. Float = 8 bytes (f64). wafer architecture How does WAFER implement word calling? Subroutine threading via WASM function table + call_indirect.
Every word has a unique WordId = index into the shared function table. Calling a word compiles to:
(i32.const <word_id>) (call_indirect (type ...))
All modules share: linear memory, globals (DSP, RSP, FSP), and the function table.
No interpreter loop. No token threading. Direct WASM function dispatch. wafer architecture What is WAFER's dictionary structure? Linked list in linear memory (Vec<u8> in Rust).
+0: Link (4B) — address of previous entry (0 = end)
+4: Flags (1B) — IMMEDIATE(0x80) | HIDDEN(0x40) | len(0x1F)
+5: Name (N bytes, uppercase)
+5+N: Padding to 4-byte alignment
: Code field (4B) — function table index (WordId)
: Parameter field — data for VARIABLE/CONSTANT/DOES>
O(1) lookup via Rust HashMap index alongside the linked list. wafer architecture What are WAFER's 6 IR optimization passes? 1. Peephole — pattern matching: OVER OVER → 2DUP, SWAP DROP → NIP, LIT(1) + → 1+
2. Constant folding — evaluate pure operations at compile time: LIT(3) LIT(4) + → LIT(7)
3. Strength reduction — replace expensive ops: LIT(2) * → LSHIFT(1), LIT(8) * → LSHIFT(3)
4. Dead code elimination — remove code after unconditional EXIT
5. Tail call detection — convert final Call before Exit to TailCall (reuses stack frame)
6. Inlining — inline small words (≤8 IR ops) at call site
All passes configurable via WaferConfig. Default: all enabled. wafer optimization What is stack-to-local promotion? WAFER codegen optimization that maps Forth's memory stack to WASM locals for straight-line code (no control flow).
Instead of DSP load/store for every stack operation, values live in WASM locals that Cranelift maps to registers.
Effect: DUP * goes from ~30 WASM instructions to ~4.
7x speedup for arithmetic-heavy words.
Only applies to words without IF/DO/BEGIN. Phase 1 limitation.
Controlled by: WaferConfig::codegen.stack_to_local_promotion wafer optimization What is WAFER's consolidation mode? Recompile all user-defined words into a single WASM module.
wafer --consolidate program.fth
wafer --consolidate -o output.wasm program.fth
Benefits:
• Direct call instead of call_indirect (no table lookup)
• Cranelift can inline across word boundaries
• Single module = single compilation unit
Use after interactive development for deployment. Not for REPL. wafer optimization What is DSP caching in WAFER? Cache the dsp global variable in a WASM local at function entry. Write back only before calls and at exit.
Without caching: every stack operation reads/writes the global DSP, which is slow.
With caching: a local variable tracks DSP, only syncing when needed.
~30-40% fewer global access instructions.
Enabled by default. Pairs well with stack-to-local promotion. wafer optimization What is batch compilation in WAFER? At startup, all ~80 IR primitives are compiled into a single WASM module instead of individual modules.
Without batching: 80 separate wasmtime compilations (~7ms boot).
With batching: 1 compilation (~0.6ms boot).
12x faster startup.
Implementation: batch_mode flag during register_primitives(), flush with batch_compile_deferred(). wafer optimization How does WAFER handle the IrOp enum? ~50 opcodes representing the intermediate representation between Forth and WASM.
Categories:
• Literals: PushI32(i32), PushI64(i64), PushF64(f64)
• Stack: Dup, Drop, Swap, Over, Rot, Nip, Tuck
• Arithmetic: Add, Sub, Mul, DivMod, Negate, Abs
• Control: If{then,else}, DoLoop{body,is_plus}, BeginUntil{body}
• Calls: Call(WordId), TailCall(WordId), Execute, Exit
Nested control flow uses recursive Vec<IrOp> (tree structure, not flat). wafer architecture How does WAFER handle DOES>? Two-phase mechanism:
1. At define-time: DOES> compiles the runtime body and saves its xt.
2. _DOES_PATCH_ (host function) patches the most recently CREATE'd word's code to call the DOES> body with the data address on stack.
: ARRAY CREATE CELLS ALLOT DOES> SWAP CELLS + ;
WAFER supports double-DOES> (redefining runtime behavior). The patched word pushes its parameter field address, then calls the DOES> code. wafer architecture How are float literals compiled in WAFER? Float literals (e.g., 3.14e) compile to IrOp::PushF64(f64).
In interpret mode: the float is pushed directly to the float stack.
In compile mode: FLITERAL is automatically applied.
Syntax: any number containing . or E/e with no base prefix is parsed as float when BASE=10.
1.5e \ 1.5
1.5e2 \ 150.0
-3.14e0 \ -3.14
Note: Floats only parsed when BASE is DECIMAL. In HEX, "1.5e2" would be parsed as an integer. wafer architecture What is WAFER's WaferConfig? Unified configuration for all optimization passes and codegen options.
WaferConfig {
opt: OptConfig { peephole, constant_fold, tail_call, strength_reduce, dce, inline }
codegen: CodegenOpts { stack_to_local_promotion }
}
Presets: WaferConfig::all() (all on, default), WaferConfig::none() (all off, for debugging).
let vm = ForthVM::new_with_config(WaferConfig::none())?; wafer architecture How does WAFER handle CATCH/THROW? Nested exception frames with stack snapshot/restore.
CATCH: saves DSP, RSP, FSP. If the xt THROWs, stacks are restored to saved state, throw code is pushed.
THROW: if code ≠ 0, unwinds to nearest CATCH frame. If no CATCH, behaves like ABORT.
Standard codes: -1 (ABORT), -2 (ABORT"), -4 (stack underflow), -13 (undefined word), -14 (compile-only).
['] RISKY CATCH ?DUP IF ." Error: " . THEN
WAFER uses Rust-side exception handling — the throw code is returned through the host function boundary. wafer architecture What is the CONSOLIDATE word? WAFER-specific word (not in Forth 2012). Recompiles all compiled definitions into a single WASM module with direct function calls. Equivalent to --consolidate CLI flag but callable from Forth code.
: FOO ... ; : BAR FOO FOO ; CONSOLIDATE
After CONSOLIDATE, all existing words use direct calls. New words still use call_indirect until next CONSOLIDATE. wafer architecture wafer-specific What Forth 2012 word sets does WAFER implement? 12 of 14 at 100% compliance:
Core, Core-Ext, Double-Number, Exception, Facility, Floating-Point (+ Ext), Locals, Memory-Allocation, Programming-Tools, Search-Order, String
Not implemented (2):
File-Access (requires WASI), Extended-Character (Unicode)
392 tests: 380 unit + 1 benchmark + 11 compliance test modules.
cargo test -p wafer-core --test compliance wafer architecture What is the difference between FM/MOD and SM/REM? FM/MOD: Floored division. Quotient rounds toward −∞. Remainder has same sign as divisor.
SM/REM: Symmetric division. Quotient truncates toward 0. Remainder has same sign as dividend. (C-like)
-7. 2 FM/MOD . . \ -4 1
-7. 2 SM/REM . . \ -3 -1
FM/MOD is preferred for modular arithmetic (always non-negative remainder with positive divisor). Forth 2012 leaves / and MOD implementation-defined. WAFER uses symmetric (SM/REM). patterns arithmetic CREATE DOES> pattern The fundamental pattern for user-defined defining words in Forth.
CREATE allocates data. DOES> specifies runtime behavior. The child word pushes its data address, then executes the DOES> body.
: ARRAY ( n -- ) CREATE CELLS ALLOT DOES> ( n -- addr ) SWAP CELLS + ;
10 ARRAY DATA 42 3 DATA ! 3 DATA @ . \ 42
Other examples: tables, structs, state machines, OOP vtables.
Mastering CREATE DOES> is the bridge from Forth user to Forth metaprogrammer. patterns defining Pictured numeric output pattern <# ... #> — right-to-left digit conversion.
Build output from least-significant digit. Use # for each digit, #S for remaining, HOLD for custom chars, SIGN for negative.
: DOLLARS ( n -- c-addr u )
S>D TUCK DABS <# # # [CHAR] . HOLD #S ROT SIGN [CHAR] $ HOLD #> ;
-1234 DOLLARS TYPE \ $-12.34
Always start with <#, end with #>. The double number is consumed by # and #S. patterns pictured-numeric POSTPONE idiom for compile-time words POSTPONE defers compilation of a word to when the defining word's code runs.
For building syntax extensions and compile-time macros.
: MY-IF POSTPONE IF ; IMMEDIATE
: [+] POSTPONE + ; IMMEDIATE \ compiles + wherever [+] appears
For immediate words: POSTPONE compiles their behavior.
For non-immediate: POSTPONE compiles code that will compile them.
Replaces obsolescent [COMPILE] and COMPILE. The single tool for all compile-time word building. patterns compilation VALUE/TO vs VARIABLE/@/! VALUE: cleaner syntax for simple storage. Access by name, update with TO.
VARIABLE: gives address, needed for +!, pointer passing, arrays.
42 VALUE X X . 99 TO X \ clean, reads like English
VARIABLE Y 42 Y ! Y @ . 5 Y +! \ address-based, more flexible
Rule of thumb: use VALUE unless you need the address. Use VARIABLE for data structures, pointer math, or +!. patterns defining DEFER/IS pattern for late binding DEFER creates a word with swappable behavior. IS changes what it does.
DEFER GREET
: HELLO ." Hello!" ; ' HELLO IS GREET
: HI ." Hi!" ; ' HI IS GREET
Use cases: forward references, pluggable behavior, mock/stub in tests, state machines.
ACTION-OF retrieves current xt. DEFER@ and DEFER! are the low-level equivalents. patterns defining Double-number literal syntax A trailing dot makes a number double-cell.
42. \ pushes double-cell (42 0) — note: this is NOT a float!
-1. \ pushes (-1 -1) — sign-extended
1000000. D. \ prints 1000000
Common confusion: 3.14 is NOT a float literal in standard Forth without the E. It's 314 as a double (the dot is inside the number). Use 3.14e or 3.14E0 for floats. patterns conversion CATCH/THROW error handling pattern Structured exception handling. CATCH wraps an xt; THROW unwinds to it.
: SAFE ['] RISKY CATCH
CASE
0 OF ." ok" ENDOF
-1 OF ." aborted" ENDOF
." error: " DUP .
ENDCASE ;
THROW 0 is a no-op. Negative codes are standard (-1 ABORT, -2 ABORT", etc.). Positive codes are application-defined. patterns control-flow :NONAME for anonymous execution Create unnamed word, get its xt. Perfect for callbacks and dispatch tables.
:NONAME DUP * ; CONSTANT SQUARE-XT
5 SQUARE-XT EXECUTE . \ 25
\ Dispatch table:
CREATE OPS :NONAME + ; , :NONAME - ; , :NONAME * ; ,
: DISPATCH CELLS OPS + @ EXECUTE ;
No dictionary entry is created. The xt is only accessible through the value on the stack at definition time. patterns defining MARKER for interactive development Create a restore point. Execute the marker to forget everything defined after it.
MARKER CLEAN
: FOO ." v1" ; : BAR FOO ;
CLEAN \ FOO and BAR are forgotten
: FOO ." v2" ; \ redefine from scratch
Essential for REPL-driven development: mark, experiment, restore, repeat. Like an undo point for the dictionary. patterns defining Loop idiom: 0 DO ... LOOP Standard counted loop. Index available via I (or J for outer loop).
: STARS 0 ?DO [CHAR] * EMIT LOOP ;
: TABLE 4 0 DO 4 0 DO I J * 4 .R LOOP CR LOOP ;
Use ?DO (not DO) when count might be 0. DO executes at least once even if limit=start. UNLOOP before EXIT in a loop. LEAVE exits immediately. patterns control-flow EVALUATE for dynamic compilation Interpret a string as Forth source at runtime. Extremely powerful; use with care.
: RUN S" 2 3 + ." EVALUATE ; \ prints 5
\ Dynamic word creation:
: MAKE-CONST ( n "name" -- )
>R S" CONSTANT " R> ... ; \ simplified
SOURCE-ID returns -1 during EVALUATE. >IN and SOURCE reflect the evaluated string. Nesting is allowed. patterns compilation