Chez Phase 3 inc6a: zero-Janet spine (analyzer + emitter on Chez), macro-free
Cross-compile jolt.ir + jolt.analyzer + jolt.backend-scheme to Scheme def-var! forms via the existing Janet emit pipeline (driver/emit-compiler-image) and run them ON CHEZ over a Scheme jolt.host impl. A macro-free Clojure expression now compiles and runs with no Janet in the loop: read (reader.ss) -> analyze (jolt.analyzer on Chez) -> IR -> emit (jolt.backend-scheme on Chez) -> eval. host/chez/host-contract.ss is the jolt.host contract on Chez (the portable seam the cross-compiled analyzer/emitter call): form-* over the Chez reader's forms, resolve-global/compile-ns/host-intern!/late-bind? over the var-cell registry. ctx is an opaque record carrying the compile ns. Native-op names are declare-var!'d into clojure.core so +, *, <, ... classify as :var and the emitter's native-op path lowers them. form-macro? is a #f stub and macro expansion / syntax-quote / record hints are stubs for inc6b (runtime macros, jolt-r8ku). host/chez/compile-eval.ss is the spine entry (read-string -> analyze -> emit -> eval). driver gains emit-compiler-image / ensure-compiler-image (image caching) and program-zero-janet / eval-zero-janet. Two bugs fixed in the keeper, not reproduced: - the Chez reader stores an unqualified symbol's ns as #f, but the analyzer tests (nil? ns); hc-sym-ns normalizes #f/'() -> jolt-nil. Without it every handled special (if/do/fn*) misanalyzed as a plain invoke. - char (int->char) was missing from clojure.core on Chez; the emitter's chez-str-lit needs it for keyword/string consts. Added jolt-char to converters.ss. Gate: test/chez/spine-test.janet 15/15 (Chez-hosted analyzer value == Janet-hosted oracle through the same emitter/RT; only the analysis host differs). Full Janet gate green (150 files). driver.janet is in the prelude fingerprint so the cache key moved; prelude content is unchanged. jolt-chez fingerprint/ensure-prelude made public for the test harness.
This commit is contained in:
parent
c47ae7fd22
commit
c2d977cadf
6 changed files with 398 additions and 2 deletions
71
test/chez/spine-test.janet
Normal file
71
test/chez/spine-test.janet
Normal file
|
|
@ -0,0 +1,71 @@
|
|||
# Chez Phase 3 inc6 (jolt-hs9n) — the zero-Janet spine.
|
||||
#
|
||||
# Validates that the analyzer + emitter, cross-compiled to Scheme and run ON CHEZ
|
||||
# over the host contract (host-contract.ss), compile and run macro-free Clojure
|
||||
# from source with NO Janet in the loop: read (reader.ss) -> analyze (jolt.analyzer
|
||||
# on Chez) -> IR -> emit (jolt.backend-scheme on Chez) -> eval.
|
||||
#
|
||||
# Oracle = the Janet-hosted analyzer through the SAME Chez emitter/RT/printer
|
||||
# (d/eval-e-with-prelude): the only difference under test is WHERE analysis runs
|
||||
# (Janet vs Chez), so equal stdout means moving analysis onto Chez is behavior-
|
||||
# preserving. Macros (let/when/->/defn) are inc6b (jolt-r8ku, runtime macros).
|
||||
#
|
||||
# janet test/chez/spine-test.janet
|
||||
(import ../../src/jolt/api :as api)
|
||||
(import ../../host/chez/driver :as d)
|
||||
(import ../../host/chez/jolt-chez :as jc)
|
||||
|
||||
(var total 0) (var fails 0)
|
||||
(defn ok [name pred &opt extra]
|
||||
(++ total)
|
||||
(if pred (printf "ok: %s" name)
|
||||
(do (++ fails) (printf "FAIL: %s %s" name (or extra "")))))
|
||||
|
||||
(unless (d/chez-available?)
|
||||
(print "chez not on PATH — skipping spine-test")
|
||||
(os/exit 0))
|
||||
|
||||
(def ctx (d/make-ctx))
|
||||
(def prelude-path (jc/ensure-prelude ctx))
|
||||
|
||||
# compiler image cache, keyed by the cross-compiled sources + the host contract.
|
||||
(defn- image-fingerprint []
|
||||
(string/slice (string (hash (string/join
|
||||
(map slurp ["jolt-core/jolt/ir.clj" "jolt-core/jolt/analyzer.clj"
|
||||
"jolt-core/jolt/backend_scheme.clj" "host/chez/host-contract.ss"
|
||||
"host/chez/compile-eval.ss"])))) 0))
|
||||
(def image-path
|
||||
(string (or (os/getenv "TMPDIR") "/tmp") "/jolt-compiler-image-" (image-fingerprint) ".ss"))
|
||||
(d/ensure-compiler-image ctx image-path)
|
||||
|
||||
# Each case: the Chez-hosted spine value must equal the Janet-hosted oracle value
|
||||
# (both printed via jolt-final-str on Chez).
|
||||
(defn check [src]
|
||||
(def [ocode oout oerr] (d/eval-e-with-prelude ctx src prelude-path))
|
||||
(def [acode aout aerr] (d/eval-zero-janet prelude-path image-path src))
|
||||
(cond
|
||||
(= ocode :emit-err) (ok src false (string "oracle emit-err: " oout))
|
||||
(not (zero? acode)) (ok src false (string "zero-janet exit " acode ": " aerr " | out=" aout))
|
||||
(ok src (= oout aout) (string "chez=" aout " oracle=" oout))))
|
||||
|
||||
# macro-free forms: handled specials (if/do/fn*), native ops, consts, invoke.
|
||||
(each src
|
||||
["(if true 10 20)"
|
||||
"(if false 10 20)"
|
||||
"(do 1 2 3)"
|
||||
"(+ 1 2)"
|
||||
"(- 10 3 2)"
|
||||
"((fn* [x] (* x x)) 7)"
|
||||
"((fn* [x] (+ x 1)) 5)"
|
||||
"((fn* [a b] (+ a b)) 3 4)"
|
||||
"(if (< 3 5) :yes :no)"
|
||||
"(if (> 3 5) :yes :no)"
|
||||
"((fn* [x] (if x :t :f)) true)"
|
||||
"(do (if true 1 2) (* 6 7))"
|
||||
"((fn* [n] (* n n n)) 4)"
|
||||
"(< 1 2)"
|
||||
"(= 5 5)"]
|
||||
(check src))
|
||||
|
||||
(printf "\n%d/%d ok" (- total fails) total)
|
||||
(when (> fails 0) (os/exit 1))
|
||||
Loading…
Add table
Add a link
Reference in a new issue