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.
35 lines
1.8 KiB
Scheme
35 lines
1.8 KiB
Scheme
;; compile-eval.ss (jolt-hs9n, Phase 3 inc6) — the zero-Janet compile spine.
|
|
;;
|
|
;; Ties together the cross-compiled compiler image (jolt.ir + jolt.analyzer +
|
|
;; jolt.backend-scheme, loaded as def-var! forms) and the host contract
|
|
;; (host-contract.ss) into a runtime entry: a Clojure source string is read by the
|
|
;; Chez data reader, analyzed by the ON-CHEZ analyzer to IR, emitted to Scheme by
|
|
;; the ON-CHEZ emitter, and eval'd — no Janet in the loop. This is the spine the
|
|
;; stage2==stage3 bootstrap fixpoint (later increments) closes over.
|
|
;;
|
|
;; Loaded after host-contract.ss + the compiler image.
|
|
|
|
(define jolt-ce-analyze (var-deref "jolt.analyzer" "analyze"))
|
|
(define jolt-ce-emit (var-deref "jolt.backend-scheme" "emit"))
|
|
(define jolt-ce-read (var-deref "clojure.core" "read-string"))
|
|
|
|
;; The zero-Janet spine ALWAYS runs with the full clojure.core prelude loaded, so a
|
|
;; clojure.* ref must lower to var-deref (resolved from the prelude), not trip the
|
|
;; emitter's "unsupported stdlib fn (no core on Chez yet)" out-of-subset guard —
|
|
;; that guard is only for the bare -e subset with no prelude. Turn prelude mode on
|
|
;; once, here, so every analyze->emit on this spine sees the full core (jolt-qjr0).
|
|
((var-deref "jolt.backend-scheme" "set-prelude-mode!") #t)
|
|
|
|
;; Source string -> Scheme source string (read -> analyze -> emit, all on Chez).
|
|
;; `ns` is the compile namespace unqualified symbols resolve against.
|
|
(define (jolt-analyze-emit src ns)
|
|
(let* ((form (jolt-ce-read src))
|
|
(ctx (make-analyze-ctx ns))
|
|
(ir (jolt-ce-analyze ctx form)))
|
|
(jolt-ce-emit ir)))
|
|
|
|
;; Source string -> value (compile on Chez, then eval the emitted Scheme in the
|
|
;; top-level environment where rt.ss's runtime procedures live).
|
|
(define (jolt-compile-eval src ns)
|
|
(eval (read (open-input-string (jolt-analyze-emit src ns)))
|
|
(interaction-environment)))
|