The bytecode compiler now handles let-match (both variants):
- Variant 1: (let-match name expr {:k v} body...) — named binding + destructure
- Variant 2: (let-match {:k v} expr body...) — pattern-only destructure
Desugars to sequential let + get calls — no new opcodes needed.
This was the last blocker for SPA navigation. The bytecoded orchestration
and router modules used let-match which compiled to CALL_PRIM "let-match"
(undefined at runtime). Now desugared at compile time.
Also synced dist/sx/ sources with web/ and recompiled all 26 .sxbc modules.
2650/2650 tests pass.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Bytecode compiler now emits OP_PERFORM for (import ...) and compiles
(define-library ...) bodies. The VM stores the import request in
globals["__io_request"] and stops the run loop — no exceptions needed.
vm-execute-module returns a suspension dict, vm-resume-module continues.
Browser: sx_browser.ml detects suspension dicts from execute_module and
returns JS {suspended, op, request, resume} objects. The sx-platform.js
while loop handles cascading suspensions via handleImportSuspension.
13 modules load via .sxbc bytecode in 226ms (manifest-driven), both
islands hydrate, all handlers wired. 2650/2650 tests pass including
6 new vm-import-suspension tests.
Also: consolidated sx-platform-2.js → sx-platform.js, fixed
vm-execute-module missing code-from-value call, fixed bootstrap.py
protocol registry transpiler issues.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Compiler (lib/compiler.sx):
- Fix emit-op return type: 8 definition form cases (defstyle,
defhandler, defpage, etc.) and the perform case now return nil
explicitly via (do (emit-op em N) nil) instead of bare emit-op
which transpiled to unit-returning OCaml.
- compile_match PREAMBLE: return Nil instead of unit (was ignore).
- Added init wrapper to PREAMBLE (needed by compile-module).
- All 41 compiler functions re-transpiled cleanly.
Render (bootstrap_render.py): re-transpiled, no changes.
Runtime: restored keyword_p predicate (needed by defio-parse-kwargs!
in the transpiled evaluator).
2608/2608 tests passing.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The SX pretty-printer was reformatting compiler.sx on every sx-tree
edit, subtly breaking JIT bytecode output. Restored the exact original
file from f3f70cc and added compile-match + dispatch entry using sed
(no sx-tree tools that trigger pretty-printing).
Also: stop injecting stale closure snapshots into VM globals — let
GLOBAL_GET fall through to vm_closure_env for live bindings.
1166 passed, 0 failed.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The SX pretty-printer reformatted the entire compiler — different
indentation, removed comments, changed dict literals. This broke
JIT compilation for render-to-html and other functions that were
previously working.
Restore the exact original formatting from before the match commits
and add compile-match as a clean insertion (no reformatting). The
compiler's own dispatch stays as cond (safe with JIT).
1166 passed, 0 failed.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The compiler's own match dispatch caused cascading JIT failures —
when compile-list is pre-compiled, the match bytecode is embedded
in it, and any subtle issue propagates to ALL subsequent compilations.
compile-list reverts to cond (battle-tested with JIT). compile-match
remains available for user code that uses match expressions.
1166 passed, 0 failed.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
compile-match-clauses was a separate define that the JIT VM couldn't
find at runtime ("VM undefined: compile-match-clauses"). Inline it
as a letrec-bound local function inside compile-match so it's
captured in the closure and visible to JIT-compiled code.
1166 passed, 0 failed.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The JIT compiler now handles the match special form, emitting the
same DUP/compare/JUMP_IF_FALSE bytecode pattern as case. Supports
literal patterns (string, number, boolean, nil), _ wildcard, symbol
binding, and quoted symbol patterns.
This fixes the infinite JIT retry loop where compile-list (which
used match for dispatch) couldn't be JIT-compiled, causing
parse-loop to endlessly fall back to CEK evaluation.
1166 passed, 0 failed.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The match special form in compile-list caused JIT-compiled functions
to fail with "Expected number, got symbol" errors, creating an
infinite retry loop in parse-loop. The JIT compiler can't compile
match expressions, so compile-list fell back to CEK on every call.
Revert to the original cond-based dispatch. The evaluator.sx match
conversions are fine (not used by JIT), only the compiler was affected.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Convert large cond chains doing string equality dispatch to use the
match special form: step-eval-list (42 arms), step-continue (31 arms),
compile-list (30 arms), ho-setup-dispatch (7 arms), value-matches-type?
(10 arms). Also fix test-canonical.sx to use defsuite/deftest format
and load canonical.sx in both test runners.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
spec/ now contains only the language definition (5 files):
evaluator.sx, parser.sx, primitives.sx, render.sx, special-forms.sx
lib/ contains code written IN the language (8 files):
stdlib.sx, types.sx, freeze.sx, content.sx,
bytecode.sx, compiler.sx, vm.sx, callcc.sx
Test files follow source: spec/tests/ for core language tests,
lib/tests/ for library tests (continuations, freeze, types, vm).
Updated all consumers:
- JS/Python/OCaml bootstrappers: added lib/ to source search paths
- OCaml bridge: spec_dir for parser/render, lib_dir for compiler/freeze
- JS test runner: scans spec/tests/ (always) + lib/tests/ (--full)
- OCaml test runner: scans spec/tests/, lib tests via explicit request
- Docker dev mounts: added ./lib:/app/lib:ro
Tests: 1041 JS standard, 1322 JS full, 1101 OCaml — all pass
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>