JIT allowlist + integration tests + --test mode + clean up debug logging

JIT allowlist (sx_server.ml):
- Replace try-every-lambda strategy with StringSet allowlist. Only
  functions in the list get JIT compiled (compiler, parser, pure transforms).
  Render functions that need dynamic scope skip JIT entirely — no retry
  overhead, no silent fallbacks.
- Add (jit-allow name) command for dynamic expansion from Python bridge.
- JIT failures log once with "[jit] DISABLED fn — reason" then go silent.

Standalone --test mode (sx_server.ml):
- New --test flag loads full env (spec + adapters + compiler + signals),
  supports --eval and --load flags. Quick kernel testing without Docker.
  Example: dune exec bin/sx_server.exe -- --test --eval '(len HTML_TAGS)'

Integration tests (integration_tests.ml):
- New binary exercising the full rendering pipeline: loads spec + adapters
  into a server-like env, renders HTML via both native and SX adapter paths.
- 26 tests: HTML tags, special forms (when/if/let), letrec with side
  effects, component rendering, eval-expr with HTML tag functions.
- Would have caught the "Undefined symbol: div/lake/init" issues from
  the previous commit immediately without Docker.

VM cleanup (sx_vm.ml):
- Remove temporary debug logging (insn counter, call_closure counter,
  VmClosure depth tracking) added during debugging.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-03-23 23:58:40 +00:00
parent dd057247a5
commit 5270d2e956
8 changed files with 573 additions and 77 deletions

View File

@@ -568,3 +568,43 @@
(assert-equal 3 (len r))
(assert-equal (list "a" (list "b") (list "c")) r))))
)
(defsuite "define-as-local"
(deftest "define inside fn creates local, not global"
;; When define is inside a fn body, recursive calls must each
;; get their own copy. If define writes to global, recursive
;; calls overwrite each other.
(let ((result
(let ((counter 0))
(letrec
((make-counter (fn ()
(define my-val counter)
(set! counter (inc counter))
my-val)))
(list (make-counter) (make-counter) (make-counter))))))
(assert-equal (list 0 1 2) result)))
(deftest "define inside fn with self-recursion via define"
;; read-list-loop pattern: define a function that calls itself
(let ((result
(let ((items (list)))
(define go (fn (n)
(when (< n 3)
(append! items n)
(go (inc n)))))
(go 0)
items)))
(assert-equal (list 0 1 2) result)))
(deftest "recursive define inside letrec fn doesn't overwrite"
;; Each call to make-list creates its own 'loop' local
(let ((make-list (fn (items)
(let ((result (list)))
(define loop (fn (i)
(when (< i (len items))
(append! result (nth items i))
(loop (inc i)))))
(loop 0)
result))))
(assert-equal (list "a" "b") (make-list (list "a" "b")))
(assert-equal (list 1 2 3) (make-list (list 1 2 3))))))