The on-Chez analyzer (inc6a) skipped macros, so let/when/->/defn didn't
expand from source. Each core/stdlib defmacro now emits into the prelude as
(def-var! ns name <expander fn>) + (mark-macro! ns name); form-macro?/
form-expand-1 on Chez look up the macro flag (rt.ss var-macro-table) and
apply the expander to the unevaluated arg forms, and the analyzer re-analyzes
the result. The expander's syntax-quote template was lowered to construction
code at cross-compile time, so it builds the expansion via __sqcat/__sqvec/
__sqmap/__sqset/__sq1 (new host/chez/syntax-quote.ss) as Chez reader forms.
Emit the bare (fn ...), not (def NAME (fn ...)): analyzing a def would
host-intern! NAME as a non-macro stub in the build ctx, and that stub makes a
later (require '[stdlib-ns]) skip loading the real macro — with-pprint-dispatch
then resolved as a fn and returned its unexpanded template. Wrapping the
lambda in def-var! manually never interns NAME. Fuller build-ctx isolation
(so stdlib cases pass instead of crash) tracked in jolt-lpvi.
__sqset builds a real set VALUE, not the reader's tagged-set form — a runtime
`#{~@xs} must be a set, not a map. form-set? additionally recognizes a pset so
a macro template's #{...} expansion still re-analyzes as a set literal.
spine-test 35/35 (20 macro cases: when/when-not/let/->/->>/and/or/cond/if-not/
defn run zero-Janet from source). Prelude parity 2280->2295, 0 new divergences.
Full Janet gate green.
97 lines
3.4 KiB
Text
97 lines
3.4 KiB
Text
# 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))
|
|
|
|
# inc6b (jolt-r9lm): runtime macros — the on-Chez analyzer expands core macros
|
|
# (emitted into the prelude as expander fns + a macro flag). Same oracle: the
|
|
# Janet analyzer expands them at analyze time, the value must match.
|
|
(each src
|
|
["(when true 1)"
|
|
"(when false 1)"
|
|
"(when true 1 2 3)"
|
|
"(when-not false 5)"
|
|
"(let [a 1] (+ a 2))"
|
|
"(let [a 1 b 2] (+ a b))"
|
|
"(let [a 1 b (+ a 1)] (* a b))"
|
|
"(-> 1 inc inc)"
|
|
"(-> 5 (- 2))"
|
|
"(->> 3 (- 10))"
|
|
"(and 1 2 3)"
|
|
"(and 1 false 3)"
|
|
"(or nil 5)"
|
|
"(or false nil 7)"
|
|
"(cond false 1 true 2)"
|
|
"(cond false 1 :else 3)"
|
|
"(if-not false :a :b)"
|
|
"(do (defn f [x] (* x x)) (f 6))"
|
|
"(do (defn g [x y] (+ x y 1)) (g 3 4))"
|
|
"(let [a 1] (when (< a 5) (-> a inc inc)))"]
|
|
(check src))
|
|
|
|
(printf "\n%d/%d ok" (- total fails) total)
|
|
(when (> fails 0) (os/exit 1))
|