From 1d6e7406682eeb0eacb0e8e427cc5f845d957358 Mon Sep 17 00:00:00 2001 From: Yogthos Date: Sat, 20 Jun 2026 17:02:42 -0400 Subject: [PATCH] Chez parity: delay / force / realized? (jolt-cf1q.7) Add a thread-safe delay type (concurrency.ss): make-delay wraps a thunk; deref/ force run it once under a lock and cache (JVM delays are thread-safe + memoized). delay? and realized?-on-a-delay are native; the overlay's `delay` macro (-> make-delay) and `force` (-> deref) now work. realized? wrapper (post-prelude) and the deref chain gain a delay arm. Removed the np-delay? stub from natives-parity.ss (the real type lives in concurrency.ss). Seed unchanged (no re-mint). zero-Janet 2673->2685, 0 new divergences; Janet gate + JVM cert green. jolt-cf1q.7 --- host/chez/concurrency.ss | 24 +++++++++++++++++++++--- host/chez/natives-parity.ss | 5 +---- host/chez/post-prelude.ss | 2 +- test/chez/run-corpus-zero-janet.janet | 6 +++--- 4 files changed, 26 insertions(+), 11 deletions(-) diff --git a/host/chez/concurrency.ss b/host/chez/concurrency.ss index a31de0e..9785e6c 100644 --- a/host/chez/concurrency.ss +++ b/host/chez/concurrency.ss @@ -214,9 +214,23 @@ (jolt-agent-state-set! a new-state) a) +;; --- delay (lazy once-forced computation) ----------------------------------- +;; (delay body) -> (make-delay (fn [] body)) (overlay macro); force/deref run the +;; thunk once under a lock and cache the value (JVM delays are thread-safe). force +;; (overlay) is (if (delay? x) (deref x) x), so it works once delay?/deref do. +(define-record-type jolt-delay (fields thunk (mutable realized?) (mutable value) mu) + (nongenerative jolt-delay-v1)) +(define (jolt-make-delay thunk) (make-jolt-delay thunk #f jolt-nil (make-mutex))) +(define (jolt-delay-force d) + (with-mutex (jolt-delay-mu d) + (unless (jolt-delay-realized? d) + (jolt-delay-value-set! d (jolt-invoke (jolt-delay-thunk d))) + (jolt-delay-realized?-set! d #t))) + (jolt-delay-value d)) + ;; --- deref extension -------------------------------------------------------- ;; Chain the fully-built jolt-deref (atoms/vars/volatiles/reduced) with futures, -;; promises, and agents, and accept the timed (deref ref ms val) arity for the +;; promises, agents, and delays; accept the timed (deref ref ms val) arity for the ;; blocking ref types. (define %pre-conc-deref jolt-deref) (set! jolt-deref @@ -229,13 +243,15 @@ (if (null? opts) (jolt-promise-deref x) (jolt-promise-deref-timed x (car opts) (cadr opts)))) ((jolt-agent? x) (jolt-agent-state x)) + ((jolt-delay? x) (jolt-delay-force x)) (else (apply %pre-conc-deref x opts))))) -;; realized? for a Chez future/promise (the overlay reads Janet map keys). Wrap the -;; overlay version in post-prelude.ss; here just the future/promise predicate. +;; realized? for a Chez future/promise/delay (the overlay reads Janet map keys). +;; Wrapped over the overlay version in post-prelude.ss. (define (jolt-conc-realized? x) (cond ((jolt-future? x) (jolt-future-done? x)) ((jolt-promise? x) (jolt-promise-delivered? x)) + ((jolt-delay? x) (jolt-delay-realized? x)) (else #f))) ;; --- bind into clojure.core ------------------------------------------------- @@ -253,4 +269,6 @@ (def-var! "clojure.core" "await" jolt-agent-await) (def-var! "clojure.core" "agent-error" jolt-agent-error) (def-var! "clojure.core" "restart-agent" jolt-agent-restart) +(def-var! "clojure.core" "make-delay" jolt-make-delay) +(def-var! "clojure.core" "delay?" jolt-delay?) (def-var! "clojure.core" "deref" jolt-deref) diff --git a/host/chez/natives-parity.ss b/host/chez/natives-parity.ss index d95cb3f..f088fa1 100644 --- a/host/chez/natives-parity.ss +++ b/host/chez/natives-parity.ss @@ -62,9 +62,7 @@ (define (np-re-matcher re s) (jolt-hash-map np-kw-type np-kw-mat np-kw-re re np-kw-s s np-kw-pos 0.0)) -;; --- delay? : no delay type is built on Chez yet, so always false (enough for -;; (delay? x) on non-delays; revisit when delay/force land). -(define (np-delay? x) #f) +;; (delay? / make-delay / force live in concurrency.ss with the real delay type.) ;; --- macroexpand-1 / macroexpand: expand a (quoted) call form via the runtime ;; macro table (host-contract hc-macro?/hc-expand-1; forward-referenced, resolved @@ -90,6 +88,5 @@ (def-var! "clojure.core" "__reader-features-set!" np-reader-features-set!) (def-var! "clojure.core" "reader-conditional" np-reader-conditional) (def-var! "clojure.core" "re-matcher" np-re-matcher) -(def-var! "clojure.core" "delay?" np-delay?) (def-var! "clojure.core" "macroexpand-1" np-macroexpand-1) (def-var! "clojure.core" "macroexpand" np-macroexpand) diff --git a/host/chez/post-prelude.ss b/host/chez/post-prelude.ss index fae4a8a..b580a0f 100644 --- a/host/chez/post-prelude.ss +++ b/host/chez/post-prelude.ss @@ -62,6 +62,6 @@ (let ((overlay-realized? (var-deref "clojure.core" "realized?"))) (def-var! "clojure.core" "realized?" (lambda (x) - (if (or (jolt-future? x) (jolt-promise? x)) + (if (or (jolt-future? x) (jolt-promise? x) (jolt-delay? x)) (jolt-conc-realized? x) (jolt-invoke overlay-realized? x))))) diff --git a/test/chez/run-corpus-zero-janet.janet b/test/chez/run-corpus-zero-janet.janet index 69296bc..c0dd21d 100644 --- a/test/chez/run-corpus-zero-janet.janet +++ b/test/chez/run-corpus-zero-janet.janet @@ -214,9 +214,9 @@ # "send/send-off applies" sync-shim cases now match the JVM's async raciness and # are allowlisted) -> 2567. jolt-cf1q.7 parity batches (hash/rseq/cat/transient-as-fn # + ns runtime fns) -> 2600; arrays -> 2631; reader-features/reader-conditional/ -# re-matcher/macroexpand/delay? -> 2642; runtime-defmacro cases via top-level eval -# of ACTUAL (matching certify.clj's eval-isolated) -> 2673. -(def base-floor (scan-number (or (os/getenv "JOLT_CHEZ_ZJ_FLOOR") "2673"))) +# re-matcher/macroexpand -> 2642; runtime-defmacro cases via top-level eval of +# ACTUAL (matching certify.clj's eval-isolated) -> 2673; delay/force/realized? -> 2685. +(def base-floor (scan-number (or (os/getenv "JOLT_CHEZ_ZJ_FLOOR") "2685"))) (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)))