A macro that syntax-quoted interop — `(.. (StringBuilder.) (.append x)) — had
its .method / Class. / .-field heads qualified to the compile ns (user/.append,
user/StringBuilder.), so they read as 'Unknown class user' at expansion. Like
Clojure, leave interop-head symbols bare in syntax-quote. Fixes any macro
templating interop, not just the one corpus case. Corpus 2694->2695.
(reduce f init (reify clojure.lang.IReduceInit (reduce [_ f i] ...))) tried to
seq the reify and threw 'not seqable'. When the coll is a reify carrying a reduce
method, drive the reduction through it. Corpus 2693->2694.
The . special form rejected a non-symbol member; a keyword member now lowers to
an invoke of the keyword on the target ((. {:value 41} :value) => 41, as on the
JVM). Added a form-keyword? contract seam. Corpus 2692->2693. Re-minted.
(:import [other.ns Type]) was a no-op (import unbound), so (Type. ...) failed
with 'Unknown class'. Bind import to register each named type's ctor closure
under the current ns. Corpus 2691->2692.
(.. x m ...) failed: the analyzer classified the .. head as a .method interop
call (method-head? matched any "."-prefixed name) and form-special?
(hc-interop-head?) also flagged it, so it never reached the macro check. Exclude
".." from both (the char after "." being "." means the threading macro, not
.method). Corpus 2690->2691. Re-minted.
JVM assoc! is variadic: with a complete first pair present (>=3 kvs), a trailing
lone key fills nil ((assoc! t :a 1 :b) => {:a 1 :b nil}); a lone key alone (1 kv)
is still a wrong-arity throw. jolt delegated to the strict persistent assoc which
threw on any odd count. Pad a trailing nil for odd kvs >=3. Corpus 2688->2690.
The per-form eval passed a FIXED compile-ns to every subform of a top-level do,
so a runtime (ns ...)/(in-ns ...) didn't redirect later defs/refs — defs landed
in the wrong ns and qualified refs hit host-static ("Unknown class"). Thread
the current ns: each subform analyzes in (chez-current-ns), which ns/in-ns move.
That exposed two more gaps, now fixed:
- use refers ALL of a target's public vars (a refer-all table consulted by
chez-resolve-refer) — was bound to plain require (explicit :refer only).
- defmethod on a QUALIFIED multifn (cf.mm/ext from another ns) resolves in the
symbol's ns, not the current one (was auto-creating a stray multifn).
Corpus 2684->2688, 0 new divergences; floor raised. No re-mint (runtime shims).
- == 1-arg returns true for any value (Clojure short-circuits before the number
check), not 'requires numbers'.
- current-time-ms wired to now-millis so the time macro works.
- subvec truncates float/ratio indices via long (Scheme quotient rejects flonums).
- defonce checks bound? not var-get — in a top-level do the name is already an
unbound interned cell, which var-get throws on.
- drop the line-seq corpus row (used janet/spit, N/A); allowlist char-array
(needs Class/forName "[C").
Corpus 2678->2683, floor raised. Re-minted. Full gate green; CI green.
jolt-cf1q.7
Add a Janet-free gate so correctness can be judged with only Chez + Clojure:
- host/chez/run-corpus.ss: corpus.edn vs JVM expecteds, lifting the per-case ns
isolation from the old Janet driver; reads corpus.edn via the jolt reader.
- host/chez/run-unit.ss + test/chez/unit.edn: the host-specific unit cases,
evaluated in-process and compared to baked expecteds.
- host/chez/selfcheck.sh: self-host fixpoint (bootstrap.ss rebuild == checked-in seed).
- host/chez/smoke.sh: real bin/joltc CLI smoke.
- host/chez/remint.sh: re-mint the seed to a byte-fixpoint after a source change.
- Makefile: 'make test' runs the lot; 'make remint' rebuilds the seed.
Numbers match the Janet gate: corpus 2679/2757 0 new div, unit 450/450, certify
0 new/0 stale.
jolt-cf1q.6