Roadmap
Where the two backends stand today, and the big work between here and running arbitrary Nim on the web target. “Full coverage” below means compile-and-run arbitrary Nim, with the JavaScript backend as the more-complete reference.
The percentages are reasoned estimates, not measurements. Their basis is the set of Leng IR node kinds each codegen lowers (versus falling to a counted todo placeholder — see capabilities.md) together with the breadth of the passing test suites.
| Backend | Coverage | Distance to 100% is mostly… |
|---|---|---|
| JavaScript | ~85% | threads + async (runtime subsystems, likely frontend-gated) + stdlib breadth |
| WebAssembly | ~30% | heap allocator → indirect calls → exceptions → case |
JavaScript backend — ~85%
Where it is. The codegen lowers essentially the whole Leng IR node set: overflow-checked arithmetic (Ovf/Keepovf), full control flow including case, calls, oconstr/aconstr, RTTI vtables / method tables (pat + flexarray), exceptions (hexer’s goto / error-code ABI via jmp/lab), emit, the GC, and FFI. The 31-test suite spans Table/HashSet, variant objects, closures, the GC, and a live DOM. The core language is done.
Big tasks left
- Threads /
spawn— needs Web Workers plus a shared-linear-memory story. Not started. Large, and partly gated on nimony’s own threading model. async/await— needs event-loop integration on the JS side. Not started. Large, and also gated on nimony settling its async story.addr-of-location edge cases — a few address-taking forms still hit thetodoplaceholder (src/jscodegen.nim:798). Small; close the remaining paths.- Stdlib breadth + hardening — many modules work (
Table/HashSet/strutils/etc.), but breadth isn’t exhaustive. Some modules fail in the nimony frontend (not this backend) — e.g.json,times,envvars— and never reach codegen; more real-world programs are needed to shake out bugs. Medium, ongoing.
The gap to 100% is mostly two runtime subsystems (threads, async) that are arguably nimony-frontend-gated, plus breadth — not core codegen. Scoped to synchronous Nim, the JS backend is ~95%+ and the only real hole is the stray addr-of forms.
Known rough edges (not roadmap items so much as honest caveats — see capabilities.md for detail):
- No runtime checks are emitted — overflow/bounds/nil checks are intentionally not generated, so code relying on them raising won’t get an exception.
- The Number/BigInt boundary —
int/uintare JS Number,int64/uint64are BigInt; mixing them in one operation throwsTypeError, which heavy-64-bit stdlib code (e.g.std/random) can hit at internal load/xor sites. - No stdin/file I/O and a fixed 64 MiB heap (no JS-side growth yet).
WebAssembly backend — ~30%
Where it is. The codegen handles the scalar + aggregate + control spine — scalar arith/cmp/bitops/conversions, if/while/break, direct (transitive, cross-module) calls, field/array/pointer load-store at shared jslayout offsets, aggregate construction in a bump region, module globals, string data segments, and whole-program mode. echo runs end to end. Five tests, all straight-line or aggregate.
What it is concretely missing (whole node kinds the JS backend has): no CaseS (no case — only if/while), no RaiseS (no exceptions), no overflow-checked arithmetic or float specials (Ovf/Inf/Nan), no Emit/Scope/Type. Indirect calls bail (src/wasmcodegen.nim:457), and storage is a bump pointer that never frees.
Big tasks left, in unlock order
- In-module heap allocator — the ported allocator running inside linear memory via
mmap/atomics host imports. This is the gate: without it there is no growableseq/string/Table/HashSet— no dynamic data at all. The single biggest unlock. - Indirect calls / closures / method dispatch —
call_indirectplus a function table. Unlocks proc values, closures, and RTTI vtables. - Exceptions — port the goto / error-code ABI the JS backend already implements (
jmp/lab→ labeled blocks); the scaffolding is partly present. casestatements —br_tableor if-chains.- Smaller missing node kinds — overflow-checked arithmetic, float specials,
Suf/Emit/Scope/Type, and theaddr/store/global-symtodopaths. - Host-value FFI + DOM — WASM↔JS glue to reach the JS backend’s DOM parity. Large, and arguably beyond core language.
Items 1–3 are the bulk of the distance to JS-backend parity.
Notes on the estimates
- The JS
~85%counts threads and async as in-scope. Scoped to synchronous Nim it is much higher. - The WASM
~30%does not move on that distinction — its gaps are structural (heap, indirect calls, exceptions), not runtime-subsystem. - Both figures describe today’s committed state; neither backend has been run through CI on the PR yet (the workflow is awaiting maintainer approval).