Chez Phase 2 (inc Q): Java class statics + constructors (jolt-avt6)

Lower host class interop on the Chez back end. The analyzer now turns a
non-var qualified ref `Class/member` into a :host-static node and a
`(Class. ...)` / `(new Class ...)` form into a :host-new node (ir.clj
gains both, with walker support). The Janet back end punts both to the
interpreter, so its behavior is unchanged (verified: dot-form, `..`
threading, shadowed `new`, and all interop still resolve via fallback).

The Chez emit lowers a value ref to host-static-ref, a call head to
host-static-call, and a constructor to host-new. host/chez/host-static.ss
is the runtime registry these resolve against — the Chez port of the
seed's class-statics / class-ctors / tagged-methods (java_base.janet +
host_io.janet), restricted to the java.lang/util/net/io surface portable
cljc code calls: Math, System (getenv/getProperty/exit/currentTimeMillis),
Long, Integer, Boolean, Character, String, Thread, Class, Pattern
(compile/quote/MULTILINE), URLEncoder/Decoder, Base64, the Number method
surface (byteValue/intValue/...), plus the StringBuilder, StringWriter,
StringReader, PushbackReader, HashMap, StringTokenizer, BigInteger,
String, MapEntry, and exception constructors. Constructed objects are
jhost records dispatched through record-method-dispatch.

Also: emit now evaluates collection-literal elements left-to-right
(emit-ordered) — Chez evaluates call args right-to-left, which had been
swapping side-effecting elements in [(read r) (read r)] and map literals.
This un-allowlisted the 6 eval-order corpus cases (the read-line trio +
the three map-construction cases). Removed `.write` from the
jolt-host-call fast-path so a StringWriter routes through dispatch.

java.time formatting, edn/read-over-readers, and slurp/with-open over
readers are deferred to a follow-up.

Corpus parity 2078 -> 2134 (floor raised), 0 new divergences; the
print-method builtin-override case is allowlisted (same multimethod gap,
newly reachable now that StringWriter constructs). emit-test 326/326,
_javastatic 51/51, conformance 355x3, full jpm test green.
This commit is contained in:
Yogthos 2026-06-18 23:24:01 -04:00
parent a706a79b90
commit c90c4cb610
10 changed files with 711 additions and 26 deletions

View file

@ -45,9 +45,10 @@
{"class name evaluates to canonical string" true
"dispatch-only class name" true
"inside class" true
"values evaluate in source order" true
"keys evaluate before their values, pairwise" true
"source order with a nil value (phm form)" true
# (the collection-literal eval-order entries here — "values evaluate in source
# order" / "keys evaluate before their values" / "source order with a nil value"
# — were REMOVED in jolt-avt6: emit now evaluates vector/set/map literal
# elements left-to-right via emit-ordered, so they pass.)
"close on throw" true
# *ns* now a namespace value (jolt-yxqm): str/ns-name of *ns* + the var str
# case ("ns-name of *ns*" / "str of *ns*" / "*ns* user" / "str of a var") pass.
@ -69,19 +70,21 @@
"defmethod overrides a record, top level" true
"defmethod fires nested in a map" true
"defmethod fires through prn" true
# Same print-method gap, newly REACHABLE in jolt-avt6: StringWriter now
# constructs, so (defmethod print-method :number ...) + (print-method 42 w)
# runs — but print-method's multimethod override on a builtin isn't consulted,
# so the StringWriter holds "42" not "#42#". (The :default print-method path —
# "StringWriter accumulates" / "direct call uses :default" — does pass now.)
"direct builtin override" true
# var def-time metadata (^:private / ^Type tag / docstring) is now captured on
# the Chez var-cell (jolt-zikh), so those three cases pass.
"methods table inspectable" true
# jolt-nfca made (require ...) a runtime no-op (the driver pre-evals requires
# for aliases), and the clojure.string prelude tier now loads — which makes
# these previously-CRASHING cases emit + run, surfacing pre-existing gaps:
# - the read-line trio reads two lines into a [(read-line) (read-line)] vector;
# the emitted Scheme evaluates the two elements in non-source order (the same
# eval-order gap already allowlisted above as "values evaluate in source
# order"), so the lines come back swapped. Reachable now that with-in-str runs.
"read-line sequential" true
"read-line after last" true
"empty line" true
# - the read-line trio ([(read-line) (read-line)]) now PASSES: jolt-avt6's
# emit-ordered evaluates the two vector elements left-to-right, so the lines
# no longer come back swapped (the entries were removed here).
# - (instance? clojure.lang.Atom (atom 0)): the fully-qualified host class name
# clojure.lang.Atom isn't mapped to the atom predicate on Chez (host-class
# interop, jolt-mn9o/avt6). Reachable now that the leading require is a no-op.
@ -220,8 +223,18 @@
# join/split/replace/replace-all/reverse-b) def-var!'d on the RT; regex split
# keeps interior empties + honors limit, regex replace does $N + fn replacement;
# require/use are runtime no-ops) 2078.
# jolt-avt6 (host class statics + constructors — the analyzer lowers Class/member
# to :host-static and (Class. ...)/(new Class ...) to :host-new; the Chez RT
# resolves them from class-statics/class-ctors/jhost-method registries
# (host-static.ss): Math/System/Long/Integer/Boolean/Character/String/Thread/Class
# statics, Pattern compile/quote/MULTILINE, URLEncoder/Decoder, Base64, the Number
# method surface (byteValue/intValue/...), and the StringBuilder/StringWriter/
# StringReader/PushbackReader/HashMap/StringTokenizer/BigInteger/String/MapEntry/
# exception constructors. Also emit now evaluates collection-literal elements
# left-to-right (emit-ordered), which un-allowlisted the 6 eval-order cases.
# java.time formatting / edn-read-over-readers / slurp-over-readers deferred) 2134.
# Strided runs scale down.
(def base-floor (scan-number (or (os/getenv "JOLT_CHEZ_PRELUDE_FLOOR") "2078")))
(def base-floor (scan-number (or (os/getenv "JOLT_CHEZ_PRELUDE_FLOOR") "2134")))
(def floor (if (os/getenv "JOLT_CORPUS_LIMIT") 0 base-floor))
(when (or (> (length diverged) 0) (< pass floor))
(printf "REGRESSION: pass %d < floor %d or %d new divergence(s)" pass floor (length diverged)))