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:
parent
3ab53ba938
commit
a706a79b90
5 changed files with 275 additions and 5 deletions
66
test/chez/_strns.janet
Normal file
66
test/chez/_strns.janet
Normal file
|
|
@ -0,0 +1,66 @@
|
|||
# jolt-nfca (clojure.string half) — the clojure.string namespace on Chez via the
|
||||
# alias `s` established by a runtime (require '[clojure.string :as s]). The Chez
|
||||
# AOT driver pre-evals require forms against the ctx so the alias resolves at
|
||||
# analyze time, and clojure.string is emitted as a prelude tier over the str-*
|
||||
# primitives. Expectations are the build/jolt (seed) oracle.
|
||||
#
|
||||
# janet test/chez/_strns.janet
|
||||
(def jolt-bin (or (os/getenv "JOLT_BIN") "bin/jolt-chez"))
|
||||
|
||||
(defn- with-req [body] (string "(do (require (quote [clojure.string :as s])) " body ")"))
|
||||
|
||||
# [label body-after-require expected]
|
||||
(def cases
|
||||
[["upper-case" "(s/upper-case \"abc\")" "ABC"]
|
||||
["lower-case" "(s/lower-case \"ABC\")" "abc"]
|
||||
["capitalize" "(s/capitalize \"hello\")" "Hello"]
|
||||
["trim" "(s/trim \" x \")" "x"]
|
||||
["triml" "(= \"x \" (s/triml \" x \"))" "true"]
|
||||
["trimr" "(= \" x\" (s/trimr \" x \"))" "true"]
|
||||
["blank? empty" "(s/blank? \"\")" "true"]
|
||||
["blank? ws" "(s/blank? \" \")" "true"]
|
||||
["blank? no" "(s/blank? \"x\")" "false"]
|
||||
["blank? nil" "(s/blank? nil)" "true"]
|
||||
["includes? y" "(s/includes? \"abcd\" \"bc\")" "true"]
|
||||
["includes? n" "(s/includes? \"abcd\" \"zz\")" "false"]
|
||||
["starts-with? y" "(s/starts-with? \"abc\" \"ab\")" "true"]
|
||||
["starts-with? n" "(s/starts-with? \"abc\" \"bc\")" "false"]
|
||||
["ends-with? y" "(s/ends-with? \"abc\" \"bc\")" "true"]
|
||||
["join no sep" "(s/join [\"a\" \"b\" \"c\"])" "abc"]
|
||||
["join sep" "(s/join \",\" [\"a\" \"b\" \"c\"])" "a,b,c"]
|
||||
["join nums" "(s/join \"-\" [1 2 3])" "1-2-3"]
|
||||
["split literal" "(s/split \"a,b,c\" \",\")" "[a b c]"]
|
||||
["split regex" "(s/split \"a1b2c\" #\"[0-9]\")" "[a b c]"]
|
||||
["split-lines" "(s/split-lines \"a\\nb\\nc\")" "[a b c]"]
|
||||
["replace lit" "(s/replace \"a_b_c\" \"_\" \"-\")" "a-b-c"]
|
||||
["replace regex" "(s/replace \"a1b2\" #\"[0-9]\" \"\")" "ab"]
|
||||
["replace-first" "(s/replace-first \"a_b_c\" \"_\" \"-\")" "a-b_c"]
|
||||
["reverse" "(s/reverse \"abc\")" "cba"]
|
||||
["index-of hit" "(s/index-of \"abc\" \"b\")" "1"]
|
||||
["index-of miss" "(nil? (s/index-of \"abc\" \"z\"))" "true"]
|
||||
["trim-newline" "(s/trim-newline \"abc\\n\\n\")" "abc"]])
|
||||
|
||||
(defn run-capture [expr]
|
||||
(def proc (os/spawn [jolt-bin "-e" expr] :p {:out :pipe :err :pipe}))
|
||||
(def out (ev/read (proc :out) 0x100000))
|
||||
(def err (ev/read (proc :err) 0x100000))
|
||||
(def code (os/proc-wait proc))
|
||||
(def lines (filter (fn [l] (not (empty? l)))
|
||||
(string/split "\n" (string/trim (if out (string out) "")))))
|
||||
[code (if (empty? lines) "" (last lines)) (if err (string err) "")])
|
||||
|
||||
(var pass 0)
|
||||
(def fails @[])
|
||||
(each [label body expected] cases
|
||||
(def [code got err] (run-capture (with-req body)))
|
||||
(cond
|
||||
(not= code 0) (array/push fails [label (string "exit " code "; err: " (string/trim err))])
|
||||
(= got expected) (++ pass)
|
||||
(array/push fails [label (string "want `" expected "`, got `" got "`")])))
|
||||
|
||||
(printf "\n_strns parity [%s]: %d/%d passed" jolt-bin pass (length cases))
|
||||
(when (> (length fails) 0)
|
||||
(printf "%d FAIL(s):" (length fails))
|
||||
(each [l m] fails (printf " FAIL [%s] %s" l m)))
|
||||
(flush)
|
||||
(os/exit (if (empty? fails) 0 1))
|
||||
|
|
@ -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)))
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue