Host gaps that blocked malli: map .iterator, two clojure.lang builders

malli loads and validates now. Three divergences surfaced building its registry
and :map schema:

dot-forms: (.iterator coll) on a map fell into the map-as-object branch and was
mis-read as a missing :iterator key (nil), so malli's -vmap got nil and crashed
on .hasNext. Route iterator through the collection-interop path — a jiterator
over the seq (the entry iterator for a map).

host-static: register clojure.lang.LazilyPersistentVector/createOwning (-vmap
fills an object-array then hands it over) and PersistentArrayMap/createWithCheck
(malli's eager entry parser relies on its duplicate-key throw; a missing class
was caught and mis-reported as ::duplicate-keys on every map schema).
This commit is contained in:
Yogthos 2026-06-22 05:35:08 -04:00
parent 6ab65a30e3
commit 4114766c71
3 changed files with 30 additions and 0 deletions

View file

@ -38,6 +38,11 @@
((or (string=? name "get") (string=? name "valAt"))
(list (apply jolt-get obj args)))
((string=? name "containsKey") (list (jolt-contains? obj (car args))))
;; (.iterator coll): a java.util.Iterator over the seq — for a map this is the
;; entry iterator. Without this a map's .iterator falls into the map-as-object
;; branch and is mis-read as a missing :iterator key (nil). Some libraries
;; (e.g. malli's -vmap) iterate a map this way.
((string=? name "iterator") (list (make-jiterator (jolt-seq obj))))
(else #f)))
;; Universal object-methods: on a

View file

@ -164,6 +164,28 @@
(register-class-statics! "LockingTransaction" (list (cons "isRunning" (lambda () #f))))
(register-class-statics! "clojure.lang.LockingTransaction" (list (cons "isRunning" (lambda () #f))))
;; clojure.lang.LazilyPersistentVector/createOwning: build a vector from an array
;; (malli's -vmap fills an object-array then hands it over). jolt has no array
;; ownership transfer, so copy the array's elements into a persistent vector.
(define (lpv-create-owning arr) (apply jolt-vector (seq->list (jolt-seq arr))))
(register-class-statics! "LazilyPersistentVector" (list (cons "createOwning" lpv-create-owning)))
(register-class-statics! "clojure.lang.LazilyPersistentVector" (list (cons "createOwning" lpv-create-owning)))
;; clojure.lang.PersistentArrayMap/createWithCheck: build a map from a [k v k v…]
;; array, throwing on a duplicate key. malli's eager entry parser relies on the
;; throw to report ::duplicate-keys, so a missing class would mis-fire on every
;; map. Build the map and signal if a key collapsed (count*2 < array length).
(define (pam-create-with-check arr)
(let ((items (seq->list (jolt-seq arr))))
(let loop ((xs items) (m (jolt-hash-map)))
(if (null? xs) m
(if (null? (cdr xs)) (error #f "PersistentArrayMap: odd key/value count")
(let ((k (car xs)))
(if (jolt-contains? m k) (error #f "Duplicate key")
(loop (cddr xs) (jolt-assoc m k (cadr xs))))))))))
(register-class-statics! "PersistentArrayMap" (list (cons "createWithCheck" pam-create-with-check)))
(register-class-statics! "clojure.lang.PersistentArrayMap" (list (cons "createWithCheck" pam-create-with-check)))
(define (now-millis)
(let ((t (current-time 'time-utc)))
(+ (* 1000 (time-second t)) (quotient (time-nanosecond t) 1000000))))

View file

@ -70,6 +70,9 @@
(let-values (((form j) (rdr-read-form src i end)))
(when (> j i)
(unless (rdr-eof? form)
(when (getenv "JOLT_TRACE_LOAD")
(display " [load-form] " (current-error-port))
(display (jolt-pr-str form) (current-error-port)) (newline (current-error-port)))
(jolt-compile-eval-form form (chez-current-ns)))
(loop j)))))))