Chez Phase 3 inc7: corpus on the Chez-hosted analyzer + a 50x-faster gate

Point the Chez-HOSTED analyzer at the full parity corpus (read -> analyze ->
emit -> eval, all on Chez, no Janet) and close the divergences so the
self-hosted compiler is faithful: 0 divergences, 2159/2494 pass.

Keystone: the on-Chez emitter ran with prelude-mode off, so every call to a
non-native clojure.core fn tripped the "unsupported stdlib fn" out-of-subset
guard. The zero-Janet spine always has the full prelude loaded, so turn
prelude mode on in compile-eval.ss (22% -> 84% pass on a sample).

Faithfulness fixes (each was the Chez host/reader diverging from the Janet
analyzer; fixed in the keeper, not the seed):
- emit-const read a char's codepoint via (get v :ch) — the Janet rep; on Chez a
  char is native. Route through a new form-char-code host-contract fn (41 cases).
- next over a lazy seq returned the empty-list terminator (truthy), not nil, so
  butlast and other (if (next s) ...) loops ran one step too far — broke
  some->/some->>/cond->>.
- reader: radix literals (2r1010/16rFF/36rZ), #^ deprecated metadata, ^meta on
  collections (lowers to a runtime with-meta form like the Janet reader),
  map-literal source order (values eval left-to-right), and nested syntax-quote
  over a literal collapses at read time.
- keyword "a/b" splits into ns/name like the seed (destructure {:keys [x/y]}).
- form-syntax-quote-lower implemented on Chez (was a throwing stub).

7 divergences allowlisted: the same print-method-multimethod / host-class set
the prelude gate defers. 328 crashes remain = shared runtime breadth (host
interop, missing core fns, eval/load-string) deferred to Phase 4 / jolt-r8ku,
not compiler faithfulness.

Gate + speedup: test/chez/run-corpus-zero-janet.janet (floor 2159). Its batched
runner (driver/eval-corpus-zero-janet) runs every case in ONE chez process —
load the runtime once, guard + reset the user namespace per case — instead of a
fresh process per case: 1379s -> 1.6s.

spine-test 35/35; Janet gate 151/0; prelude parity 2295/2494 unchanged, 0 new
divergences.
This commit is contained in:
Yogthos 2026-06-20 01:11:54 -04:00
parent d165198969
commit 8b86174b91
9 changed files with 460 additions and 19 deletions

View file

@ -25,7 +25,7 @@
[jolt.host :refer [form-sym? form-sym-name form-sym-ns form-sym-meta
form-list? form-vec? form-map? form-set? form-char?
form-literal? form-elements form-vec-items
form-map-pairs form-set-items]]))
form-map-pairs form-set-items form-char-code]]))
;; Hot clojure.core primitives lowered to native Scheme, mirroring the Janet
;; backend's native-ops. `=` is the exactness-aware jolt= from values.ss; inc/dec/
@ -148,10 +148,11 @@
(keyword? v) (if-let [kns (namespace v)]
(str "(keyword " (chez-str-lit kns) " " (chez-str-lit (name v)) ")")
(str "(keyword #f " (chez-str-lit (name v)) ")"))
;; jolt char value {:ch <codepoint> :jolt/type :jolt/char}. Use the host
;; contract form-char? — a :jolt/type-tagged struct is not a plain map? in
;; jolt, so a native map? test misses it.
(form-char? v) (str "(integer->char " (get v :ch) ")")
;; char literal -> (integer->char <codepoint>). Get the codepoint via the host
;; contract (form-char-code), NOT (get v :ch): on Janet a char is a struct with
;; a :ch field, but on Chez (the self-hosted spine) it's a native char, so the
;; struct-field read returns nil and emits (integer->char) with no arg.
(form-char? v) (str "(integer->char " (form-char-code v) ")")
:else (throw (ex-info (str "emit-const: unsupported literal " (pr-str v)) {}))))
;; Emit a call `(ctor a0 a1 ...)` with the args evaluated LEFT-TO-RIGHT. Chez's