Punctuation (`,` `.` `+` `/` `:` and an embedded `-`) after the leftmost digit now forces double-cell conversion, so `12.34`, `1,234`, `12:30:45` and `2026-08-06` convert as doubles. Only a trailing `.` worked before, and `1.5` was an "unknown word" error. The punctuation is a double-cell marker, not a fractional point, so the scale has to travel separately: DPL carries the digit count right of the rightmost punctuation character (negative when there was none), which is what lets `<# #>` place the point back on output. NH carries the high cell a single-cell conversion drops, so a token that overflows a cell is still recoverable as a double. parse_number and parse_double_number duplicated the prefix and sign handling and could not share a DPL counter, so they collapse into one parse_numeric_literal that reports which kind it converted. Verified token-for-token against sf64. One deliberate divergence: WAFER keeps accepting a sign before a base prefix (`-$FF`), which sf64 rejects.
6.8 KiB
Changelog
All notable changes to WAFER are documented in this file.
The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.
[0.2.2] - 2026-08-06
Added
- SwiftForth-style input number conversion. Punctuation (
,.+/:and an embedded-) anywhere after the leftmost digit now forces double-cell conversion, so12.34,1,234,12:30:45and2026-08-06all convert as doubles without a custom parser. Previously only a trailing.worked and1.5was an "unknown word" error. The punctuation is a double-cell marker, not a fractional point: every spelling of1234(1234.,123.4,.1234) yields the same value. DPL( -- addr ): digits to the right of the rightmost punctuation character in the last converted number, negative when the token carried none. Seeded at -1024 and bumped once per digit, matchingsf64. Together with<# #>this is how fixed-point input is scaled.NH( -- addr ): the high-order cell dropped by a single-cell conversion, so a token that overflows a cell can be recovered as a double (4000000000 NH @ D.).
Verified token-for-token against SwiftForth sf64: DPL values, double
promotion and sign handling agree on every probed form. One deliberate
divergence — WAFER also accepts a sign before a base prefix (-$FF), which
sf64 rejects; the Forth 2012 spelling $-FF works in both. A leading +
is punctuation rather than a sign in both engines, so +7 is the double 7
with DPL = 1.
0.2.1 - 2026-08-06
Fixed
- The search order is now authoritative (Forth 2012 §16.3.3): a word whose wordlist is not in the search order is no longer findable. Previously lookup fell back to the newest entry across all wordlists, making word hiding impossible. Verified against gforth and SwiftForth, and guarded by a cross-engine corpus program.
- Host words validate their stack arguments. Around 40 host-implemented
words (
RND-SEED,ACCEPT,RESIZE,ALLOCATE,FREE,SEARCH,SUBSTITUTE,ROLL,M*,UM/MOD,SF@ SF! DF@ DF!,F. FE. FS. F~,2R@, and friends) performed raw stack-pointer arithmetic with no underflow check — calling them on an empty stack silently corrupted the stack pointer (the compiled-code guards from 0.2.0 do not cover host words). All argument-taking host words now fail with a clean, CATCHable underflow error, enforced by a class-wide regression test.
0.2.0 - 2026-08-06
The usability release: introspection, source files, honest errors, and a safety net under every compiled word.
Added
- Stack guards in compiled code: under/overflow checks at the
stack-pointer choke points of generated WASM. Faults THROW standard codes
(
-3..-6,-44,-45), are CATCHable, and print standard messages instead of silently corrupting memory. Default on;wafer buildoutput stays unguarded;WAFER_STACK_GUARDS=0|1overrides. SEE: source-level decompiler. Colon words (including everything inboot.fth) show their captured verbatim source; data words show synthesized definitions with current values (9 VALUE X,DEFER D ( IS DUP )); primitives fall back to a readable IR dump —SEEnever dead-ends on a defined word.SEE-IR: post-optimization IR view with resolved callee names and indented control flow — shows what the optimizer actually did.HELP: stack effect + one-line description for every word in a fresh VM (dictionary words and outer-interpreter tokens alike); coverage is enforced by a unit test, so an undocumented new word fails the build. User words echo their leading( n -- n )comment.INCLUDE/INCLUDED: nestable source-file loading with cycle detection, depth bound, paths relative to the including file, and per-levelSOURCE-ID. The loader is injected (CLI: filesystem; web: defined error), so the core stays IO-free.wafer prog.fthnow runs through the same machinery.MARKERextensions:REMEMBER(re-runnable marker),EMPTYandGILD(boot-state rollback and re-baselining). Marker rollback now also restores search order, wordlists,REPLACESsubstitutions,ABORT"texts, and captured word sources — enabling theREMEMBER+INCLUDEedit-reload loop.WORDS: optional substring filter (WORDS FLOAT), word count, andWORDS ALL— a grouped full view by wordlist plus internal words.- Return-stack introspection:
.RS,RDEPTH,RP@. - Tools:
.ShonorsBASE,F.S,?, bounds-checkedDUMP, realBYE, namedORDERoutput. - CLI REPL: persistent history (XDG state dir,
0600), dictionary-backed tab completion, prefix history search on Up/Down, Ctrl-C clears the line. - Web REPL: history persisted to localStorage, User Words palette,
BASEindicator in the stack bar. - Error reporting: uncaught
THROWcodes map to standard messages;ABORT"text prints only when uncaught; errors inside included files carryfile.fth:line:context; uncaught throws are typed (WaferError::UncaughtThrow) for embedding consumers; compiled words carry WASM name sections, so genuine traps name the faulting word (in CRASHER: wasm trap: out of bounds memory access). - SwiftForth correctness lane: the cross-engine program corpus can run
against sf64 as an oracle (
just compare-correctness), alongside the existing gforth lane and the sf64 performance lane.
Fixed
- Multi-line command output in the CLI REPL starts on its own line
(inline
okecho only for single-line output). .Sprinted in decimal regardless ofBASE.- A bare interpreted
R>underflowed silently (exposed by the new stack guards; compliance baseline updated). SPACESwith a negative count now outputs nothing, per Forth 2012 6.1.2230.
Changed
wafer prog.fthreports errors withfile:linecontext and resolves nestedINCLUDEs relative to the file.- Internal words (
_-prefixed) are flagged in the dictionary and hidden fromWORDSand completion (WORDS ALLshows them). - Dependencies upgraded across the board: wasmtime 43 → 47, wasm-encoder/wasmparser 0.246 → 0.255, plus all semver-compatible updates.
0.1.0 - 2026-08-04
Initial development line (untagged): Forth 2012 core with IR optimizer and
WASM codegen via wasm-encoder/wasmtime, ~300 words across Core, Double,
Float, String, Search-Order, Exception, and Tools word sets, Forth 2012
compliance suite, CONSOLIDATE whole-program recompilation, wafer build
AOT export (WASM / native / JS loader), browser REPL, SHA-1/256/512 words,
and cross-engine benchmark lanes against gforth and SwiftForth.