Skip to content

Commit f033bc3

Browse files
committed
CLJS-3464: parents does not walk JavaScript prototype chain
- implement `bases` return immediate prototype of arg - implement `supers` returns immediate and indirect protoypes of arg - fix hierarchy code to use js-fn? where Clojure used class - add assertions to derive - uncomment some test assertions
1 parent 5a26a08 commit f033bc3

File tree

2 files changed

+53
-21
lines changed

2 files changed

+53
-21
lines changed

src/main/cljs/cljs/core.cljs

Lines changed: 50 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -11262,6 +11262,23 @@ reduces them without incurring seq initialization"
1126211262
(defn- swap-global-hierarchy! [f & args]
1126311263
(apply swap! (get-global-hierarchy) f args))
1126411264

11265+
(defn bases
11266+
"Returns the immediate prototype of c"
11267+
[c]
11268+
(when c
11269+
(let [s (.getPrototypeOf js/Object c)]
11270+
(when s
11271+
(list s)))))
11272+
11273+
(defn supers
11274+
"Returns the immediate and indirect prototypes of c, if any"
11275+
[c]
11276+
(loop [ret (set (bases c)) cs ret]
11277+
(if (seq cs)
11278+
(let [c (first cs) bs (bases c)]
11279+
(recur (into ret bs) (into (disj cs c) bs)))
11280+
(not-empty ret))))
11281+
1126511282
(defn ^boolean isa?
1126611283
"Returns true if (= child parent), or child is directly or indirectly derived from
1126711284
parent, either via a JavaScript type inheritance relationship or a
@@ -11270,33 +11287,46 @@ reduces them without incurring seq initialization"
1127011287
hierarchy"
1127111288
([child parent] (isa? @(get-global-hierarchy) child parent))
1127211289
([h child parent]
11273-
(or (= child parent)
11274-
;; (and (class? parent) (class? child)
11275-
;; (. ^Class parent isAssignableFrom child))
11276-
(contains? ((:ancestors h) child) parent)
11277-
;;(and (class? child) (some #(contains? ((:ancestors h) %) parent) (supers child)))
11278-
(and (vector? parent) (vector? child)
11279-
(== (count parent) (count child))
11280-
(loop [ret true i 0]
11281-
(if (or (not ret) (== i (count parent)))
11282-
ret
11283-
(recur (isa? h (child i) (parent i)) (inc i))))))))
11290+
(or (= child parent)
11291+
(and (js-fn? parent) (js-fn? child)
11292+
(instance? parent child))
11293+
(contains? ((:ancestors h) child) parent)
11294+
(and (js-fn? child) (some #(contains? ((:ancestors h) %) parent) (supers child)))
11295+
(and (vector? parent) (vector? child)
11296+
(== (count parent) (count child))
11297+
(loop [ret true i 0]
11298+
(if (or (not ret) (== i (count parent)))
11299+
ret
11300+
(recur (isa? h (child i) (parent i)) (inc i))))))))
1128411301

1128511302
(defn parents
1128611303
"Returns the immediate parents of tag, either via a JavaScript type
1128711304
inheritance relationship or a relationship established via derive. h
1128811305
must be a hierarchy obtained from make-hierarchy, if not supplied
1128911306
defaults to the global hierarchy"
1129011307
([tag] (parents @(get-global-hierarchy) tag))
11291-
([h tag] (not-empty (get (:parents h) tag))))
11308+
([h tag]
11309+
(not-empty
11310+
(let [tp (get (:parents h) tag)]
11311+
(if (js-fn? tag)
11312+
(into (set (bases tag)) tp)
11313+
tp)))))
1129211314

1129311315
(defn ancestors
1129411316
"Returns the immediate and indirect parents of tag, either via a JavaScript type
1129511317
inheritance relationship or a relationship established via derive. h
1129611318
must be a hierarchy obtained from make-hierarchy, if not supplied
1129711319
defaults to the global hierarchy"
1129811320
([tag] (ancestors @(get-global-hierarchy) tag))
11299-
([h tag] (not-empty (get (:ancestors h) tag))))
11321+
([h tag]
11322+
(not-empty
11323+
(let [ta (get (:ancestors h) tag)]
11324+
(if (js-fn? tag)
11325+
(let [superclasses (set (supers tag))]
11326+
(reduce into superclasses
11327+
(cons ta
11328+
(map #(get (:ancestors h) %) superclasses))))
11329+
ta)))))
1130011330

1130111331
(defn descendants
1130211332
"Returns the immediate and indirect children of tag, through a
@@ -11305,7 +11335,10 @@ reduces them without incurring seq initialization"
1130511335
hierarchy. Note: does not work on JavaScript type inheritance
1130611336
relationships."
1130711337
([tag] (descendants @(get-global-hierarchy) tag))
11308-
([h tag] (not-empty (get (:descendants h) tag))))
11338+
([h tag]
11339+
(if (js-fn? tag)
11340+
(throw (js/Error. "Can't get descendants of constructors"))
11341+
(not-empty (get (:descendants h) tag)))))
1130911342

1131011343
(defn derive
1131111344
"Establishes a parent/child relationship between parent and
@@ -11315,13 +11348,12 @@ reduces them without incurring seq initialization"
1131511348
supplied defaults to, and modifies, the global hierarchy."
1131611349
([tag parent]
1131711350
(assert (namespace parent))
11318-
;; (assert (or (class? tag) (and (instance? cljs.core.Named tag) (namespace tag))))
11351+
(assert (or (js-fn? tag) (and (implements? INamed tag) (namespace tag))))
1131911352
(swap-global-hierarchy! derive tag parent) nil)
1132011353
([h tag parent]
1132111354
(assert (not= tag parent))
11322-
;; (assert (or (class? tag) (instance? clojure.lang.Named tag)))
11323-
;; (assert (instance? clojure.lang.INamed tag))
11324-
;; (assert (instance? clojure.lang.INamed parent))
11355+
(assert (or (js-fn? tag) (implements? INamed tag)))
11356+
(assert (implements? INamed parent))
1132511357
(let [tp (:parents h)
1132611358
td (:descendants h)
1132711359
ta (:ancestors h)

src/test/cljs/cljs/core_test.cljs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -197,12 +197,12 @@
197197
(is (= #{:cljs.core-test/rect :cljs.core-test/square} (descendants ::shape)))
198198
(is (true? (isa? 42 42)))
199199
(is (true? (isa? ::square ::shape)))
200-
;(derive ObjMap ::collection)
200+
(derive ObjMap ::collection)
201201
(derive cljs.core.PersistentHashSet ::collection)
202-
;(is (true? (isa? ObjMap ::collection)))
202+
(is (true? (isa? ObjMap ::collection)))
203203
(is (true? (isa? cljs.core.PersistentHashSet ::collection)))
204204
(is (false? (isa? cljs.core.IndexedSeq ::collection)))
205-
;; ?? (isa? String Object)
205+
(isa? js/String js/Object)
206206
(is (true? (isa? [::square ::rect] [::shape ::shape])))
207207
;; ?? (ancestors java.util.ArrayList)
208208
;; ?? isa? based dispatch tests

0 commit comments

Comments
 (0)