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
This commit is contained in:
Yogthos 2026-06-20 18:03:58 -04:00
parent 60b4bae105
commit 01f49f50c3
4 changed files with 46 additions and 7 deletions

View file

@ -198,7 +198,11 @@
(lambda (type-sym val) (lambda (type-sym val)
(let ((tn (class-short (symbol-t-name type-sym)))) (let ((tn (class-short (symbol-t-name type-sym))))
(cond (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) "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))) ((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)))))) (else (%it-instance-check type-sym val))))))
@ -275,10 +279,30 @@
(cons "US" (make-jhost "locale" (vector "en-US"))) (cons "US" (make-jhost "locale" (vector "en-US")))
(cons "ROOT" (make-jhost "locale" (vector "root"))))) (cons "ROOT" (make-jhost "locale" (vector "root")))))
;; java.util.Date: #inst's class. (Date. ms) and the no-arg now form -> a jinst, ;; java.util.Date / java.sql.Timestamp: #inst's classes. (Date.) = now, (Date. ms)
;; so .getTime / inst? / instance? Date work; ctor + .getTime mirror host_io.janet. ;; or (Date. another-date) -> a jinst (ms-of accepts a number / jinst / instant), so
(register-class-ctor! "Date" (lambda args (make-jinst (if (null? args) (now-ms) (exact->inexact (car args)))))) ;; .getTime / inst? / instance? Date|Timestamp work. (jolt-dcmm)
(register-class-ctor! "java.util.Date" (lambda args (make-jinst (if (null? args) (now-ms) (exact->inexact (car args)))))) (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). ;; a jinst's java.util.Date method surface (record-method-dispatch arm).
(define %it-rmd record-method-dispatch) (define %it-rmd record-method-dispatch)

View file

@ -121,6 +121,13 @@
(define (reader-jhost? x) (define (reader-jhost? x)
(and (jhost? x) (member (jhost-tag x) '("string-reader" "pushback-reader")))) (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) (define (jolt-slurp src . opts)
(cond (cond
((jfile? src) (read-file-string (jfile-path src))) ((jfile? src) (read-file-string (jfile-path src)))

View file

@ -65,3 +65,9 @@
(if (or (jolt-future? x) (jolt-promise? x) (jolt-delay? x)) (if (or (jolt-future? x) (jolt-promise? x) (jolt-delay? x))
(jolt-conc-realized? x) (jolt-conc-realized? x)
(jolt-invoke overlay-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))))

View file

@ -216,8 +216,10 @@
# + ns runtime fns) -> 2600; arrays -> 2631; reader-features/reader-conditional/ # + ns runtime fns) -> 2600; arrays -> 2631; reader-features/reader-conditional/
# re-matcher/macroexpand -> 2642; runtime-defmacro cases via top-level eval of # re-matcher/macroexpand -> 2642; runtime-defmacro cases via top-level eval of
# ACTUAL (matching certify.clj's eval-isolated) -> 2673; delay/force/realized? -> # ACTUAL (matching certify.clj's eval-isolated) -> 2673; delay/force/realized? ->
# 2685; deftype (P. args) constructor via host-new var fallback -> 2688. # 2685; deftype (P. args) constructor via host-new var fallback -> 2688;
(def base-floor (scan-number (or (os/getenv "JOLT_CHEZ_ZJ_FLOOR") "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)) (def floor (if (os/getenv "JOLT_CORPUS_LIMIT") 0 base-floor))
(when (or (> (length diverged) 0) (< pass floor)) (when (or (> (length diverged) 0) (< pass floor))
(printf "REGRESSION: pass %d < floor %d or %d new divergence(s)" pass floor (length diverged))) (printf "REGRESSION: pass %d < floor %d or %d new divergence(s)" pass floor (length diverged)))