Chez Phase 2 (inc P): clojure.string namespace (jolt-nfca)

Bring the clojure.string namespace up on Chez so aliased refs like s/split,
s/upper-case, s/join, s/replace resolve and run.

Three pieces. (1) The Chez AOT driver analyzes the whole user form before any
require runs, so a (require '[clojure.string :as s]) never registered the
alias in time; eval-e-with-prelude now recursively pre-evals require/use forms
against the ctx, which loads the aliased ns and registers the alias so the
analyzer resolves s/X to a clojure.string var. (2) emit-core-prelude emits
stdlib namespaces (clojure.string) as their own def-var! tier through the same
analyze->emit pipeline, so the runtime var-deref resolves. (3) natives-str.ss
def-var!s the str-* primitives clojure.string.clj is written over (upper/lower/
trim/triml/trimr/find/reverse-b/join/split/replace/replace-all), plus no-op
require/use. Regex split keeps interior empties and honors the limit (ported
the seed re-split); regex replace does $N backref expansion and fn replacement
(ported replacement-for). new RT/clj files added to the prelude fingerprint.

Corpus prelude floor 2026 -> 2078 (+52), 0 new divergences. _strns 28/28 vs
build/jolt. Four previously-CRASHING cases now emit+run and surface pre-existing
gaps (read-line vector eval-order x3, instance? clojure.lang.Atom) — allowlisted
with notes. full jpm test + conformance x3 green.
This commit is contained in:
Yogthos 2026-06-18 21:38:13 -04:00
parent 3ab53ba938
commit a706a79b90
5 changed files with 275 additions and 5 deletions

View file

@ -71,7 +71,21 @@
"defmethod fires through prn" 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})
"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
# - (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.
"atom?" true})
(def ctx (d/make-ctx))
@ -200,8 +214,14 @@
# a string target: case/trim/length/indexOf/substring/startsWith/contains/replace/
# charAt/equalsIgnoreCase + the regex methods matches/replaceAll/replaceFirst/
# split) 2026.
# jolt-nfca cont. (clojure.string namespace — the driver pre-evals (require ...)
# so an aliased ref like s/split resolves at analyze time; clojure.string.clj is
# emitted as a prelude tier over the str-* primitives (str-upper/lower/trim/find/
# 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.
# Strided runs scale down.
(def base-floor (scan-number (or (os/getenv "JOLT_CHEZ_PRELUDE_FLOOR") "2026")))
(def base-floor (scan-number (or (os/getenv "JOLT_CHEZ_PRELUDE_FLOOR") "2078")))
(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)))