Derive class identity from one hierarchy graph
instance?, extend-protocol dispatch, isa?/supers/ancestors, and the exception hierarchy each read their own hand-kept table, and those tables had drifted: (instance? clojure.lang.Associative [1 2]) was true but a protocol extended to Associative wouldn't dispatch to a vector; keyword/IFn and seq/Seqable had the same split; (isa? ExceptionInfo RuntimeException) was false and (supers NumberFormatException) was empty. Add one FQN -> direct-supers graph (class-hierarchy.ss) and derive the views from it. value-host-tags builds on the graph closure so a vector reports Associative/Indexed/ILookup/Counted/Seqable, a keyword reports IFn, a seq reports Seqable/List/Counted, etc. instance? now tests membership in that same list, so it can't disagree with dispatch. canonical-host-tag recognizes any modeled class (was a separate literal set missing Seqable/ILookup/...). class-direct-supers unions the graph edges and class-supers returns the transitive closure, so the exception hierarchy answers isa?/supers/ancestors. The graph is open: jolt.host/register-class-supers! lets a library graft its own classes on and get every view for free. Runtime only, no re-mint. make test green (0 new/stale divergences), +3 JVM-certified corpus rows.
This commit is contained in:
parent
d7dad2b450
commit
d4acd69a73
5 changed files with 251 additions and 18 deletions
204
host/chez/java/class-hierarchy.ss
Normal file
204
host/chez/java/class-hierarchy.ss
Normal file
|
|
@ -0,0 +1,204 @@
|
|||
;; class-hierarchy.ss — one JVM class/interface graph, the single source of truth
|
||||
;; for every "what classes does this satisfy" question. value-host-tags (protocol
|
||||
;; dispatch), instance?, isa?/supers/ancestors, and the exception hierarchy all
|
||||
;; derive from the ONE table here instead of maintaining parallel hand-kept lists
|
||||
;; that drift apart.
|
||||
;;
|
||||
;; The graph is keyed by canonical (FQN) class name -> its DIRECT super
|
||||
;; interfaces/classes (also FQN). Transitivity is computed (jch-closure), so a row
|
||||
;; lists only what a class directly extends/implements, matching the JVM source.
|
||||
;;
|
||||
;; It is OPEN: a library registers a class and its supers with
|
||||
;; jolt.host/register-class-supers! (plus a class-arm in host-class.ss to map its
|
||||
;; values to that class name), and every derived view picks the class up with no
|
||||
;; core change. Loaded before records.ss so value-host-tags can derive from it.
|
||||
|
||||
;; canonical-name -> list of direct super canonical-names. Mutable + extensible.
|
||||
(define jvm-class-parents (make-hashtable string-hash string=?))
|
||||
;; closure cache, invalidated whenever the graph is extended.
|
||||
(define jch-closure-cache (make-hashtable string-hash string=?))
|
||||
(define jch-tags-cache (make-hashtable string-hash string=?))
|
||||
|
||||
;; Merge direct supers for a class (union with any already registered). Public so
|
||||
;; libraries can graft their own classes onto the modeled hierarchy.
|
||||
(define (jch-register-supers! name supers)
|
||||
(let ((cur (hashtable-ref jvm-class-parents name '())))
|
||||
(hashtable-set! jvm-class-parents name
|
||||
(let add ((ss supers) (acc cur))
|
||||
(cond ((null? ss) acc)
|
||||
((member (car ss) acc) (add (cdr ss) acc))
|
||||
(else (add (cdr ss) (append acc (list (car ss)))))))))
|
||||
(hashtable-clear! jch-closure-cache)
|
||||
(hashtable-clear! jch-tags-cache))
|
||||
|
||||
(define (jch-direct-supers name) (hashtable-ref jvm-class-parents name '()))
|
||||
|
||||
;; transitive supers of NAME (canonical), excluding NAME and Object; Object is the
|
||||
;; universal root supplied by callers. Breadth-first, deduped, stable order.
|
||||
(define (jch-closure name)
|
||||
(or (hashtable-ref jch-closure-cache name #f)
|
||||
(let ((result
|
||||
(let loop ((pending (jch-direct-supers name)) (seen '()))
|
||||
(cond ((null? pending) (reverse seen))
|
||||
((member (car pending) seen) (loop (cdr pending) seen))
|
||||
(else (loop (append (jch-direct-supers (car pending)) (cdr pending))
|
||||
(cons (car pending) seen)))))))
|
||||
(hashtable-set! jch-closure-cache name result)
|
||||
result)))
|
||||
|
||||
(define (jch-last-segment s)
|
||||
(let loop ((i (- (string-length s) 1)))
|
||||
(cond ((< i 0) s)
|
||||
((char=? (string-ref s i) #\.) (substring s (+ i 1) (string-length s)))
|
||||
((char=? (string-ref s i) #\$) (substring s (+ i 1) (string-length s)))
|
||||
(else (loop (- i 1))))))
|
||||
|
||||
;; The protocol-dispatch / instance? tag list for a value of class NAME: the class
|
||||
;; and its whole ancestry, each in BOTH canonical and simple spelling (extend-protocol
|
||||
;; and instance? accept either "Associative" or "clojure.lang.Associative"), plus
|
||||
;; "Object". Memoized — this is on the hot protocol-dispatch path.
|
||||
(define (jch-tags name)
|
||||
(or (hashtable-ref jch-tags-cache name #f)
|
||||
(let* ((chain (cons name (jch-closure name)))
|
||||
(result
|
||||
(let build ((cs chain) (acc '()))
|
||||
(if (null? cs)
|
||||
(reverse (cons "Object" acc))
|
||||
(let* ((fqn (car cs))
|
||||
(simple (jch-last-segment fqn))
|
||||
(acc1 (if (member fqn acc) acc (cons fqn acc)))
|
||||
(acc2 (if (or (string=? simple fqn) (member simple acc1))
|
||||
acc1 (cons simple acc1))))
|
||||
(build (cdr cs) acc2))))))
|
||||
(hashtable-set! jch-tags-cache name result)
|
||||
result)))
|
||||
|
||||
;; Is WANTED (canonical or simple) the class CHILD (canonical) or one of its
|
||||
;; ancestors? Object is every class's root. Matched by full name or last segment so
|
||||
;; "IOException" and "java.io.IOException" both hit.
|
||||
(define (jch-isa? child wanted)
|
||||
(let ((wseg (jch-last-segment wanted)))
|
||||
(or (string=? wanted "java.lang.Object") (string=? wanted "Object")
|
||||
(let loop ((names (cons child (jch-closure child))))
|
||||
(cond ((null? names) #f)
|
||||
((or (string=? wanted (car names))
|
||||
(string=? wseg (jch-last-segment (car names)))) #t)
|
||||
(else (loop (cdr names))))))))
|
||||
|
||||
;; Does the graph model WANTED at all (as a class or as any class's ancestor)? Used
|
||||
;; by instance? to decide between a definitive #f and 'pass (defer to other arms).
|
||||
(define jch-known-cache #f)
|
||||
(define (jch-known? wanted)
|
||||
(when (not jch-known-cache)
|
||||
(set! jch-known-cache (make-hashtable string-hash string=?))
|
||||
(let-values (((keys vals) (hashtable-entries jvm-class-parents)))
|
||||
(vector-for-each
|
||||
(lambda (k supers)
|
||||
(hashtable-set! jch-known-cache k #t)
|
||||
(hashtable-set! jch-known-cache (jch-last-segment k) #t)
|
||||
(for-each (lambda (s)
|
||||
(hashtable-set! jch-known-cache s #t)
|
||||
(hashtable-set! jch-known-cache (jch-last-segment s) #t))
|
||||
supers))
|
||||
keys vals)))
|
||||
(or (hashtable-ref jch-known-cache wanted #f)
|
||||
(hashtable-ref jch-known-cache (jch-last-segment wanted) #f)))
|
||||
|
||||
;; A register also invalidates the known-name cache.
|
||||
(define jch-register-supers!-inner jch-register-supers!)
|
||||
(set! jch-register-supers!
|
||||
(lambda (name supers)
|
||||
(set! jch-known-cache #f)
|
||||
(jch-register-supers!-inner name supers)))
|
||||
|
||||
;; ---- seed the built-in graph: direct supers only, faithful to the JVM ---------
|
||||
;; core clojure.lang interfaces
|
||||
(jch-register-supers! "clojure.lang.IPersistentCollection" '("clojure.lang.Seqable"))
|
||||
(jch-register-supers! "clojure.lang.ISeq" '("clojure.lang.IPersistentCollection"))
|
||||
(jch-register-supers! "clojure.lang.Associative" '("clojure.lang.IPersistentCollection" "clojure.lang.ILookup"))
|
||||
(jch-register-supers! "clojure.lang.IPersistentStack" '("clojure.lang.IPersistentCollection"))
|
||||
(jch-register-supers! "clojure.lang.IPersistentVector" '("clojure.lang.Associative" "clojure.lang.Sequential"
|
||||
"clojure.lang.IPersistentStack" "clojure.lang.Reversible"
|
||||
"clojure.lang.Indexed"))
|
||||
(jch-register-supers! "clojure.lang.IPersistentMap" '("java.lang.Iterable" "clojure.lang.Associative" "clojure.lang.Counted"))
|
||||
(jch-register-supers! "clojure.lang.IPersistentSet" '("clojure.lang.IPersistentCollection" "clojure.lang.Counted"))
|
||||
(jch-register-supers! "clojure.lang.IPersistentList" '("clojure.lang.Sequential" "clojure.lang.IPersistentStack"))
|
||||
(jch-register-supers! "clojure.lang.IObj" '("clojure.lang.IMeta"))
|
||||
(jch-register-supers! "clojure.lang.IFn" '("java.lang.Runnable" "java.util.concurrent.Callable"))
|
||||
(jch-register-supers! "clojure.lang.Fn" '("clojure.lang.IFn"))
|
||||
(jch-register-supers! "clojure.lang.AFn" '("clojure.lang.IFn"))
|
||||
(jch-register-supers! "clojure.lang.AFunction" '("clojure.lang.AFn" "clojure.lang.Fn"))
|
||||
;; java.util collection interfaces
|
||||
(jch-register-supers! "java.util.List" '("java.util.Collection"))
|
||||
(jch-register-supers! "java.util.Set" '("java.util.Collection"))
|
||||
(jch-register-supers! "java.util.Collection" '("java.lang.Iterable"))
|
||||
;; concrete collection classes
|
||||
(jch-register-supers! "clojure.lang.APersistentVector" '("clojure.lang.IPersistentVector" "java.util.List"))
|
||||
(jch-register-supers! "clojure.lang.PersistentVector" '("clojure.lang.APersistentVector" "clojure.lang.IObj"
|
||||
"java.util.List" "java.lang.Comparable"))
|
||||
(jch-register-supers! "clojure.lang.APersistentMap" '("clojure.lang.IPersistentMap" "java.util.Map"))
|
||||
(jch-register-supers! "clojure.lang.PersistentArrayMap" '("clojure.lang.APersistentMap" "clojure.lang.IObj"))
|
||||
(jch-register-supers! "clojure.lang.PersistentHashMap" '("clojure.lang.APersistentMap" "clojure.lang.IObj"))
|
||||
(jch-register-supers! "clojure.lang.PersistentTreeMap" '("clojure.lang.APersistentMap" "clojure.lang.IObj" "clojure.lang.Sorted" "clojure.lang.Reversible"))
|
||||
(jch-register-supers! "clojure.lang.APersistentSet" '("clojure.lang.IPersistentSet" "java.util.Set"))
|
||||
(jch-register-supers! "clojure.lang.PersistentHashSet" '("clojure.lang.APersistentSet" "clojure.lang.IObj"))
|
||||
(jch-register-supers! "clojure.lang.PersistentTreeSet" '("clojure.lang.APersistentSet" "clojure.lang.IObj" "clojure.lang.Sorted" "clojure.lang.Reversible"))
|
||||
(jch-register-supers! "clojure.lang.ASeq" '("clojure.lang.ISeq" "clojure.lang.Sequential" "java.util.List"))
|
||||
(jch-register-supers! "clojure.lang.PersistentList" '("clojure.lang.ASeq" "clojure.lang.IPersistentList" "clojure.lang.Counted"))
|
||||
(jch-register-supers! "clojure.lang.PersistentList$EmptyList" '("clojure.lang.PersistentList"))
|
||||
(jch-register-supers! "clojure.lang.LazySeq" '("clojure.lang.ISeq" "clojure.lang.Sequential" "java.util.List" "clojure.lang.IObj"))
|
||||
(jch-register-supers! "clojure.lang.Cons" '("clojure.lang.ASeq"))
|
||||
(jch-register-supers! "clojure.lang.PersistentQueue" '("clojure.lang.IPersistentList" "clojure.lang.IPersistentCollection" "java.util.Collection"))
|
||||
;; scalars / named / callable
|
||||
(jch-register-supers! "clojure.lang.Keyword" '("clojure.lang.IFn" "clojure.lang.Named" "java.lang.Comparable"))
|
||||
(jch-register-supers! "clojure.lang.Symbol" '("clojure.lang.IObj" "clojure.lang.IFn" "clojure.lang.Named" "java.lang.Comparable"))
|
||||
(jch-register-supers! "clojure.lang.Var" '("clojure.lang.IDeref" "clojure.lang.IFn"))
|
||||
(jch-register-supers! "clojure.lang.Atom" '("clojure.lang.IDeref"))
|
||||
(jch-register-supers! "clojure.lang.Ratio" '("java.lang.Number" "java.lang.Comparable"))
|
||||
(jch-register-supers! "clojure.lang.BigInt" '("java.lang.Number"))
|
||||
(jch-register-supers! "java.lang.String" '("java.lang.CharSequence" "java.lang.Comparable"))
|
||||
(jch-register-supers! "java.lang.Long" '("java.lang.Number" "java.lang.Comparable"))
|
||||
(jch-register-supers! "java.lang.Integer" '("java.lang.Number" "java.lang.Comparable"))
|
||||
(jch-register-supers! "java.lang.Double" '("java.lang.Number" "java.lang.Comparable"))
|
||||
(jch-register-supers! "java.lang.Float" '("java.lang.Number" "java.lang.Comparable"))
|
||||
(jch-register-supers! "java.math.BigDecimal" '("java.lang.Number" "java.lang.Comparable"))
|
||||
(jch-register-supers! "java.math.BigInteger" '("java.lang.Number" "java.lang.Comparable"))
|
||||
(jch-register-supers! "java.lang.Boolean" '("java.lang.Comparable"))
|
||||
(jch-register-supers! "java.lang.Character" '("java.lang.Comparable"))
|
||||
(jch-register-supers! "java.util.UUID" '("java.lang.Comparable"))
|
||||
;; exception hierarchy (folds in the former exception-parent table)
|
||||
(jch-register-supers! "java.lang.Exception" '("java.lang.Throwable"))
|
||||
(jch-register-supers! "java.lang.RuntimeException" '("java.lang.Exception"))
|
||||
(jch-register-supers! "clojure.lang.ExceptionInfo" '("java.lang.RuntimeException" "clojure.lang.IExceptionInfo"))
|
||||
(jch-register-supers! "java.lang.IllegalArgumentException" '("java.lang.RuntimeException"))
|
||||
(jch-register-supers! "clojure.lang.ArityException" '("java.lang.IllegalArgumentException"))
|
||||
(jch-register-supers! "java.lang.NumberFormatException" '("java.lang.IllegalArgumentException"))
|
||||
(jch-register-supers! "java.lang.IllegalStateException" '("java.lang.RuntimeException"))
|
||||
(jch-register-supers! "java.lang.UnsupportedOperationException" '("java.lang.RuntimeException"))
|
||||
(jch-register-supers! "java.lang.ArithmeticException" '("java.lang.RuntimeException"))
|
||||
(jch-register-supers! "java.lang.NullPointerException" '("java.lang.RuntimeException"))
|
||||
(jch-register-supers! "java.lang.ClassCastException" '("java.lang.RuntimeException"))
|
||||
(jch-register-supers! "java.lang.IndexOutOfBoundsException" '("java.lang.RuntimeException"))
|
||||
(jch-register-supers! "java.util.ConcurrentModificationException" '("java.lang.RuntimeException"))
|
||||
(jch-register-supers! "java.util.NoSuchElementException" '("java.lang.RuntimeException"))
|
||||
(jch-register-supers! "java.io.UncheckedIOException" '("java.lang.RuntimeException"))
|
||||
(jch-register-supers! "java.time.DateTimeException" '("java.lang.RuntimeException"))
|
||||
(jch-register-supers! "java.time.format.DateTimeParseException" '("java.time.DateTimeException"))
|
||||
(jch-register-supers! "java.lang.InterruptedException" '("java.lang.Exception"))
|
||||
(jch-register-supers! "java.io.IOException" '("java.lang.Exception"))
|
||||
(jch-register-supers! "java.io.InterruptedIOException" '("java.io.IOException"))
|
||||
(jch-register-supers! "java.io.FileNotFoundException" '("java.io.IOException"))
|
||||
(jch-register-supers! "java.io.UnsupportedEncodingException" '("java.io.IOException"))
|
||||
(jch-register-supers! "java.net.UnknownHostException" '("java.io.IOException"))
|
||||
(jch-register-supers! "java.net.SocketException" '("java.io.IOException"))
|
||||
(jch-register-supers! "java.net.ConnectException" '("java.net.SocketException"))
|
||||
(jch-register-supers! "java.net.SocketTimeoutException" '("java.io.InterruptedIOException"))
|
||||
(jch-register-supers! "java.net.MalformedURLException" '("java.io.IOException"))
|
||||
(jch-register-supers! "javax.net.ssl.SSLException" '("java.io.IOException"))
|
||||
(jch-register-supers! "java.lang.Error" '("java.lang.Throwable"))
|
||||
(jch-register-supers! "java.lang.AssertionError" '("java.lang.Error"))
|
||||
;; Throwable's only super is Object (universal), so no row needed for it.
|
||||
|
||||
;; Public seam: libraries extend the modeled hierarchy.
|
||||
(def-var! "jolt.host" "register-class-supers!"
|
||||
(lambda (name supers) (jch-register-supers! name (seq->list supers)) jolt-nil))
|
||||
|
|
@ -767,6 +767,12 @@
|
|||
(register-instance-check-arm!
|
||||
(lambda (type-sym val)
|
||||
(let ((iface (hsc-last-segment (symbol-t-name type-sym))))
|
||||
;; the value's own class-graph tags (value-host-tags) are authoritative — the
|
||||
;; SAME source protocol dispatch reads, so instance? and extend-protocol can't
|
||||
;; disagree about the interfaces a builtin implements.
|
||||
(if (let ((tags (value-host-tags val)))
|
||||
(or (member (symbol-t-name type-sym) tags) (member iface tags)))
|
||||
#t
|
||||
(let ((hit (cond
|
||||
((or (string=? iface "IObj") (string=? iface "IMeta")) (hsc-imeta? val))
|
||||
((or (string=? iface "IMapEntry") (string=? iface "MapEntry")) (jolt-map-entry? val))
|
||||
|
|
@ -827,7 +833,7 @@
|
|||
((or (string=? iface "Reader") (string=? iface "BufferedReader"))
|
||||
(reader-jhost? val))
|
||||
(else 'none))))
|
||||
(if (eq? hit 'none) 'pass (if hit #t #f))))))
|
||||
(if (eq? hit 'none) 'pass (if hit #t #f)))))))
|
||||
|
||||
;; java.lang.Class value: (class x) / (.getClass x) return one. It renders like
|
||||
;; the JVM — str/.toString -> "class <name>", pr -> "<name>", .getName -> "<name>"
|
||||
|
|
@ -985,9 +991,20 @@
|
|||
(define (str-has-dollar? s)
|
||||
(let loop ((i 0)) (and (< i (string-length s)) (or (char=? (string-ref s i) #\$) (loop (+ i 1))))))
|
||||
(define (class-direct-supers name)
|
||||
(or (hashtable-ref class-supers-tbl name #f)
|
||||
(and (str-has-dollar? name) '("clojure.lang.AFunction"))
|
||||
'()))
|
||||
;; union the modeled class graph (jch, direct edges) with any legacy table entry,
|
||||
;; so isa?/supers/ancestors see the single hierarchy source plus anything not yet
|
||||
;; migrated. The closure below traverses these to the full transitive set.
|
||||
(let ((jch (jch-direct-supers name))
|
||||
(old (hashtable-ref class-supers-tbl name #f)))
|
||||
(cond ((and (pair? jch) old)
|
||||
(let merge ((ss old) (acc jch))
|
||||
(cond ((null? ss) acc)
|
||||
((member (car ss) acc) (merge (cdr ss) acc))
|
||||
(else (merge (cdr ss) (append acc (list (car ss))))))))
|
||||
((pair? jch) jch)
|
||||
(old old)
|
||||
((str-has-dollar? name) '("clojure.lang.AFunction"))
|
||||
(else '()))))
|
||||
;; transitive closure of direct supers (set semantics via an accumulator list)
|
||||
(define (class-ancestors-list name)
|
||||
(let loop ((pending (class-direct-supers name)) (seen '()))
|
||||
|
|
@ -1037,8 +1054,9 @@
|
|||
(def-var! "jolt.host" "class-supers"
|
||||
(lambda (x)
|
||||
(let ((name (class-key x)))
|
||||
(if (and name (hashtable-contains? class-supers-tbl name))
|
||||
(list->cseq (hashtable-ref class-supers-tbl name '()))
|
||||
(if name
|
||||
(let ((as (class-ancestors-list name))) ; transitive, like the JVM
|
||||
(if (null? as) jolt-nil (list->cseq as)))
|
||||
jolt-nil))))
|
||||
(def-var! "jolt.host" "class-ancestors"
|
||||
(lambda (x)
|
||||
|
|
|
|||
|
|
@ -473,24 +473,22 @@
|
|||
((number? obj) '("Long" "Integer" "BigInteger" "BigInt" "Number" "Object"))
|
||||
((string? obj) '("String" "CharSequence" "Object"))
|
||||
((boolean? obj) '("Boolean" "Object"))
|
||||
((keyword? obj) '("Keyword" "Named" "Object"))
|
||||
((jolt-symbol? obj) '("Symbol" "Named" "Object"))
|
||||
((pvec? obj) '("PersistentVector" "APersistentVector" "IPersistentVector" "IPersistentCollection"
|
||||
"List" "java.util.List" "Sequential" "Collection" "Iterable" "java.lang.Iterable" "Object"))
|
||||
((pmap? obj) '("PersistentArrayMap" "APersistentMap" "IPersistentMap" "Associative"
|
||||
"Map" "java.util.Map" "Iterable" "java.lang.Iterable" "Object"))
|
||||
((pset? obj) '("PersistentHashSet" "APersistentSet" "IPersistentSet" "Set" "java.util.Set" "Collection" "Iterable" "java.lang.Iterable" "Object"))
|
||||
((keyword? obj) (jch-tags "clojure.lang.Keyword"))
|
||||
((jolt-symbol? obj) (jch-tags "clojure.lang.Symbol"))
|
||||
((pvec? obj) (jch-tags "clojure.lang.PersistentVector"))
|
||||
((pmap? obj) (jch-tags "clojure.lang.PersistentArrayMap"))
|
||||
((pset? obj) (jch-tags "clojure.lang.PersistentHashSet"))
|
||||
;; jolt models every seq as a list (no distinct LazySeq), so a seq also
|
||||
;; reports PersistentList / IPersistentList / IPersistentStack — extend-protocol
|
||||
;; clojure.lang.IPersistentList (algo.monads' writer monad) dispatches on one.
|
||||
((or (cseq? obj) (empty-list-t? obj)) '("PersistentList" "IPersistentList" "IPersistentStack" "ASeq" "ISeq" "IPersistentCollection" "Sequential" "Collection" "Iterable" "java.lang.Iterable" "Object"))
|
||||
((or (cseq? obj) (empty-list-t? obj)) (jch-tags "clojure.lang.PersistentList"))
|
||||
;; a lazy seq (map/filter/… result) is clojure.lang.LazySeq: a Sequential
|
||||
;; ISeq, but not a PersistentList — matching the JVM so extend-protocol /
|
||||
;; instance? on a deferred seq dispatch like an eager one where they should.
|
||||
((jolt-lazyseq? obj) '("LazySeq" "ISeq" "IPersistentCollection" "Sequential" "Collection" "Iterable" "java.lang.Iterable" "Object"))
|
||||
((jolt-lazyseq? obj) (jch-tags "clojure.lang.LazySeq"))
|
||||
;; a var is clojure.lang.Var (also IDeref / IFn) — reitit's Expand protocol
|
||||
;; extends to Var so a #'handler route dispatches.
|
||||
((var-cell? obj) '("Var" "clojure.lang.Var" "IDeref" "IFn" "Object"))
|
||||
((var-cell? obj) (jch-tags "clojure.lang.Var"))
|
||||
;; java.net.URI jhost — extend-protocol java.net.URI (hiccup ToURI/ToStr).
|
||||
((and (jhost? obj) (string=? (jhost-tag obj) "uri")) '("URI" "java.net.URI" "Object"))
|
||||
;; a ByteBuffer — extend-protocol java.nio.ByteBuffer (aws-api util).
|
||||
|
|
@ -541,7 +539,7 @@
|
|||
;; extended to both (data.json's JSONWriter) routes a sql.Date to its impl.
|
||||
((and (jhost? obj) (string=? (jhost-tag obj) "sql-date")) '("java.sql.Date" "Date" "java.util.Date" "Object"))
|
||||
;; a bare procedure (fn) — extend-protocol to clojure.lang.{Fn,IFn,AFn}.
|
||||
((procedure? obj) '("Fn" "IFn" "AFn" "Object"))
|
||||
((procedure? obj) (jch-tags "clojure.lang.AFunction"))
|
||||
((jolt-nil? obj) '("nil"))
|
||||
;; a defrecord IS the clojure.lang map/record interfaces, so a protocol
|
||||
;; extended to IRecord / IPersistentMap / Associative / Seqable / … (and not
|
||||
|
|
@ -671,7 +669,12 @@
|
|||
(strip-prefix type-name "java.time.")
|
||||
(strip-prefix type-name "clojure.lang.")
|
||||
type-name)))
|
||||
(and (hashtable-ref host-type-set base #f) base)))
|
||||
;; a host class if the literal set lists it OR the class graph models it — both
|
||||
;; feed value-host-tags (which emits the same bare segment), so a protocol
|
||||
;; extended to any modeled class keys under a tag the value reports.
|
||||
(and (or (hashtable-ref host-type-set base #f)
|
||||
(jch-known? base) (jch-known? type-name))
|
||||
base)))
|
||||
;; An extend/extend-type/extend-protocol registration marks the tag as an
|
||||
;; extender of the protocol (recorded inside type-registry so the per-case prune
|
||||
;; restores it). deftype/defrecord inline impls go through register-inline-method
|
||||
|
|
|
|||
|
|
@ -356,6 +356,11 @@
|
|||
;; jolt-pr-str (above), and the var-cell machinery — so loaded last.
|
||||
(load "host/chez/multimethods.ss")
|
||||
|
||||
;; the single JVM class/interface graph — value-host-tags, instance?, isa?/supers,
|
||||
;; and the exception hierarchy all derive from it. Before records.ss so
|
||||
;; value-host-tags can build on jch-tags.
|
||||
(load "host/chez/java/class-hierarchy.ss")
|
||||
|
||||
;; records + protocols: defrecord/deftype/defprotocol/
|
||||
;; extend-type/reify. A jrec record type set!-extended into the collection
|
||||
;; dispatchers + a protocol registry. After multimethods.ss (chez-current-ns) and
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue