From 96f50b9dfadf356baca978e36b8f7476263945d2 Mon Sep 17 00:00:00 2001 From: giles Date: Mon, 23 Mar 2026 19:17:05 +0000 Subject: [PATCH] Add sibling sublist parser tests + reset JIT sx-parse MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Tests: parse "(a (b) (c))" must produce 3 siblings, not nested. Catches JIT compilation bug where closing parens cause sibling lists to become children. Reset sx-parse to CEK on the OCaml kernel — the JIT-compiled version of sx-parse's complex letrec produces wrong bytecode. CEK interpretation works correctly (tests pass on all platforms). Co-Authored-By: Claude Opus 4.6 (1M context) --- shared/sx/ocaml_bridge.py | 10 ++++++++++ spec/tests/test-parser.sx | 13 +++++++++++++ 2 files changed, 23 insertions(+) diff --git a/shared/sx/ocaml_bridge.py b/shared/sx/ocaml_bridge.py index 184eb3e..05dc206 100644 --- a/shared/sx/ocaml_bridge.py +++ b/shared/sx/ocaml_bridge.py @@ -440,6 +440,16 @@ class OcamlBridge: _logger.warning("OCaml load skipped %s: %s", filepath, e) + # JIT workaround: sx-parse has a complex letrec (20 mutually + # recursive functions) that the JIT compiles incorrectly — + # closing parens cause siblings to become children. + # CEK-interpreted sx-parse works correctly. + try: + await self._send('(vm-reset-fn "sx-parse")') + await self._read_until_ok(ctx=None) + except OcamlBridgeError: + pass + # SSR overrides: effect is a no-op on the server (prevents # reactive loops during island SSR — effects are DOM side-effects) try: diff --git a/spec/tests/test-parser.sx b/spec/tests/test-parser.sx index 2a2c535..cfcc157 100644 --- a/spec/tests/test-parser.sx +++ b/spec/tests/test-parser.sx @@ -79,6 +79,19 @@ (assert-length 1 result) (assert-equal (list 1 (list 2 3) 4) (first result)))) + (deftest "parse sibling sublists" + ;; Regression: closing paren of (b) must not swallow (c) as a child + (let ((result (sx-parse "(a (b) (c))"))) + (assert-length 1 result) + (assert-length 3 (first result)) + (assert-equal (list (make-symbol "a") (list (make-symbol "b")) (list (make-symbol "c"))) + (first result)))) + + (deftest "parse multiple sibling sublists with content" + (let ((result (sx-parse "(div (span 1) (span 2) (span 3))"))) + (assert-length 1 result) + (assert-length 4 (first result)))) + (deftest "parse square brackets as list" (let ((result (sx-parse "[1 2 3]"))) (assert-length 1 result)