diff --git a/host/chez/java/host-class.ss b/host/chez/java/host-class.ss index eceb399..72fb6ca 100644 --- a/host/chez/java/host-class.ss +++ b/host/chez/java/host-class.ss @@ -65,6 +65,19 @@ (def-var! "clojure.core" "class" jolt-class) +;; The PUBLIC clojure.core/type — Clojure's (or (:type meta) (class x)). This is the +;; java host layer's job: the core taxonomy (natives-meta.ss jolt-type, kept under +;; __type-tag for print-method) is JVM-free, and the JVM class mapping lives HERE, +;; next to (class …). The inst/array/byte-buffer host files extend `class` (a +;; class-arm or jolt-type fallthrough) and re-point `type` at this same fn, so the +;; remap of every value — :jolt/inst -> java.util.Date etc. — happens in one place. +(define ty-meta-key (keyword #f "type")) +(define (jolt-type-pub x) + (let* ((m (jolt-meta x)) + (override (if (jolt-nil? m) jolt-nil (jolt-get m ty-meta-key jolt-nil)))) + (if (not (jolt-nil? override)) override (jolt-class x)))) +(def-var! "clojure.core" "type" jolt-type-pub) + ;; bare class-name tokens -> canonical JVM class-name strings. (define class-token-alist '(("String" . "java.lang.String") ("Number" . "java.lang.Number") diff --git a/host/chez/java/inst-time.ss b/host/chez/java/inst-time.ss index c65c743..dfb6752 100644 --- a/host/chez/java/inst-time.ss +++ b/host/chez/java/inst-time.ss @@ -280,6 +280,10 @@ (register-hash-arm! jinst? (lambda (x) (jolt-hash (jinst-ms x)))) +;; #inst is a java.util.Date — (class x) / (type x) report that, not the internal +;; :jolt/inst tag (which print-method still dispatches on via __type-tag). +(register-class-arm! jinst? (lambda (x) "java.util.Date")) + ;; java.time.Instant is nano-precise: two Instants are = when their epoch-nanos ;; match (so an Instant and one shifted by a single nanosecond differ). (define (jt-instant-tag? x) (and (jhost? x) (string=? (jhost-tag x) "instant"))) @@ -303,7 +307,6 @@ (define %it-type jolt-type) (set! jolt-type (lambda (x) (if (jinst? x) inst-type-kw (%it-type x)))) -(def-var! "clojure.core" "type" jolt-type) ;; instance? java.util.Date -> a jinst; java.time.Instant/LocalDateTime -> the ;; matching jhost tag. The instance? macro passes the class-name symbol. diff --git a/host/chez/java/io.ss b/host/chez/java/io.ss index d30a695..5b319c7 100644 --- a/host/chez/java/io.ss +++ b/host/chez/java/io.ss @@ -319,7 +319,6 @@ (define io-kw-file (keyword "jolt" "file")) (define %io-type jolt-type) (set! jolt-type (lambda (x) (if (jfile? x) io-kw-file (%io-type x)))) -(def-var! "clojure.core" "type" jolt-type) ;; (instance? java.io.File f): the instance? macro passes the class-name symbol; ;; match "File" / "java.io.File" (and any *.File) against a jfile. diff --git a/host/chez/java/natives-array.ss b/host/chez/java/natives-array.ss index de130fb..403639a 100644 --- a/host/chez/java/natives-array.ss +++ b/host/chez/java/natives-array.ss @@ -156,7 +156,6 @@ ;; (jolt-type …) for arrays, so extending jolt-type covers both. (define %na-type jolt-type) (set! jolt-type (lambda (x) (if (jolt-array? x) (na-array-class-name x) (%na-type x)))) -(def-var! "clojure.core" "type" jolt-type) ;; instance? over an array class token ([I, [C, …). An array token reaches us as ;; a string ("[C", from (Class/forName "[C")) — the dispatcher leaves it a string diff --git a/host/chez/natives-meta.ss b/host/chez/natives-meta.ss index d9a1bdb..45fbab1 100644 --- a/host/chez/natives-meta.ss +++ b/host/chez/natives-meta.ss @@ -132,4 +132,10 @@ ((procedure? x) ty-fn) (else ty-object)))) +;; jolt-type is the keyword TAXONOMY (:string/:set/:jolt/inst/…) — jolt's native +;; value model, with no JVM in it. print-method/print-dup dispatch on it (via +;; __type-tag). The PUBLIC clojure.core/type is Clojure's (or (:type meta) (class +;; x)) — a JVM class — but that mapping belongs to the java host layer (host-class.ss +;; rebinds `type` next to `class`), so this core layer stays JVM-free. +(def-var! "clojure.core" "__type-tag" jolt-type) (def-var! "clojure.core" "type" jolt-type) diff --git a/host/chez/seed/prelude.ss b/host/chez/seed/prelude.ss index cf2d9b9..bf61667 100644 --- a/host/chez/seed/prelude.ss +++ b/host/chez/seed/prelude.ss @@ -967,11 +967,11 @@ (guard (e (#t #f)) (def-var-with-meta! "clojure.core" "line-seq" (letrec ((line-seq (lambda (rdr) (let fnrec2450 ((rdr rdr)) (if (jolt-truthy? (jolt-invoke (var-deref "clojure.core" "string?") rdr)) (jolt-seq (jolt-invoke (var-deref "clojure.core" "str-split") "\n" rdr)) (jolt-invoke (var-deref "clojure.core" "make-lazy-seq") (lambda () (let fnrec2451 () (jolt-invoke (var-deref "clojure.core" "coll->cells") (let* ((line (jolt-invoke (var-deref "clojure.core" "-read-line") rdr))) (if (jolt-truthy? line) (jolt-cons line (line-seq rdr)) jolt-nil))))))))))) line-seq) (let* ((_o$2452 (keyword #f "doc")) (_o$2453 "Returns the lines of text from rdr as a lazy sequence of strings, as by\n read-line. (Jolt extension kept from the old kernel stub: a plain string\n splits into its lines.)")) (jolt-hash-map _o$2452 _o$2453)))) (guard (e (#t #f)) - (jolt-invoke (var-deref "clojure.core" "defmulti-setup") (jolt-symbol #f "print-method") (lambda (x writer) (let fnrec2454 ((x x) (writer writer)) (let* ((t (jolt-get (jolt-invoke (var-deref "clojure.core" "meta") x) (keyword #f "type")))) (if (jolt-truthy? (jolt-invoke (var-deref "clojure.core" "keyword?") t)) t (jolt-invoke (var-deref "clojure.core" "type") x))))))) + (jolt-invoke (var-deref "clojure.core" "defmulti-setup") (jolt-symbol #f "print-method") (lambda (x writer) (let fnrec2454 ((x x) (writer writer)) (let* ((t (jolt-get (jolt-invoke (var-deref "clojure.core" "meta") x) (keyword #f "type")))) (if (jolt-truthy? (jolt-invoke (var-deref "clojure.core" "keyword?") t)) t (jolt-invoke (var-deref "clojure.core" "__type-tag") x))))))) (guard (e (#t #f)) (jolt-invoke (var-deref "clojure.core" "defmethod-setup") (jolt-symbol #f "print-method") (keyword #f "default") (lambda (o w) (let fnrec2455 ((o o) (w w)) (begin (record-method-dispatch w "write" (jolt-vector (jolt-invoke (var-deref "clojure.core" "__pr-str1") o))) jolt-nil))))) (guard (e (#t #f)) - (jolt-invoke (var-deref "clojure.core" "defmulti-setup") (jolt-symbol #f "print-dup") (lambda (x writer) (let fnrec2456 ((x x) (writer writer)) (let* ((t (jolt-get (jolt-invoke (var-deref "clojure.core" "meta") x) (keyword #f "type")))) (if (jolt-truthy? (jolt-invoke (var-deref "clojure.core" "keyword?") t)) t (jolt-invoke (var-deref "clojure.core" "type") x))))))) + (jolt-invoke (var-deref "clojure.core" "defmulti-setup") (jolt-symbol #f "print-dup") (lambda (x writer) (let fnrec2456 ((x x) (writer writer)) (let* ((t (jolt-get (jolt-invoke (var-deref "clojure.core" "meta") x) (keyword #f "type")))) (if (jolt-truthy? (jolt-invoke (var-deref "clojure.core" "keyword?") t)) t (jolt-invoke (var-deref "clojure.core" "__type-tag") x))))))) (guard (e (#t #f)) (jolt-invoke (var-deref "clojure.core" "defmethod-setup") (jolt-symbol #f "print-dup") (keyword #f "default") (lambda (o w) (let fnrec2457 ((o o) (w w)) (jolt-invoke (var-deref "clojure.core" "print-method") o w))))) (guard (e (#t #f)) diff --git a/jolt-core/clojure/core/50-io.clj b/jolt-core/clojure/core/50-io.clj index d4941c9..2d80196 100644 --- a/jolt-core/clojure/core/50-io.clj +++ b/jolt-core/clojure/core/50-io.clj @@ -150,7 +150,7 @@ ;; documented jolt divergence). (defmulti print-method (fn [x writer] (let [t (get (meta x) :type)] - (if (keyword? t) t (type x))))) + (if (keyword? t) t (__type-tag x))))) (defmethod print-method :default [o w] (.write w (__pr-str1 o)) @@ -160,7 +160,7 @@ ;; (as Clojure's default does for most types). (defmulti print-dup (fn [x writer] (let [t (get (meta x) :type)] - (if (keyword? t) t (type x))))) + (if (keyword? t) t (__type-tag x))))) (defmethod print-dup :default [o w] (print-method o w)) diff --git a/test/chez/unit.edn b/test/chez/unit.edn index 2a08a09..cb1a1ec 100644 --- a/test/chez/unit.edn +++ b/test/chez/unit.edn @@ -67,7 +67,7 @@ {:suite "exinfo" :expr "(instance? RuntimeException (InterruptedException. \"x\"))" :expected "false"} {:suite "exinfo" :expr "(.getMessage (RuntimeException. \"boom\"))" :expected "boom"} {:suite "exinfo" :expr "(ex-message (RuntimeException. \"boom\"))" :expected "boom"} - {:suite "exinfo" :expr "(type (ex-info \"x\" {}))" :expected ":jolt/ex-info"} + {:suite "exinfo" :expr "(type (ex-info \"x\" {}))" :expected "clojure.lang.ExceptionInfo"} {:suite "hostobj" :expr "(.getName (.getClass \"x\"))" :expected "java.lang.String"} {:suite "hostobj" :expr "(.getClass 5)" :expected "java.lang.Long"} {:suite "hostobj" :expr "(.getSimpleName (.getClass :k))" :expected "Keyword"} @@ -164,7 +164,7 @@ {:suite "insttime" :expr "(inst-ms #inst \"2020-01-01T00:00:00Z\")" :expected "1577836800000"} {:suite "insttime" :expr "(inst-ms* #inst \"1970-01-01T00:00:00Z\")" :expected "0"} {:suite "insttime" :expr "(some? #inst \"2020-01-01T00:00:00Z\")" :expected "true"} - {:suite "insttime" :expr "(str (type #inst \"2020-01-01T00:00:00Z\"))" :expected ":jolt/inst"} + {:suite "insttime" :expr "(str (type #inst \"2020-01-01T00:00:00Z\"))" :expected "class java.util.Date"} {:suite "insttime" :expr "(= #inst \"2020\" #inst \"2020-01-01T00:00:00.000Z\")" :expected "true"} {:suite "insttime" :expr "(= #inst \"2020-03\" #inst \"2020-03-01T00:00:00Z\")" :expected "true"} {:suite "insttime" :expr "(= #inst \"2020-03-15\" #inst \"2020-03-15T00:00:00Z\")" :expected "true"} @@ -200,7 +200,7 @@ {:suite "io" :expr "(do (require (quote [clojure.java.io :as io])) (.exists (io/file \"README.md\")))" :expected "true"} {:suite "io" :expr "(do (require (quote [clojure.java.io :as io])) (instance? java.io.File (io/file \"/a/b\")))" :expected "true"} {:suite "io" :expr "(do (require (quote [clojure.java.io :as io])) (instance? java.io.File \"/a/b\"))" :expected "false"} - {:suite "io" :expr "(do (require (quote [clojure.java.io :as io])) (str (type (io/file \"/a\"))))" :expected ":jolt/file"} + {:suite "io" :expr "(do (require (quote [clojure.java.io :as io])) (str (type (io/file \"/a\"))))" :expected "class java.io.File"} {:suite "io" :expr "(do (require (quote [clojure.java.io :as io])) (every? (fn [f] (instance? java.io.File f)) (file-seq (io/file \"docs\"))))" :expected "true"} {:suite "io" :expr "(do (require (quote [clojure.java.io :as io])) (pos? (count (filter (fn [f] (.isFile f)) (file-seq (io/file \"docs\"))))))" :expected "true"} {:suite "io" :expr "(do (require (quote [clojure.string :as s])) (boolean (some (fn [p] (s/ends-with? p \"README.md\")) (file-seq \".\"))))" :expected "true"} @@ -458,43 +458,43 @@ {:suite "strns" :expr "(do (require (quote [clojure.string :as s])) (s/index-of \"abc\" \"b\"))" :expected "1"} {:suite "strns" :expr "(do (require (quote [clojure.string :as s])) (nil? (s/index-of \"abc\" \"z\")))" :expected "true"} {:suite "strns" :expr "(do (require (quote [clojure.string :as s])) (s/trim-newline \"abc\\n\\n\"))" :expected "abc"} - {:suite "type" :expr "(type 5)" :expected ":number"} - {:suite "type" :expr "(type 5.0)" :expected ":number"} - {:suite "type" :expr "(type (/ 10 2))" :expected ":number"} - {:suite "type" :expr "(type \"s\")" :expected ":string"} - {:suite "type" :expr "(type :k)" :expected ":keyword"} - {:suite "type" :expr "(type 'x)" :expected ":symbol"} - {:suite "type" :expr "(type true)" :expected ":boolean"} - {:suite "type" :expr "(type false)" :expected ":boolean"} + {:suite "type" :expr "(type 5)" :expected "java.lang.Long"} + {:suite "type" :expr "(type 5.0)" :expected "java.lang.Double"} + {:suite "type" :expr "(type (/ 10 2))" :expected "java.lang.Long"} + {:suite "type" :expr "(type \"s\")" :expected "java.lang.String"} + {:suite "type" :expr "(type :k)" :expected "clojure.lang.Keyword"} + {:suite "type" :expr "(type 'x)" :expected "clojure.lang.Symbol"} + {:suite "type" :expr "(type true)" :expected "java.lang.Boolean"} + {:suite "type" :expr "(type false)" :expected "java.lang.Boolean"} {:suite "type" :expr "(type nil)" :expected ""} - {:suite "type" :expr "(type \\a)" :expected ":char"} - {:suite "type" :expr "(type [1 2])" :expected ":vector"} - {:suite "type" :expr "(type [])" :expected ":vector"} - {:suite "type" :expr "(type {:a 1})" :expected ":map"} - {:suite "type" :expr "(type #{1})" :expected ":set"} - {:suite "type" :expr "(type '(1 2))" :expected ":seq"} - {:suite "type" :expr "(type '())" :expected ":seq"} - {:suite "type" :expr "(type (first {:a 1}))" :expected ":vector"} - {:suite "type" :expr "(type (map inc [1 2]))" :expected ":seq"} - {:suite "type" :expr "(type (filter odd? [1 2 3]))" :expected ":seq"} - {:suite "type" :expr "(type (lazy-seq (cons 1 nil)))" :expected ":seq"} - {:suite "type" :expr "(type (take 2 (iterate inc 0)))" :expected ":seq"} - {:suite "type" :expr "(type inc)" :expected ":fn"} + {:suite "type" :expr "(type \\a)" :expected "java.lang.Character"} + {:suite "type" :expr "(type [1 2])" :expected "clojure.lang.PersistentVector"} + {:suite "type" :expr "(type [])" :expected "clojure.lang.PersistentVector"} + {:suite "type" :expr "(type {:a 1})" :expected "clojure.lang.PersistentArrayMap"} + {:suite "type" :expr "(type #{1})" :expected "clojure.lang.PersistentHashSet"} + {:suite "type" :expr "(type '(1 2))" :expected "clojure.lang.PersistentList"} + {:suite "type" :expr "(type '())" :expected "clojure.lang.PersistentList$EmptyList"} + {:suite "type" :expr "(type (first {:a 1}))" :expected "clojure.lang.PersistentVector"} + {:suite "type" :expr "(type (map inc [1 2]))" :expected "clojure.lang.PersistentList"} + {:suite "type" :expr "(type (filter odd? [1 2 3]))" :expected "clojure.lang.PersistentList"} + {:suite "type" :expr "(type (lazy-seq (cons 1 nil)))" :expected "clojure.lang.LazySeq"} + {:suite "type" :expr "(type (take 2 (iterate inc 0)))" :expected "clojure.lang.PersistentList"} + {:suite "type" :expr "(type inc)" :expected "clojure.lang.IFn"} {:suite "type" :expr "(type (sorted-map :a 1))" :expected ":map"} {:suite "type" :expr "(type (sorted-set 1))" :expected ":jolt/sorted-set"} {:suite "type" :expr "(type (with-meta [1] {:type :custom}))" :expected ":custom"} {:suite "type" :expr "(type (with-meta {:a 1} {:type :rec}))" :expected ":rec"} - {:suite "type" :expr "(type (with-meta [1] {:other 9}))" :expected ":vector"} + {:suite "type" :expr "(type (with-meta [1] {:other 9}))" :expected "clojure.lang.PersistentVector"} {:suite "type" :expr "(do (defrecord TyR [a]) (type (->TyR 1)))" :expected "user.TyR"} {:suite "type" :expr "(do (defrecord TyR [a]) (= (symbol (str (type (->TyR 1)))) (type (->TyR 1))))" :expected "false"} {:suite "type" :expr "(do (defrecord TyR [a]) (symbol? (type (->TyR 1))))" :expected "false"} - {:suite "type" :expr "(type (atom 1))" :expected ":jolt/atom"} + {:suite "type" :expr "(type (atom 1))" :expected "clojure.lang.Atom"} {:suite "type" :expr "(type (volatile! 1))" :expected ":jolt/volatile"} - {:suite "type" :expr "(type #\"re\")" :expected ":jolt/regex"} + {:suite "type" :expr "(type #\"re\")" :expected "java.util.regex.Pattern"} {:suite "type" :expr "(do (def vx 1) (type (var vx)))" :expected ":jolt/var"} {:suite "type" :expr "(type (transient []))" :expected ":jolt/transient"} - {:suite "type" :expr "(type (random-uuid))" :expected ":jolt/uuid"} - {:suite "type" :expr "(type (ex-info \"x\" {}))" :expected ":jolt/ex-info"} + {:suite "type" :expr "(type (random-uuid))" :expected "java.util.UUID"} + {:suite "type" :expr "(type (ex-info \"x\" {}))" :expected "clojure.lang.ExceptionInfo"} {:suite "var_meta" :expr "(do (def ^:private pv 1) (:private (meta (var pv))))" :expected "true"} {:suite "var_meta" :expr "(do (def ^String tv \"a\") (:tag (meta (var tv))))" :expected "java.lang.String"} {:suite "var_meta" :expr "(do (def dv2 \"hi\" 1) (:doc (meta (var dv2))))" :expected "hi"}