From 4114766c710b6035229bc3fbd5c2354ebadc5e9d Mon Sep 17 00:00:00 2001 From: Yogthos Date: Mon, 22 Jun 2026 05:35:08 -0400 Subject: [PATCH] Host gaps that blocked malli: map .iterator, two clojure.lang builders MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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). --- host/chez/dot-forms.ss | 5 +++++ host/chez/host-static.ss | 22 ++++++++++++++++++++++ host/chez/loader.ss | 3 +++ 3 files changed, 30 insertions(+) diff --git a/host/chez/dot-forms.ss b/host/chez/dot-forms.ss index dd73774..945f810 100644 --- a/host/chez/dot-forms.ss +++ b/host/chez/dot-forms.ss @@ -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 diff --git a/host/chez/host-static.ss b/host/chez/host-static.ss index a46298b..57a081c 100644 --- a/host/chez/host-static.ss +++ b/host/chez/host-static.ss @@ -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)))) diff --git a/host/chez/loader.ss b/host/chez/loader.ss index 7fb9cb9..b338e2d 100644 --- a/host/chez/loader.ss +++ b/host/chez/loader.ss @@ -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)))))))