You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Follow-up to #2 (DO/LOOP family and friends). That issue added DO/LOOP/?DO/I/UNLOOP and CONSTANT/VARIABLE and BEGIN-style WHILE/REPEAT/AGAIN. The remaining words from #2's body are still missing — most are small one-liners once the loop and defining-word machinery is in place, but a few (DOES>, LEAVE) need additional kernel support.
Scope: both kernels (forth-in-forth and forth-on-forthish), unless otherwise noted. Preserve byte-identical output across the two where possible.
+LOOP — like LOOP but increments the index by TOS instead of 1. Handles negative increments (down-counting) and the "cross the boundary" exit condition (standard Forth semantics: exit when the boundary is crossed in the direction of increment).
Needs a new (+LOOP) primitive in kernel.s. IMMEDIATE +LOOP parallels LOOP's compile-time behavior.
J — push the outer loop's index (for nested DO/LOOP). With our RS layout [index limit caller-IP], J reads 9(r1) (index of the outer loop, below caller's IP). One new primitive.
LEAVE — exit the current loop early. Requires compile-time bookkeeping: ?DO-style forward branches chained through LOOP so each LEAVE can be patched to the loop exit. Meaningful refactor of the IMMEDIATE DO/LOOP compiler.
2. DOES>
DOES> — splice runtime behavior onto the most recent CREATE. Requires the inner interpreter to support re-entering a colon-def at a patched address. Classic approach: CREATE builds a word whose CFA is a trampoline that pushes the data-field address and jumps to DOCOL at a patched location.
Would let CONSTANT/VARIABLE be expressed more elegantly: : CONSTANT CREATE , DOES> @ ; instead of the current ,DOCOL + ['] LIT templating.
Non-trivial. Likely wants a small kernel primitive ((DOES>)) plus rework of CREATE's CFA format.
3. RECURSE
RECURSE — IMMEDIATE; compiles a call to the currently-compiling definition. Needed because the new entry is SMUDGE/HIDDEN during its own compilation, so FIND won't see it. With LATEST pointing at the in-progress entry, implementation is a few lines: : RECURSE LATEST @ >CFA , ; IMMEDIATE (requires >CFA or equivalent).
4. Stack / comparison ergonomics (pure Forth, no new primitives)
?DUP — DUP if non-zero. : ?DUP DUP IF DUP THEN ;
PICK — n PICK copies the n-th stack element to top. One-liner using SP@ (we have it): : PICK 1 + 3 * SP@ + @ ; — cell-size aware.
ROLL — n ROLL rotates the n-th element to top. Trickier; needs a helper loop.
MIN / MAX — : MIN 2DUP < IF DROP ELSE NIP THEN ; etc.
With the words from #2 in place, the core language feels almost complete, but a handful of idioms — especially LEAVE, ?DUP, MIN/MAX, <=/>=/<> — still require awkward workarounds in demos. DOES> is the big one: it unlocks a whole family of defining words (arrays, enumerations, records) that are currently inexpressible.
Split from #2 so that issue can stay closed; pick any subset of these off at a time.
Testing
Each new word gets a demo in examples/ and stack-leak coverage (DEPTH before/after). Match byte-identical behavior between forth-in-forth and forth-on-forthish kernels where applicable.
Problem
Follow-up to #2 (DO/LOOP family and friends). That issue added DO/LOOP/?DO/I/UNLOOP and CONSTANT/VARIABLE and BEGIN-style WHILE/REPEAT/AGAIN. The remaining words from #2's body are still missing — most are small one-liners once the loop and defining-word machinery is in place, but a few (DOES>, LEAVE) need additional kernel support.
Scope: both kernels (forth-in-forth and forth-on-forthish), unless otherwise noted. Preserve byte-identical output across the two where possible.
Words to add
1. DO-loop extensions (build on #2)
+LOOP— like LOOP but increments the index by TOS instead of 1. Handles negative increments (down-counting) and the "cross the boundary" exit condition (standard Forth semantics: exit when the boundary is crossed in the direction of increment).(+LOOP)primitive in kernel.s. IMMEDIATE+LOOPparallels LOOP's compile-time behavior.J— push the outer loop's index (for nested DO/LOOP). With our RS layout[index limit caller-IP], J reads9(r1)(index of the outer loop, below caller's IP). One new primitive.LEAVE— exit the current loop early. Requires compile-time bookkeeping: ?DO-style forward branches chained through LOOP so each LEAVE can be patched to the loop exit. Meaningful refactor of the IMMEDIATE DO/LOOP compiler.2. DOES>
DOES>— splice runtime behavior onto the most recent CREATE. Requires the inner interpreter to support re-entering a colon-def at a patched address. Classic approach: CREATE builds a word whose CFA is a trampoline that pushes the data-field address and jumps to DOCOL at a patched location.: CONSTANT CREATE , DOES> @ ;instead of the current ,DOCOL + ['] LIT templating.(DOES>)) plus rework of CREATE's CFA format.3. RECURSE
RECURSE— IMMEDIATE; compiles a call to the currently-compiling definition. Needed because the new entry is SMUDGE/HIDDEN during its own compilation, so FIND won't see it. With LATEST pointing at the in-progress entry, implementation is a few lines:: RECURSE LATEST @ >CFA , ; IMMEDIATE(requires>CFAor equivalent).4. Stack / comparison ergonomics (pure Forth, no new primitives)
?DUP—DUPif non-zero.: ?DUP DUP IF DUP THEN ;PICK—n PICKcopies the n-th stack element to top. One-liner usingSP@(we have it):: PICK 1 + 3 * SP@ + @ ;— cell-size aware.ROLL—n ROLLrotates the n-th element to top. Trickier; needs a helper loop.MIN/MAX—: MIN 2DUP < IF DROP ELSE NIP THEN ;etc.<=/>=/<>—: <= > 0= ;,: >= < 0= ;,: <> = 0= ;0<>— non-zero test.: 0<> 0= 0= ;Expected location:
core/lowlevel.fthfor simple ones;core/midlevel.fthor a newcore/ergo.fthtier for PICK/ROLL if they grow.Non-goals
forth.sroot kernel (separate users, separate compatibility concerns — same scope rule as forth-in-forth: add DO/LOOP, ?DO, WHILE/REPEAT, AGAIN, CONSTANT, VARIABLE #2).Motivation
With the words from #2 in place, the core language feels almost complete, but a handful of idioms — especially LEAVE,
?DUP,MIN/MAX,<=/>=/<>— still require awkward workarounds in demos. DOES> is the big one: it unlocks a whole family of defining words (arrays, enumerations, records) that are currently inexpressible.Split from #2 so that issue can stay closed; pick any subset of these off at a time.
Testing
Each new word gets a demo in
examples/and stack-leak coverage (DEPTH before/after). Match byte-identical behavior between forth-in-forth and forth-on-forthish kernels where applicable.