From 01f49f50c3ee744aada7ac166fa3f39fb9be333e Mon Sep 17 00:00:00 2001 From: Yogthos Date: Sat, 20 Jun 2026 18:03:58 -0400 Subject: [PATCH] Chez parity: date/time + clojure.edn/read over a reader (jolt-cf1q.7/dcmm/7t3l/uicd) Date/time (inst-time.ss): java.util.Date / java.sql.Timestamp ctors accept ms or another date value (ms-of) -> a jinst; java.text.SimpleDateFormat (pattern + .format via the existing format-ms UTC engine; .setTimeZone accepted); java.util.TimeZone/ getTimeZone. instance? answers Date true / Timestamp false for a jinst (a Date is not a Timestamp on the JVM). clojure.edn/read over a reader (io.ss + post-prelude): the overlay edn.clj's drain-reader is janet/type-coupled, so Chez drains the jhost StringReader/ PushbackReader to a string and reads the first EDN form. Unblocks jolt-uicd. Native Chez throughout (no vendoring): Chez date arithmetic + string ports. zero-Janet 2688->2692, 0 new divergences; self-host + Janet gate + JVM cert green. jolt-cf1q.7 jolt-dcmm jolt-7t3l jolt-uicd --- host/chez/inst-time.ss | 34 +++++++++++++++++++++++---- host/chez/io.ss | 7 ++++++ host/chez/post-prelude.ss | 6 +++++ test/chez/run-corpus-zero-janet.janet | 6 +++-- 4 files changed, 46 insertions(+), 7 deletions(-) diff --git a/host/chez/inst-time.ss b/host/chez/inst-time.ss index 658939a..8c554f4 100644 --- a/host/chez/inst-time.ss +++ b/host/chez/inst-time.ss @@ -198,7 +198,11 @@ (lambda (type-sym val) (let ((tn (class-short (symbol-t-name type-sym)))) (cond - ((jinst? val) (if (string=? tn "Date") #t (%it-instance-check type-sym val))) + ;; a #inst / (Date.) is a java.util.Date; it is NOT a java.sql.Timestamp + ;; (on the JVM a Date is not a Timestamp), so answer Timestamp explicitly #f. + ((jinst? val) (cond ((string=? tn "Date") #t) + ((string=? tn "Timestamp") #f) + (else (%it-instance-check type-sym val)))) ((and (jhost? val) (string=? (jhost-tag val) "instant")) (if (string=? tn "Instant") #t (%it-instance-check type-sym val))) ((and (jhost? val) (string=? (jhost-tag val) "local-dt")) (if (string=? tn "LocalDateTime") #t (%it-instance-check type-sym val))) (else (%it-instance-check type-sym val)))))) @@ -275,10 +279,30 @@ (cons "US" (make-jhost "locale" (vector "en-US"))) (cons "ROOT" (make-jhost "locale" (vector "root"))))) -;; java.util.Date: #inst's class. (Date. ms) and the no-arg now form -> a jinst, -;; so .getTime / inst? / instance? Date work; ctor + .getTime mirror host_io.janet. -(register-class-ctor! "Date" (lambda args (make-jinst (if (null? args) (now-ms) (exact->inexact (car args)))))) -(register-class-ctor! "java.util.Date" (lambda args (make-jinst (if (null? args) (now-ms) (exact->inexact (car args)))))) +;; java.util.Date / java.sql.Timestamp: #inst's classes. (Date.) = now, (Date. ms) +;; or (Date. another-date) -> a jinst (ms-of accepts a number / jinst / instant), so +;; .getTime / inst? / instance? Date|Timestamp work. (jolt-dcmm) +(define (date-ctor . args) + (make-jinst (if (null? args) (now-ms) (exact->inexact (ms-of (car args)))))) +(register-class-ctor! "Date" date-ctor) +(register-class-ctor! "java.util.Date" date-ctor) +(register-class-ctor! "Timestamp" date-ctor) +(register-class-ctor! "java.sql.Timestamp" date-ctor) + +;; java.util.TimeZone: an opaque id holder (format-ms is UTC, so a non-UTC zone is +;; not honored — only the UTC case the corpus uses is exercised). +(define (timezone-of id) (make-jhost "timezone" (vector (if (string? id) id (jolt-str-render-one id))))) +(register-class-statics! "TimeZone" (list (cons "getTimeZone" timezone-of))) +(register-class-statics! "java.util.TimeZone" (list (cons "getTimeZone" timezone-of))) + +;; java.text.SimpleDateFormat: holds a pattern; .setTimeZone is accepted (format-ms +;; is UTC); .format(date) renders the date per the pattern via the format-ms engine. +(define (sdf-ctor pat . _) (make-jhost "sdf" (vector (if (string? pat) pat (jolt-str-render-one pat))))) +(register-class-ctor! "SimpleDateFormat" sdf-ctor) +(register-class-ctor! "java.text.SimpleDateFormat" sdf-ctor) +(register-host-methods! "sdf" + (list (cons "setTimeZone" (lambda (self tz) jolt-nil)) + (cons "format" (lambda (self d) (format-ms (vector-ref (jhost-state self) 0) (ms-of d)))))) ;; a jinst's java.util.Date method surface (record-method-dispatch arm). (define %it-rmd record-method-dispatch) diff --git a/host/chez/io.ss b/host/chez/io.ss index b5bed88..72af1fd 100644 --- a/host/chez/io.ss +++ b/host/chez/io.ss @@ -121,6 +121,13 @@ (define (reader-jhost? x) (and (jhost? x) (member (jhost-tag x) '("string-reader" "pushback-reader")))) +;; clojure.edn/read over a reader (jolt-uicd): the overlay edn.clj's drain-reader is +;; janet/type-coupled, so on Chez we drain the jhost reader to a string and read the +;; first EDN form (read-string). Re-asserted over the prelude in post-prelude.ss. +(define (chez-edn-read reader) + (jolt-invoke (var-deref "clojure.core" "read-string") + (if (reader-jhost? reader) (drain-reader reader) (jolt-str-render-one reader)))) + (define (jolt-slurp src . opts) (cond ((jfile? src) (read-file-string (jfile-path src))) diff --git a/host/chez/post-prelude.ss b/host/chez/post-prelude.ss index b580a0f..59db040 100644 --- a/host/chez/post-prelude.ss +++ b/host/chez/post-prelude.ss @@ -65,3 +65,9 @@ (if (or (jolt-future? x) (jolt-promise? x) (jolt-delay? x)) (jolt-conc-realized? x) (jolt-invoke overlay-realized? x))))) +;; clojure.edn/read over a reader: the overlay edn.clj drain-reader uses janet/type; +;; the native Chez version (io.ss) drains the jhost reader instead (jolt-uicd/jolt-7t3l). +(def-var! "clojure.edn" "read" + (case-lambda + ((reader) (chez-edn-read reader)) + ((opts reader) (chez-edn-read reader)))) diff --git a/test/chez/run-corpus-zero-janet.janet b/test/chez/run-corpus-zero-janet.janet index 80fa538..4e85574 100644 --- a/test/chez/run-corpus-zero-janet.janet +++ b/test/chez/run-corpus-zero-janet.janet @@ -216,8 +216,10 @@ # + ns runtime fns) -> 2600; arrays -> 2631; reader-features/reader-conditional/ # re-matcher/macroexpand -> 2642; runtime-defmacro cases via top-level eval of # ACTUAL (matching certify.clj's eval-isolated) -> 2673; delay/force/realized? -> -# 2685; deftype (P. args) constructor via host-new var fallback -> 2688. -(def base-floor (scan-number (or (os/getenv "JOLT_CHEZ_ZJ_FLOOR") "2688"))) +# 2685; deftype (P. args) constructor via host-new var fallback -> 2688; +# date/time (Date/Timestamp/SimpleDateFormat/TimeZone) + clojure.edn/read over a +# reader -> 2692. +(def base-floor (scan-number (or (os/getenv "JOLT_CHEZ_ZJ_FLOOR") "2692"))) (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)))