Commit graph

12 commits

Author SHA1 Message Date
Yogthos
4d1ec44676 JVM parity: unchecked-char -> char, pr of infinities -> ##Inf
Allowlist review found three addressable divergences:
- unchecked-char returned a number; the JVM returns a char.
- the readable printer (pr-str, coll elements, the -e/REPL printer) rendered
  infinities as Infinity/inf; Clojure's readable form is ##Inf/##-Inf/##NaN
  (str/print still gives Infinity). So (pr-str ##Inf) => ##Inf, (str [##Inf]) =>
  [##Inf], (str ##Inf) => Infinity.

Corpus 2695->2698; allowlist 43->40 (drop the 3 now-passing entries). Re-minted.
2026-06-21 17:55:05 -04:00
Yogthos
31a453d492 (. obj :kw) is a keyword lookup (JVM parity)
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.
2026-06-21 17:13:40 -04:00
Yogthos
547a8c6d17 The .. threading macro analyzes as a macro, not interop (jolt-c2l1 tail)
(.. 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.
2026-06-21 17:08:11 -04:00
Yogthos
76f8274603 sorted-map entries are real map-entries (jolt-jk23)
sorted-map seq/first/entries built plain [k v] vectors, so map-entry? was false
and key/val threw. Build them via a new jolt.host/map-entry seam (entry-flagged
pvec), matching a regular map's entries. Re-minted.
2026-06-21 16:43:05 -04:00
Yogthos
7d0e2f2b61 dedupe: add the 0-arg transducer arity (jolt-05i2)
(into [] (dedupe) coll) / (sequence (dedupe) coll) threw an arity error — dedupe
was [coll]-only. Add the 0-arg stateful transducer (tracks [seen? prev] in a
volatile, no sentinel). Re-minted.
2026-06-21 15:42:01 -04:00
Yogthos
cf0b544baf Host interop fixes: ==/time/subvec/defonce + corpus cleanup
- == 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
2026-06-21 15:36:41 -04:00
Yogthos
48e2ef5910 Scrub dangling Janet references; drop dead Janet-coupled files
Rephrase comments that pointed at deleted Janet files (emit.janet, the seed
sources, 'the Janet back end punts ...') to present-tense descriptions of the
Chez behavior. Comment/docstring-only; the self-host fixpoint is unchanged
(comments don't affect the compiled seed).

Delete five files that were Janet-host shims with no Chez path: clojure.java.io
(provided natively by host/chez/io.ss), and jolt.{nrepl,png,interop,shell}
(the janet.* bridge, os/shell, janet.net — none exist on Chez).

jolt-cf1q.6
2026-06-21 12:01:04 -04:00
Yogthos
467ad75ff7 Chez numeric tower: exact ints / Ratio / double for JVM parity (jolt-n6al)
jolt was all-flonum (one :number type, inherited from Janet whose only number
type is a double). The Chez runtime has a full numeric tower, so the zero-Janet
path now carries it = JVM Clojure semantics:

  (/ 1 2)      => 1/2      (exact Ratio, was 0.5)
  (integer? 3) => true   (integer? 3.0) => false   (float? 3.0) => true
  (ratio? (/ 1 2)) => true   (= 3 3.0) => false   (== 3 3.0) => true
  (+ 1 2) => 3 (exact)   (/ 1.0 2) => 0.5 (double)

jolt= was already exactness-aware (values.ss) and == is value-equality, so
=/== match the JVM split. The reader preserves exactness (integer literals exact,
a/b ratios exact rationals, decimals/exponents flonums); backend_scheme emit-const
renders exact ints/ratios and flonums faithfully; the value-position arithmetic,
count, int, compare, bit ops, parseLong, string .length/.indexOf, range,
timestamps, and array bytes return exact integers (= JVM int/long) instead of
coercing to flonum. double/parseDouble/clojure.math floor|ceil|signum stay double.

Only the zero-Janet path carries the tower (the Janet reader loses exactness into
a double before emit). The prelude/all-flonum path is unaffected for compiled code;
the runtime reader is shared, so a couple of all-flonum reader assertions become
value (==) assertions. ~16 numeric corpus cases now give the JVM tower value vs the
Janet-era :expected and are allowlisted as tower divergences (Chez == reference
JVM) pending the corpus flip to JVM (jolt-ecz0). No BigDecimal type (1M).

Re-minted. zero-janet 2682 (floor 2698->2682, the reclassified tower cases), 0 new
divergences; fixpoint 10/10, bootstrap 6/6, spine 35/35, cli 49/49; Janet gate 155
files 0 failed.
2026-06-20 23:09:27 -04:00
Yogthos
eb1c3298a4 Chez parity: trailing-apostrophe symbols + arglist return hints (jolt-vgrp, jolt-5540)
Two Chez reader bugs, both JVM-parity gaps:

inc'/+'/foo' (trailing apostrophe) were mis-read as a symbol followed by a
quote macro, because the reader treated ' as a terminator. In Clojure ' is a
NON-terminating macro char (constituent after the first char). Since the seed
is minted on Chez, (def inc' inc) became (def inc 'inc), clobbering inc's var
cell with its own symbol -- so (var-get (var inc)) returned the symbol, not the
fn. Drop ' from the token terminator set; a leading ' still quotes.

^bytes [b] / ^String [x y] return-type hints: the Chez reader lowered ^meta on
a collection to a (with-meta vec meta) form, but emitted a QUALIFIED
clojure.core/with-meta while the Janet reader emits a bare with-meta -- so the
fn/defn macros' unwrap logic (matching the bare head) slipped past it and choked
on a non-vector arglist. Emit bare with-meta to match Janet, and unwrap a
(with-meta <vec> _) arglist in analyze-fn as a backstop.

Re-minted the seed. zero-janet 2699, prelude 2652, Janet gate 155/0, fixpoint
10/10, bootstrap 6/6, all 0 new divergences.
2026-06-20 22:17:29 -04:00
Yogthos
ec30c9e405 Chez concurrency pt.1: real OS-thread futures + blocking promises (shared heap)
future/future-call run the body on a native thread (fork-thread) over the SAME
heap — JVM semantics, not Janet's isolated-heap snapshot. deref blocks on a
mutex+condition latch; timed (deref f ms val) uses an absolute deadline.
promise is a real blocking promise (deref parks until deliver), replacing the
Janet non-blocking atom shim. future?/future-done?/future-cancelled?/future-cancel
/realized? are native (the overlay versions read Janet map keys); re-asserted in
post-prelude over the overlay. pmap/pcalls/pvalues (overlay, over future) light
up for free.

Thread-safety this forces:
- atoms get a per-atom mutex; swap!/swap-vals! are a JVM-style CAS loop (f runs
  outside the lock, so a watch/validator can deref the same atom); reset!/
  compare-and-set! are atomic.
- the dynamic binding stack becomes a Chez thread-parameter, so each future/thread
  has its own; Chez inherits it at fork, giving binding conveyance (the shim also
  installs an explicit snapshot).
- Thread/sleep really sleeps now (a worker sleeping doesn't block the parent).

Re-minted the seed: future-call now resolves at compile time, so pmap compiles to
a var-deref instead of the host-static-call fallback that crashed. image.ss
unchanged.

Corpus: the 2 snapshot cases now match the JVM (shared) not Janet (isolated) —
allowlisted on both Chez gates; the two racy future-cancel cases allowlisted;
"promise undelivered" (blocks on JVM/Chez, profile :bucket :timeout) skipped like
:throws. Zero-Janet corpus 2544 -> 2569, 0 new divergences, floor raised. Full
Janet gate + JVM cert green.

jolt-byjr
2026-06-20 13:11:31 -04:00
Yogthos
6abbea3835 Fix 4 clojure.core bugs surfaced by JVM certification
The corpus certifier (test/conformance) flagged four cases where jolt's
hand-written :expected matched a real defect rather than Clojure. Fixed in the
jolt-core overlay, corrected the spec :expected, re-certified against JVM Clojure:

- ex-message: returns nil for a non-throwable (dropped the lenient string branch);
  still returns the message for ex-info. (jolt-l8e8)
- munge: preserves the argument's type — a symbol munges to a symbol, not a string.
  (jolt-hc35)
- print: (print nil) emits "nil", not "" (top-level nil guard; str yields "").
  (jolt-pqio)
- bounded-count: uses the counted? fast path (full count), else counts up to n via
  seq — was (min n (count coll)), wrong for counted colls. Added an uncounted-coll
  spec case. (jolt-2507)

Removed the 4 :bug entries from known-divergences.edn (now certified), regenerated
corpus + profile, re-minted the Chez bootstrap seed (clojure.core changed). Gates:
Janet 155/0, JVM certify clean, both Chez corpus gates 2534 (floors raised),
bootstrap 6/6, fixpoint intact.
2026-06-20 11:06:33 -04:00
Yogthos
2c74476aed Chez Phase 3 inc9a: self-contained Chez bootstrap (no Janet in the loop)
Makes the inc8 fixpoint the actual build. host/chez/bootstrap.ss loads a seed
(prelude, image) pair and rebuilds the clojure.core prelude + compiler image from
source via the on-Chez compiler — read/analyze/emit all on Chez, zero Janet.

The seed (host/chez/seed/{prelude,image}.ss) is the checked-in bootstrap
compiler, minted once via the fixpoint (driver/mint-chez-seed* iterates
bootstrap.ss from the Janet-emitted pair to a joint byte-fixpoint). It's a joint
fixpoint: rebuilding from an up-to-date seed reproduces it exactly. So a fresh
checkout + Chez (no Janet) yields a working jolt.

test/chez/bootstrap-test.janet spawns only chez, asserts the rebuilt artifacts
match the seed byte-for-byte and compile+run real cases. Drift (seed sources
changed) fails the test with a re-mint pointer; host/chez/seed/README documents
re-minting.
2026-06-20 06:46:05 -04:00