From eb7d0489342fa5cfab3c05b23cdf4fa1a9e95181 Mon Sep 17 00:00:00 2001 From: davidnolen Date: Tue, 29 Jul 2025 19:17:17 -0400 Subject: [PATCH 01/53] ugh, bring it back --- src/main/cljs/cljs/core.cljs | 369 +++++++++++++++++++++++++++++++++++ 1 file changed, 369 insertions(+) diff --git a/src/main/cljs/cljs/core.cljs b/src/main/cljs/cljs/core.cljs index 4305440a8..d04fd38db 100644 --- a/src/main/cljs/cljs/core.cljs +++ b/src/main/cljs/cljs/core.cljs @@ -12400,3 +12400,372 @@ reduces them without incurring seq initialization" (identical? "window" *global*) (set! goog/global js/window) (identical? "self" *global*) (set! goog/global js/self) (identical? "global" *global*) (set! goog/global js/global))) + +;; ----------------------------------------------------------------------------- +;; Original 2011 Copy-on-Write Types + +;;; Vector + +(deftype Vector [meta array] + IWithMeta + (-with-meta [coll meta] (Vector. meta array)) + + IMeta + (-meta [coll] meta) + + IStack + (-peek [coll] + (let [count (.-length array)] + (when (> count 0) + (aget array (dec count))))) + (-pop [coll] + (if (> (.-length array) 0) + (let [new-array (aclone array)] + (. new-array (pop)) + (Vector. meta new-array)) + (throw (js/Error. "Can't pop empty vector")))) + + ICollection + (-conj [coll o] + (let [new-array (aclone array)] + (.push new-array o) + (Vector. meta new-array))) + + IEmptyableCollection + (-empty [coll] (with-meta (. Vector -EMPTY) meta)) + + ISequential + IEquiv + (-equiv [coll other] (equiv-sequential coll other)) + + IHash + (-hash [coll] (hash-coll coll)) + + ISeqable + (-seq [coll] + (when (> (.-length array) 0) + (let [vector-seq + (fn vector-seq [i] + (lazy-seq + (when (< i (.-length array)) + (cons (aget array i) (vector-seq (inc i))))))] + (vector-seq 0)))) + + ICounted + (-count [coll] (.-length array)) + + IIndexed + (-nth [coll n] + (if (and (<= 0 n) (< n (.-length array))) + (aget array n) + #_(throw (js/Error. (str "No item " n " in vector of length " (.-length array)))))) + (-nth [coll n not-found] + (if (and (<= 0 n) (< n (.-length array))) + (aget array n) + not-found)) + + ILookup + (-lookup [coll k] (-nth coll k nil)) + (-lookup [coll k not-found] (-nth coll k not-found)) + + IAssociative + (-assoc [coll k v] + (let [new-array (aclone array)] + (aset new-array k v) + (Vector. meta new-array))) + + IVector + (-assoc-n [coll n val] (-assoc coll n val)) + + IReduce + (-reduce [v f] + (ci-reduce array f)) + (-reduce [v f start] + (ci-reduce array f start)) + + IFn + (-invoke [coll k] + (-lookup coll k)) + (-invoke [coll k not-found] + (-lookup coll k not-found)) + + IPrintWithWriter + (-pr-writer [coll writer opts] (pr-sequential-writer writer pr-writer "[" " " "]" opts coll))) + +(set! (. Vector -EMPTY) (Vector. nil (array))) + +(set! (. Vector -fromArray) (fn [xs] (Vector. nil xs))) + +; The keys field is an array of all keys of this map, in no particular +; order. Any string, keyword, or symbol key is used as a property name +; to store the value in strobj. If a key is assoc'ed when that same +; key already exists in strobj, the old value is overwritten. If a +; non-string key is assoc'ed, return a HashMap object instead. + +(defn- obj-map-contains-key? + ([k strobj] + (obj-map-contains-key? k strobj true false)) + ([k strobj true-val false-val] + (if (and (goog/isString k) (.hasOwnProperty strobj k)) + true-val + false-val))) + +(defn- obj-map-compare-keys [a b] + (let [a (hash a) + b (hash b)] + (cond + (< a b) -1 + (> a b) 1 + :else 0))) + +(deftype ObjMap [meta keys strobj] + IWithMeta + (-with-meta [coll meta] (ObjMap. meta keys strobj)) + + IMeta + (-meta [coll] meta) + + ICollection + (-conj [coll entry] + (if (vector? entry) + (-assoc coll (-nth entry 0) (-nth entry 1)) + (reduce -conj + coll + entry))) + + IEmptyableCollection + (-empty [coll] (with-meta (. ObjMap -EMPTY) meta)) + + IEquiv + (-equiv [coll other] (equiv-map coll other)) + + IHash + (-hash [coll] (hash-coll coll)) + + ISeqable + (-seq [coll] + (when (pos? (.-length keys)) + (map #(vector % (aget strobj %)) + (.sort keys obj-map-compare-keys)))) + + ICounted + (-count [coll] (.-length keys)) + + ILookup + (-lookup [coll k] (-lookup coll k nil)) + (-lookup [coll k not-found] + (obj-map-contains-key? k strobj (aget strobj k) not-found)) + + IAssociative + (-assoc [coll k v] + (if (goog/isString k) + (let [new-strobj (goog.object/clone strobj) + overwrite? (.hasOwnProperty new-strobj k)] + (aset new-strobj k v) + (if overwrite? + (ObjMap. meta keys new-strobj) ; overwrite + (let [new-keys (aclone keys)] ; append + (.push new-keys k) + (ObjMap. meta new-keys new-strobj)))) + ; non-string key. game over. + (with-meta (into (hash-map k v) (seq coll)) meta))) + (-contains-key? [coll k] + (obj-map-contains-key? k strobj)) + + IMap + (-dissoc [coll k] + (if (and (goog/isString k) (.hasOwnProperty strobj k)) + (let [new-keys (aclone keys) + new-strobj (goog.object/clone strobj)] + (.splice new-keys (scan-array 1 k new-keys) 1) + (js-delete new-strobj k) + (ObjMap. meta new-keys new-strobj)) + coll)) ; key not found, return coll unchanged + + IFn + (-invoke [coll k] + (-lookup coll k)) + (-invoke [coll k not-found] + (-lookup coll k not-found)) + + IPrintWithWriter + (-pr-writer [coll writer opts] + (print-map coll pr-writer writer opts))) + +(set! (. ObjMap -EMPTY) (ObjMap. nil (array) (js-obj))) + +(set! (. ObjMap -fromObject) (fn [ks obj] (ObjMap. nil ks obj))) + +(defn obj-map + "keyval => key val + Returns a new object map with supplied mappings." + [& keyvals] + (let [ks (array) + obj (js-obj)] + (loop [kvs (seq keyvals)] + (if kvs + (do (.push ks (first kvs)) + (gobject/set obj (first kvs) (second kvs)) + (recur (nnext kvs))) + (.fromObject ObjMap ks obj))))) + +; The keys field is an array of all keys of this map, in no particular +; order. Each key is hashed and the result used as a property name of +; hashobj. Each values in hashobj is actually a bucket in order to handle hash +; collisions. A bucket is an array of alternating keys (not their hashes) and +; vals. +(deftype HashMap [meta count hashobj] + IWithMeta + (-with-meta [coll meta] (HashMap. meta count hashobj)) + + IMeta + (-meta [coll] meta) + + ICollection + (-conj [coll entry] + (if (vector? entry) + (-assoc coll (-nth entry 0) (-nth entry 1)) + (reduce -conj + coll + entry))) + + IEmptyableCollection + (-empty [coll] (with-meta (. HashMap -EMPTY) meta)) + + IEquiv + (-equiv [coll other] (equiv-map coll other)) + + IHash + (-hash [coll] (hash-coll coll)) + + ISeqable + (-seq [coll] + (when (pos? count) + (let [hashes (.sort (js-keys hashobj))] + (mapcat #(map vec (partition 2 (aget hashobj %))) + hashes)))) + + ICounted + (-count [coll] count) + + ILookup + (-lookup [coll k] (-lookup coll k nil)) + (-lookup [coll k not-found] + (let [bucket (aget hashobj (hash k)) + i (when bucket (scan-array 2 k bucket))] + (if i + (aget bucket (inc i)) + not-found))) + + IAssociative + (-assoc [coll k v] + (let [h (hash k) + bucket (aget hashobj h)] + (if bucket + (let [new-bucket (aclone bucket) + new-hashobj (goog.object/clone hashobj)] + (aset new-hashobj h new-bucket) + (if-let [i (scan-array 2 k new-bucket)] + (do ; found key, replace + (aset new-bucket (inc i) v) + (HashMap. meta count new-hashobj)) + (do ; did not find key, append + (.push new-bucket k v) + (HashMap. meta (inc count) new-hashobj)))) + (let [new-hashobj (goog.object/clone hashobj)] ; did not find bucket + (aset new-hashobj h (array k v)) + (HashMap. meta (inc count) new-hashobj))))) + (-contains-key? [coll k] + (let [bucket (aget hashobj (hash k)) + i (when bucket (scan-array 2 k bucket))] + (if i + true + false))) + + IMap + (-dissoc [coll k] + (let [h (hash k) + bucket (aget hashobj h) + i (when bucket (scan-array 2 k bucket))] + (if (not i) + coll ; key not found, return coll unchanged + (let [new-hashobj (goog.object/clone hashobj)] + (if (> 3 (.-length bucket)) + (js-delete new-hashobj h) + (let [new-bucket (aclone bucket)] + (.splice new-bucket i 2) + (aset new-hashobj h new-bucket))) + (HashMap. meta (dec count) new-hashobj))))) + + IFn + (-invoke [coll k] + (-lookup coll k)) + (-invoke [coll k not-found] + (-lookup coll k not-found)) + + IPrintWithWriter + (-pr-writer [coll writer opts] + (print-map coll pr-writer writer opts))) + +(set! (. HashMap -EMPTY) (HashMap. nil 0 (js-obj))) + +(set! (. HashMap -fromArrays) (fn [ks vs] + (let [len (.-length ks)] + (loop [i 0, out (. HashMap -EMPTY)] + (if (< i len) + (recur (inc i) (assoc out (aget ks i) (aget vs i))) + out))))) + +(deftype Set [meta hash-map] + IWithMeta + (-with-meta [coll meta] (Set. meta hash-map)) + + IMeta + (-meta [coll] meta) + + ICollection + (-conj [coll o] + (Set. meta (assoc hash-map o nil))) + + IEmptyableCollection + (-empty [coll] (with-meta (. Set -EMPTY) meta)) + + IEquiv + (-equiv [coll other] + (and + (set? other) + (= (count coll) (count other)) + (every? #(contains? coll %) + other))) + + IHash + (-hash [coll] (hash-coll coll)) + + ISeqable + (-seq [coll] (keys hash-map)) + + ICounted + (-count [coll] (count (seq coll))) + + ILookup + (-lookup [coll v] + (-lookup coll v nil)) + (-lookup [coll v not-found] + (if (-contains-key? hash-map v) + v + not-found)) + + ISet + (-disjoin [coll v] + (Set. meta (dissoc hash-map v))) + + IFn + (-invoke [coll k] + (-lookup coll k)) + (-invoke [coll k not-found] + (-lookup coll k not-found)) + + IPrintWithWriter + (-pr-writer [coll writer opts] (pr-sequential-writer writer pr-writer "#{" " " "}" opts coll))) + +(set! (. Set -EMPTY) (Set. nil (hash-map))) From 3105284afa07081db390baee4ca4e9bee42998d3 Mon Sep 17 00:00:00 2001 From: davidnolen Date: Tue, 29 Jul 2025 19:51:58 -0400 Subject: [PATCH 02/53] - remove old ObjMap - update older ObjMap - simple-hash-map to avoid name collision --- src/main/cljs/cljs/core.cljs | 280 ++++++++++------------------------- 1 file changed, 78 insertions(+), 202 deletions(-) diff --git a/src/main/cljs/cljs/core.cljs b/src/main/cljs/cljs/core.cljs index d04fd38db..479a6a120 100644 --- a/src/main/cljs/cljs/core.cljs +++ b/src/main/cljs/cljs/core.cljs @@ -6561,163 +6561,6 @@ reduces them without incurring seq initialization" i (recur (+ i incr))))))) -; The keys field is an array of all keys of this map, in no particular -; order. Any string, keyword, or symbol key is used as a property name -; to store the value in strobj. If a key is assoc'ed when that same -; key already exists in strobj, the old value is overwritten. If a -; non-string key is assoc'ed, return a HashMap object instead. - -(defn- obj-map-compare-keys [a b] - (let [a (hash a) - b (hash b)] - (cond - (< a b) -1 - (> a b) 1 - :else 0))) - -(defn- obj-map->hash-map [m k v] - (let [ks (.-keys m) - len (alength ks) - so (.-strobj m) - mm (meta m)] - (loop [i 0 - out (transient (.-EMPTY PersistentHashMap))] - (if (< i len) - (let [k (aget ks i)] - (recur (inc i) (assoc! out k (gobject/get so k)))) - (-with-meta (persistent! (assoc! out k v)) mm))))) - -;;; ObjMap - DEPRECATED - -(defn- obj-clone [obj ks] - (let [new-obj (js-obj) - l (alength ks)] - (loop [i 0] - (when (< i l) - (let [k (aget ks i)] - (gobject/set new-obj k (gobject/get obj k)) - (recur (inc i))))) - new-obj)) - -(deftype ObjMap [meta keys strobj update-count ^:mutable __hash] - Object - (toString [coll] - (pr-str* coll)) - (equiv [this other] - (-equiv this other)) - - IWithMeta - (-with-meta [coll new-meta] - (if (identical? new-meta meta) - coll - (ObjMap. new-meta keys strobj update-count __hash))) - - IMeta - (-meta [coll] meta) - - ICollection - (-conj [coll entry] - (if (vector? entry) - (-assoc coll (-nth entry 0) (-nth entry 1)) - (reduce -conj - coll - entry))) - - IEmptyableCollection - (-empty [coll] (-with-meta (.-EMPTY ObjMap) meta)) - - IEquiv - (-equiv [coll other] (equiv-map coll other)) - - IHash - (-hash [coll] (caching-hash coll hash-unordered-coll __hash)) - - ISeqable - (-seq [coll] - (when (pos? (alength keys)) - (map #(vector % (unchecked-get strobj %)) - (.sort keys obj-map-compare-keys)))) - - ICounted - (-count [coll] (alength keys)) - - ILookup - (-lookup [coll k] (-lookup coll k nil)) - (-lookup [coll k not-found] - (if (and (string? k) - (not (nil? (scan-array 1 k keys)))) - (unchecked-get strobj k) - not-found)) - - IAssociative - (-assoc [coll k v] - (if (string? k) - (if (or (> update-count (.-HASHMAP_THRESHOLD ObjMap)) - (>= (alength keys) (.-HASHMAP_THRESHOLD ObjMap))) - (obj-map->hash-map coll k v) - (if-not (nil? (scan-array 1 k keys)) - (let [new-strobj (obj-clone strobj keys)] - (gobject/set new-strobj k v) - (ObjMap. meta keys new-strobj (inc update-count) nil)) ; overwrite - (let [new-strobj (obj-clone strobj keys) ; append - new-keys (aclone keys)] - (gobject/set new-strobj k v) - (.push new-keys k) - (ObjMap. meta new-keys new-strobj (inc update-count) nil)))) - ;; non-string key. game over. - (obj-map->hash-map coll k v))) - (-contains-key? [coll k] - (if (and (string? k) - (not (nil? (scan-array 1 k keys)))) - true - false)) - - IFind - (-find [coll k] - (when (and (string? k) - (not (nil? (scan-array 1 k keys)))) - (MapEntry. k (unchecked-get strobj k) nil))) - - IKVReduce - (-kv-reduce [coll f init] - (let [len (alength keys)] - (loop [keys (.sort keys obj-map-compare-keys) - init init] - (if (seq keys) - (let [k (first keys) - init (f init k (unchecked-get strobj k))] - (if (reduced? init) - @init - (recur (rest keys) init))) - init)))) - - IMap - (-dissoc [coll k] - (if (and (string? k) - (not (nil? (scan-array 1 k keys)))) - (let [new-keys (aclone keys) - new-strobj (obj-clone strobj keys)] - (.splice new-keys (scan-array 1 k new-keys) 1) - (js-delete new-strobj k) - (ObjMap. meta new-keys new-strobj (inc update-count) nil)) - coll)) ; key not found, return coll unchanged - - IFn - (-invoke [coll k] - (-lookup coll k)) - (-invoke [coll k not-found] - (-lookup coll k not-found)) - - IEditableCollection - (-as-transient [coll] - (transient (into (hash-map) coll)))) - -(set! (.-EMPTY ObjMap) (ObjMap. nil (array) (js-obj) 0 empty-unordered-hash)) - -(set! (.-HASHMAP_THRESHOLD ObjMap) 8) - -(set! (.-fromObject ObjMap) (fn [ks obj] (ObjMap. nil ks obj 0 nil))) - ;; Record Iterator (deftype RecordIter [^:mutable i record base-count fields ext-map-iter] Object @@ -9191,19 +9034,6 @@ reduces them without incurring seq initialization" (.createAsIfByAssoc PersistentArrayMap (to-array s)) (if (seq s) (first s) (.-EMPTY PersistentArrayMap)))) -(defn obj-map - "keyval => key val - Returns a new object map with supplied mappings." - [& keyvals] - (let [ks (array) - obj (js-obj)] - (loop [kvs (seq keyvals)] - (if kvs - (do (.push ks (first kvs)) - (gobject/set obj (first kvs) (second kvs)) - (recur (nnext kvs))) - (.fromObject ObjMap ks obj))))) - (defn sorted-map "keyval => key val Returns a new sorted map with supplied mappings." @@ -10855,10 +10685,6 @@ reduces them without incurring seq initialization" MapEntry (-pr-writer [coll writer opts] (pr-sequential-writer writer pr-writer "[" " " "]" opts coll)) - ObjMap - (-pr-writer [coll writer opts] - (print-map coll pr-writer writer opts)) - KeySeq (-pr-writer [coll writer opts] (pr-sequential-writer writer pr-writer "(" " " ")" opts coll)) @@ -12502,14 +12328,6 @@ reduces them without incurring seq initialization" ; key already exists in strobj, the old value is overwritten. If a ; non-string key is assoc'ed, return a HashMap object instead. -(defn- obj-map-contains-key? - ([k strobj] - (obj-map-contains-key? k strobj true false)) - ([k strobj true-val false-val] - (if (and (goog/isString k) (.hasOwnProperty strobj k)) - true-val - false-val))) - (defn- obj-map-compare-keys [a b] (let [a (hash a) b (hash b)] @@ -12518,7 +12336,25 @@ reduces them without incurring seq initialization" (> a b) 1 :else 0))) -(deftype ObjMap [meta keys strobj] +(defn- obj-clone [obj ks] + (let [new-obj (js-obj) + l (alength ks)] + (loop [i 0] + (when (< i l) + (let [k (aget ks i)] + (gobject/set new-obj k (gobject/get obj k)) + (recur (inc i))))) + new-obj)) + +(declare simple-hash-map) + +(deftype ObjMap [meta keys strobj ^:mutable __hash] + Object + (toString [coll] + (pr-str* coll)) + (equiv [this other] + (-equiv this other)) + IWithMeta (-with-meta [coll meta] (ObjMap. meta keys strobj)) @@ -12540,46 +12376,73 @@ reduces them without incurring seq initialization" (-equiv [coll other] (equiv-map coll other)) IHash - (-hash [coll] (hash-coll coll)) + (-hash [coll] (caching-hash coll hash-unordered-coll __hash)) ISeqable (-seq [coll] - (when (pos? (.-length keys)) - (map #(vector % (aget strobj %)) + (when (pos? (alength keys)) + (map #(vector % (unchecked-get strobj %)) (.sort keys obj-map-compare-keys)))) ICounted - (-count [coll] (.-length keys)) + (-count [coll] (alength keys)) ILookup (-lookup [coll k] (-lookup coll k nil)) (-lookup [coll k not-found] - (obj-map-contains-key? k strobj (aget strobj k) not-found)) + (if (and (string? k) + (not (nil? (scan-array 1 k keys)))) + (unchecked-get strobj k) + not-found)) IAssociative (-assoc [coll k v] - (if (goog/isString k) - (let [new-strobj (goog.object/clone strobj) - overwrite? (.hasOwnProperty new-strobj k)] - (aset new-strobj k v) - (if overwrite? - (ObjMap. meta keys new-strobj) ; overwrite - (let [new-keys (aclone keys)] ; append - (.push new-keys k) - (ObjMap. meta new-keys new-strobj)))) + (if (string? k) + (if-not (nil? (scan-array 1 k keys)) + (let [new-strobj (obj-clone strobj keys)] + (gobject/set new-strobj k v) + (ObjMap. meta keys new-strobj nil)) ; overwrite + (let [new-strobj (obj-clone strobj keys) ; append + new-keys (aclone keys)] + (gobject/set new-strobj k v) + (.push new-keys k) + (ObjMap. meta new-keys new-strobj nil))) ; non-string key. game over. - (with-meta (into (hash-map k v) (seq coll)) meta))) + (with-meta (into (simple-hash-map k v) (seq coll)) meta))) (-contains-key? [coll k] - (obj-map-contains-key? k strobj)) + (if (and (string? k) + (not (nil? (scan-array 1 k keys)))) + true + false)) + + IFind + (-find [coll k] + (when (and (string? k) + (not (nil? (scan-array 1 k keys)))) + (MapEntry. k (unchecked-get strobj k) nil))) + + IKVReduce + (-kv-reduce [coll f init] + (let [len (alength keys)] + (loop [keys (.sort keys obj-map-compare-keys) + init init] + (if (seq keys) + (let [k (first keys) + init (f init k (unchecked-get strobj k))] + (if (reduced? init) + @init + (recur (rest keys) init))) + init)))) IMap (-dissoc [coll k] - (if (and (goog/isString k) (.hasOwnProperty strobj k)) + (if (and (string? k) + (not (nil? (scan-array 1 k keys)))) (let [new-keys (aclone keys) - new-strobj (goog.object/clone strobj)] + new-strobj (obj-clone strobj keys)] (.splice new-keys (scan-array 1 k new-keys) 1) (js-delete new-strobj k) - (ObjMap. meta new-keys new-strobj)) + (ObjMap. meta new-keys new-strobj nil)) coll)) ; key not found, return coll unchanged IFn @@ -12588,6 +12451,10 @@ reduces them without incurring seq initialization" (-invoke [coll k not-found] (-lookup coll k not-found)) + ;IEditableCollection + ;(-as-transient [coll] + ; (transient (into (simple-hash-map) coll))) + IPrintWithWriter (-pr-writer [coll writer opts] (print-map coll pr-writer writer opts))) @@ -12716,6 +12583,15 @@ reduces them without incurring seq initialization" (recur (inc i) (assoc out (aget ks i) (aget vs i))) out))))) +(defn simple-hash-map + "keyval => key val + Returns a new hash map with supplied mappings." + [& keyvals] + (loop [in (seq keyvals), out (. HashMap -EMPTY)] + (if in + (recur (nnext in) (assoc out (first in) (second in))) + out))) + (deftype Set [meta hash-map] IWithMeta (-with-meta [coll meta] (Set. meta hash-map)) From dba928b9334b5df85bf1731d89e704f7f61057ed Mon Sep 17 00:00:00 2001 From: davidnolen Date: Tue, 29 Jul 2025 20:00:41 -0400 Subject: [PATCH 03/53] fix all the ObjMap ctor sites --- src/main/cljs/cljs/core.cljs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/cljs/cljs/core.cljs b/src/main/cljs/cljs/core.cljs index 479a6a120..7421b69a2 100644 --- a/src/main/cljs/cljs/core.cljs +++ b/src/main/cljs/cljs/core.cljs @@ -12356,7 +12356,7 @@ reduces them without incurring seq initialization" (-equiv this other)) IWithMeta - (-with-meta [coll meta] (ObjMap. meta keys strobj)) + (-with-meta [coll meta] (ObjMap. meta keys strobj __hash)) IMeta (-meta [coll] meta) @@ -12459,9 +12459,9 @@ reduces them without incurring seq initialization" (-pr-writer [coll writer opts] (print-map coll pr-writer writer opts))) -(set! (. ObjMap -EMPTY) (ObjMap. nil (array) (js-obj))) +(set! (. ObjMap -EMPTY) (ObjMap. nil (array) (js-obj) empty-ordered-hash)) -(set! (. ObjMap -fromObject) (fn [ks obj] (ObjMap. nil ks obj))) +(set! (. ObjMap -fromObject) (fn [ks obj] (ObjMap. nil ks obj nil))) (defn obj-map "keyval => key val From db629371ca6d63295b477a22c58c3eeca91fbeb5 Mon Sep 17 00:00:00 2001 From: davidnolen Date: Tue, 29 Jul 2025 20:27:26 -0400 Subject: [PATCH 04/53] check for :lite-mode? - emit Vector if set --- src/main/cljs/cljs/core.cljs | 14 +++++++------- src/main/clojure/cljs/closure.clj | 2 +- src/main/clojure/cljs/compiler.cljc | 12 +++++++++++- 3 files changed, 19 insertions(+), 9 deletions(-) diff --git a/src/main/cljs/cljs/core.cljs b/src/main/cljs/cljs/core.cljs index 7421b69a2..ca32963ba 100644 --- a/src/main/cljs/cljs/core.cljs +++ b/src/main/cljs/cljs/core.cljs @@ -12232,9 +12232,9 @@ reduces them without incurring seq initialization" ;;; Vector -(deftype Vector [meta array] +(deftype Vector [meta array ^:mutable __hash] IWithMeta - (-with-meta [coll meta] (Vector. meta array)) + (-with-meta [coll meta] (Vector. meta array __hash)) IMeta (-meta [coll] meta) @@ -12248,14 +12248,14 @@ reduces them without incurring seq initialization" (if (> (.-length array) 0) (let [new-array (aclone array)] (. new-array (pop)) - (Vector. meta new-array)) + (Vector. meta new-array nil)) (throw (js/Error. "Can't pop empty vector")))) ICollection (-conj [coll o] (let [new-array (aclone array)] (.push new-array o) - (Vector. meta new-array))) + (Vector. meta new-array nil))) IEmptyableCollection (-empty [coll] (with-meta (. Vector -EMPTY) meta)) @@ -12298,7 +12298,7 @@ reduces them without incurring seq initialization" (-assoc [coll k v] (let [new-array (aclone array)] (aset new-array k v) - (Vector. meta new-array))) + (Vector. meta new-array nil))) IVector (-assoc-n [coll n val] (-assoc coll n val)) @@ -12318,9 +12318,9 @@ reduces them without incurring seq initialization" IPrintWithWriter (-pr-writer [coll writer opts] (pr-sequential-writer writer pr-writer "[" " " "]" opts coll))) -(set! (. Vector -EMPTY) (Vector. nil (array))) +(set! (. Vector -EMPTY) (Vector. nil (array) nil)) -(set! (. Vector -fromArray) (fn [xs] (Vector. nil xs))) +(set! (. Vector -fromArray) (fn [xs] (Vector. nil xs nil))) ; The keys field is an array of all keys of this map, in no particular ; order. Any string, keyword, or symbol key is used as a property name diff --git a/src/main/clojure/cljs/closure.clj b/src/main/clojure/cljs/closure.clj index b215573f6..147365455 100644 --- a/src/main/clojure/cljs/closure.clj +++ b/src/main/clojure/cljs/closure.clj @@ -211,7 +211,7 @@ :watch :watch-error-fn :watch-fn :install-deps :process-shim :rename-prefix :rename-prefix-namespace :closure-variable-map-in :closure-property-map-in :closure-variable-map-out :closure-property-map-out :stable-names :ignore-js-module-exts :opts-cache :aot-cache :elide-strict :fingerprint :spec-skip-macros - :nodejs-rt :target-fn :deps-cmd :bundle-cmd :global-goog-object&array :node-modules-dirs}) + :nodejs-rt :target-fn :deps-cmd :bundle-cmd :global-goog-object&array :node-modules-dirs :lite-mode?}) (def string->charset {"iso-8859-1" StandardCharsets/ISO_8859_1 diff --git a/src/main/clojure/cljs/compiler.cljc b/src/main/clojure/cljs/compiler.cljc index fcc03ab96..3aedfee88 100644 --- a/src/main/clojure/cljs/compiler.cljc +++ b/src/main/clojure/cljs/compiler.cljc @@ -522,6 +522,9 @@ (and (every? #(= (:op %) :const) keys) (= (count (into #{} keys)) (count keys))))) +(defn lite-mode? [] + (get-in @env/*compiler* [:options :lite-mode?])) + (defn emit-map [keys vals comma-sep distinct-keys?] (cond (zero? (count keys)) @@ -562,10 +565,17 @@ ", 5, cljs.core.PersistentVector.EMPTY_NODE, [" (comma-sep items) "], null)") (emits "cljs.core.PersistentVector.fromArray([" (comma-sep items) "], true)"))))) +(defn emit-lite-vector [items comma-sep] + (if (empty? items) + (emits "cljs.core.Vector.EMPTY") + (emits "new cljs.core.Vector(null, [" (comma-sep items) "], null)"))) + (defmethod emit* :vector [{:keys [items env]}] (emit-wrap env - (emit-vector items comma-sep))) + (if (lite-mode?) + (emit-lite-vector items comma-sep) + (emit-vector items comma-sep)))) (defn distinct-constants? [items] (let [items (map ana/unwrap-quote items)] From 85a36202a59fa9dc21fa0d634a919f715ea5cae4 Mon Sep 17 00:00:00 2001 From: davidnolen Date: Tue, 29 Jul 2025 20:32:49 -0400 Subject: [PATCH 05/53] :lite-mode? -> :lite-mode --- src/main/clojure/cljs/closure.clj | 2 +- src/main/clojure/cljs/compiler.cljc | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/clojure/cljs/closure.clj b/src/main/clojure/cljs/closure.clj index 147365455..c0ed3499a 100644 --- a/src/main/clojure/cljs/closure.clj +++ b/src/main/clojure/cljs/closure.clj @@ -211,7 +211,7 @@ :watch :watch-error-fn :watch-fn :install-deps :process-shim :rename-prefix :rename-prefix-namespace :closure-variable-map-in :closure-property-map-in :closure-variable-map-out :closure-property-map-out :stable-names :ignore-js-module-exts :opts-cache :aot-cache :elide-strict :fingerprint :spec-skip-macros - :nodejs-rt :target-fn :deps-cmd :bundle-cmd :global-goog-object&array :node-modules-dirs :lite-mode?}) + :nodejs-rt :target-fn :deps-cmd :bundle-cmd :global-goog-object&array :node-modules-dirs :lite-mode}) (def string->charset {"iso-8859-1" StandardCharsets/ISO_8859_1 diff --git a/src/main/clojure/cljs/compiler.cljc b/src/main/clojure/cljs/compiler.cljc index 3aedfee88..8f7f6414d 100644 --- a/src/main/clojure/cljs/compiler.cljc +++ b/src/main/clojure/cljs/compiler.cljc @@ -523,7 +523,7 @@ (= (count (into #{} keys)) (count keys))))) (defn lite-mode? [] - (get-in @env/*compiler* [:options :lite-mode?])) + (get-in @env/*compiler* [:options :lite-mode])) (defn emit-map [keys vals comma-sep distinct-keys?] (cond From 930fbef3e0d8619929f38438d9567d527a1cfb5d Mon Sep 17 00:00:00 2001 From: davidnolen Date: Tue, 29 Jul 2025 23:01:29 -0400 Subject: [PATCH 06/53] update HashMap and Set --- src/main/cljs/cljs/core.cljs | 40 +++++++++++++++++++++++------------- 1 file changed, 26 insertions(+), 14 deletions(-) diff --git a/src/main/cljs/cljs/core.cljs b/src/main/cljs/cljs/core.cljs index ca32963ba..b2a5fecdd 100644 --- a/src/main/cljs/cljs/core.cljs +++ b/src/main/cljs/cljs/core.cljs @@ -12481,9 +12481,15 @@ reduces them without incurring seq initialization" ; hashobj. Each values in hashobj is actually a bucket in order to handle hash ; collisions. A bucket is an array of alternating keys (not their hashes) and ; vals. -(deftype HashMap [meta count hashobj] +(deftype HashMap [meta count hashobj ^:mutable __hash] + Object + (toString [coll] + (pr-str* coll)) + (equiv [this other] + (-equiv this other)) + IWithMeta - (-with-meta [coll meta] (HashMap. meta count hashobj)) + (-with-meta [coll meta] (HashMap. meta count hashobj __hash)) IMeta (-meta [coll] meta) @@ -12503,7 +12509,7 @@ reduces them without incurring seq initialization" (-equiv [coll other] (equiv-map coll other)) IHash - (-hash [coll] (hash-coll coll)) + (-hash [coll] (caching-hash coll hash-unordered-coll __hash)) ISeqable (-seq [coll] @@ -12535,13 +12541,13 @@ reduces them without incurring seq initialization" (if-let [i (scan-array 2 k new-bucket)] (do ; found key, replace (aset new-bucket (inc i) v) - (HashMap. meta count new-hashobj)) + (HashMap. meta count new-hashobj nil)) (do ; did not find key, append (.push new-bucket k v) - (HashMap. meta (inc count) new-hashobj)))) + (HashMap. meta (inc count) new-hashobj nil)))) (let [new-hashobj (goog.object/clone hashobj)] ; did not find bucket (aset new-hashobj h (array k v)) - (HashMap. meta (inc count) new-hashobj))))) + (HashMap. meta (inc count) new-hashobj nil))))) (-contains-key? [coll k] (let [bucket (aget hashobj (hash k)) i (when bucket (scan-array 2 k bucket))] @@ -12562,7 +12568,7 @@ reduces them without incurring seq initialization" (let [new-bucket (aclone bucket)] (.splice new-bucket i 2) (aset new-hashobj h new-bucket))) - (HashMap. meta (dec count) new-hashobj))))) + (HashMap. meta (dec count) new-hashobj nil))))) IFn (-invoke [coll k] @@ -12574,7 +12580,7 @@ reduces them without incurring seq initialization" (-pr-writer [coll writer opts] (print-map coll pr-writer writer opts))) -(set! (. HashMap -EMPTY) (HashMap. nil 0 (js-obj))) +(set! (. HashMap -EMPTY) (HashMap. nil 0 (js-obj) empty-unordered-hash)) (set! (. HashMap -fromArrays) (fn [ks vs] (let [len (.-length ks)] @@ -12592,16 +12598,22 @@ reduces them without incurring seq initialization" (recur (nnext in) (assoc out (first in) (second in))) out))) -(deftype Set [meta hash-map] +(deftype Set [meta hash-map ^:mutable __hash] + Object + (toString [coll] + (pr-str* coll)) + (equiv [this other] + (-equiv this other)) + IWithMeta - (-with-meta [coll meta] (Set. meta hash-map)) + (-with-meta [coll meta] (Set. meta hash-map __hash)) IMeta (-meta [coll] meta) ICollection (-conj [coll o] - (Set. meta (assoc hash-map o nil))) + (Set. meta (assoc hash-map o nil) nil)) IEmptyableCollection (-empty [coll] (with-meta (. Set -EMPTY) meta)) @@ -12615,7 +12627,7 @@ reduces them without incurring seq initialization" other))) IHash - (-hash [coll] (hash-coll coll)) + (-hash [coll] (caching-hash coll hash-unordered-coll __hash)) ISeqable (-seq [coll] (keys hash-map)) @@ -12633,7 +12645,7 @@ reduces them without incurring seq initialization" ISet (-disjoin [coll v] - (Set. meta (dissoc hash-map v))) + (Set. meta (dissoc hash-map v) nil)) IFn (-invoke [coll k] @@ -12644,4 +12656,4 @@ reduces them without incurring seq initialization" IPrintWithWriter (-pr-writer [coll writer opts] (pr-sequential-writer writer pr-writer "#{" " " "}" opts coll))) -(set! (. Set -EMPTY) (Set. nil (hash-map))) +(set! (. Set -EMPTY) (Set. nil (hash-map) empty-unordered-hash)) From 71b1e996da3bb0290a5e26c8f46a5d3c9fa40b42 Mon Sep 17 00:00:00 2001 From: davidnolen Date: Wed, 30 Jul 2025 08:26:08 -0400 Subject: [PATCH 07/53] no .toString for :lite-mode, pay for what you use --- src/main/cljs/cljs/core.cljs | 20 +------------------- 1 file changed, 1 insertion(+), 19 deletions(-) diff --git a/src/main/cljs/cljs/core.cljs b/src/main/cljs/cljs/core.cljs index b2a5fecdd..ac125c14f 100644 --- a/src/main/cljs/cljs/core.cljs +++ b/src/main/cljs/cljs/core.cljs @@ -12349,12 +12349,6 @@ reduces them without incurring seq initialization" (declare simple-hash-map) (deftype ObjMap [meta keys strobj ^:mutable __hash] - Object - (toString [coll] - (pr-str* coll)) - (equiv [this other] - (-equiv this other)) - IWithMeta (-with-meta [coll meta] (ObjMap. meta keys strobj __hash)) @@ -12482,12 +12476,6 @@ reduces them without incurring seq initialization" ; collisions. A bucket is an array of alternating keys (not their hashes) and ; vals. (deftype HashMap [meta count hashobj ^:mutable __hash] - Object - (toString [coll] - (pr-str* coll)) - (equiv [this other] - (-equiv this other)) - IWithMeta (-with-meta [coll meta] (HashMap. meta count hashobj __hash)) @@ -12599,12 +12587,6 @@ reduces them without incurring seq initialization" out))) (deftype Set [meta hash-map ^:mutable __hash] - Object - (toString [coll] - (pr-str* coll)) - (equiv [this other] - (-equiv this other)) - IWithMeta (-with-meta [coll meta] (Set. meta hash-map __hash)) @@ -12656,4 +12638,4 @@ reduces them without incurring seq initialization" IPrintWithWriter (-pr-writer [coll writer opts] (pr-sequential-writer writer pr-writer "#{" " " "}" opts coll))) -(set! (. Set -EMPTY) (Set. nil (hash-map) empty-unordered-hash)) +(set! (. Set -EMPTY) (Set. nil (simple-hash-map) empty-unordered-hash)) From 90945e63b4ec0747baae0594cdf37142eff0ebc2 Mon Sep 17 00:00:00 2001 From: davidnolen Date: Wed, 30 Jul 2025 08:42:04 -0400 Subject: [PATCH 08/53] - something weird about simple-hash-map, leave a note - switch to HashMap/EMPTY --- src/main/cljs/cljs/core.cljs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/main/cljs/cljs/core.cljs b/src/main/cljs/cljs/core.cljs index ac125c14f..4e01aa341 100644 --- a/src/main/cljs/cljs/core.cljs +++ b/src/main/cljs/cljs/core.cljs @@ -12577,6 +12577,8 @@ reduces them without incurring seq initialization" (recur (inc i) (assoc out (aget ks i) (aget vs i))) out))))) +;; FIXME: calling this (simple-hash-map) expands the codesize significantly, +;; not clear why at the moment, seems to do less than (hash-map) (defn simple-hash-map "keyval => key val Returns a new hash map with supplied mappings." @@ -12638,4 +12640,4 @@ reduces them without incurring seq initialization" IPrintWithWriter (-pr-writer [coll writer opts] (pr-sequential-writer writer pr-writer "#{" " " "}" opts coll))) -(set! (. Set -EMPTY) (Set. nil (simple-hash-map) empty-unordered-hash)) +(set! (. Set -EMPTY) (Set. nil (. HashMap -EMPTY) empty-unordered-hash)) From d3beffe57f0da3c728e5b9dd9b501944a4a80303 Mon Sep 17 00:00:00 2001 From: davidnolen Date: Wed, 30 Jul 2025 08:44:34 -0400 Subject: [PATCH 09/53] :lite-mode path for maps --- src/main/clojure/cljs/compiler.cljc | 30 +++++++++++++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/src/main/clojure/cljs/compiler.cljc b/src/main/clojure/cljs/compiler.cljc index 8f7f6414d..dcbf11e9e 100644 --- a/src/main/clojure/cljs/compiler.cljc +++ b/src/main/clojure/cljs/compiler.cljc @@ -525,6 +525,27 @@ (defn lite-mode? [] (get-in @env/*compiler* [:options :lite-mode])) +(defn obj-map-key [x] + (if (keyword? x) + (str \" "\\uFDD0" \' + (if (namespace x) + (str (namespace x) "/") "") + (name x) + \") + x)) + +(defn emit-obj-map [str-keys vals comma-sep distinct-keys?] + (if (zero? (count str-keys)) + (emits "cljs.core.ObjMap.EMPTY") + (emits "cljs.core.ObjMap.fromObject([" (comma-sep str-keys) "], {" + (comma-sep (map (fn [k v] (str k ":" (emit-str v))) str-keys vals)) + "})"))) + +(defn emit-lite-map [keys vals comma-sep distinct-keys?] + (if (zero? (count keys)) + (emits "cljs.core.HashMap.EMPTY") + (emits "cljs.core.HashMap.fromArrays([" (comma-sep keys) "], [" (comma-sep vals) "])"))) + (defn emit-map [keys vals comma-sep distinct-keys?] (cond (zero? (count keys)) @@ -547,9 +568,14 @@ "])"))) (defmethod emit* :map - [{:keys [env keys vals]}] + [{:keys [env form keys vals]}] (emit-wrap env - (emit-map keys vals comma-sep distinct-keys?))) + (if (lite-mode?) + (let [form-keys (clojure.core/keys form)] + (if (every? #(or (string? %) (keyword? %)) form-keys) + (emit-obj-map (map obj-map-key form-keys) vals comma-sep distinct-keys?) + (emit-lite-map keys vals comma-sep distinct-keys?))) + (emit-map keys vals comma-sep distinct-keys?)))) (defn emit-list [items comma-sep] (if (empty? items) From 4e3f244e877f4b25abf2ac34c5e107491e241d10 Mon Sep 17 00:00:00 2001 From: davidnolen Date: Wed, 30 Jul 2025 16:48:50 -0400 Subject: [PATCH 10/53] always elide toString Object methods in :lite-mode --- src/main/clojure/cljs/core.cljc | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/src/main/clojure/cljs/core.cljc b/src/main/clojure/cljs/core.cljc index 8393a1a67..de6242553 100644 --- a/src/main/clojure/cljs/core.cljc +++ b/src/main/clojure/cljs/core.cljc @@ -1507,13 +1507,18 @@ ~@body)))) (core/defn- add-obj-methods [type type-sym sigs] - (map (core/fn [[f & meths :as form]] - (core/let [[f meths] (if (vector? (first meths)) - [f [(rest form)]] - [f meths])] - `(set! ~(extend-prefix type-sym f) - ~(with-meta `(fn ~@(map #(adapt-obj-params type %) meths)) (meta form))))) - sigs)) + (->> sigs + ;; Elide all toString methods in :lite-mode + (remove + (core/fn [[f]] + (and (comp/lite-mode?) (= 'toString f)))) + (map + (core/fn [[f & meths :as form]] + (core/let [[f meths] (if (vector? (first meths)) + [f [(rest form)]] + [f meths])] + `(set! ~(extend-prefix type-sym f) + ~(with-meta `(fn ~@(map #(adapt-obj-params type %) meths)) (meta form)))))))) (core/defn- ifn-invoke-methods [type type-sym [f & meths :as form]] (map From ac117358996665a84ed2e533cb705ae8564b974a Mon Sep 17 00:00:00 2001 From: davidnolen Date: Wed, 30 Jul 2025 16:51:40 -0400 Subject: [PATCH 11/53] assoc directly reference array-map, replace w/ literal --- src/main/cljs/cljs/core.cljs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/cljs/cljs/core.cljs b/src/main/cljs/cljs/core.cljs index 4e01aa341..1ca45372e 100644 --- a/src/main/cljs/cljs/core.cljs +++ b/src/main/cljs/cljs/core.cljs @@ -2070,7 +2070,7 @@ reduces them without incurring seq initialization" (-assoc coll k v) (if-not (nil? coll) (-assoc coll k v) - (array-map k v)))) + {k v}))) ([coll k v & kvs] (let [ret (assoc coll k v)] (if kvs From 42bb870445cc0fcb9ec8cddd2a1c5573bd453fc8 Mon Sep 17 00:00:00 2001 From: davidnolen Date: Wed, 30 Jul 2025 16:52:28 -0400 Subject: [PATCH 12/53] add simple-vector for now, might need to compiler support soon, but can use this util then --- src/main/cljs/cljs/core.cljs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/main/cljs/cljs/core.cljs b/src/main/cljs/cljs/core.cljs index 1ca45372e..7dc9004d6 100644 --- a/src/main/cljs/cljs/core.cljs +++ b/src/main/cljs/cljs/core.cljs @@ -12322,6 +12322,12 @@ reduces them without incurring seq initialization" (set! (. Vector -fromArray) (fn [xs] (Vector. nil xs nil))) +(defn simple-vector + [& args] + (if (and (instance? IndexedSeq args) (zero? (.-i args))) + (.fromArray Vector (.-arr args) (not (array? (.-arr args)))) + (vec args))) + ; The keys field is an array of all keys of this map, in no particular ; order. Any string, keyword, or symbol key is used as a property name ; to store the value in strobj. If a key is assoc'ed when that same From ac61da8fc0240ff9d6aebe0aaecccbba00f9fa92 Mon Sep 17 00:00:00 2001 From: davidnolen Date: Wed, 30 Jul 2025 16:53:17 -0400 Subject: [PATCH 13/53] - formatting - avoid map in ObjMap for now until we get our ducks in a row --- src/main/cljs/cljs/core.cljs | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/main/cljs/cljs/core.cljs b/src/main/cljs/cljs/core.cljs index 7dc9004d6..f3cede02f 100644 --- a/src/main/cljs/cljs/core.cljs +++ b/src/main/cljs/cljs/core.cljs @@ -12365,9 +12365,7 @@ reduces them without incurring seq initialization" (-conj [coll entry] (if (vector? entry) (-assoc coll (-nth entry 0) (-nth entry 1)) - (reduce -conj - coll - entry))) + (reduce -conj coll entry))) IEmptyableCollection (-empty [coll] (with-meta (. ObjMap -EMPTY) meta)) @@ -12381,8 +12379,9 @@ reduces them without incurring seq initialization" ISeqable (-seq [coll] (when (pos? (alength keys)) - (map #(vector % (unchecked-get strobj %)) - (.sort keys obj-map-compare-keys)))) + (prim-seq + (.map (.sort keys obj-map-compare-keys) + #(unchecked-get strobj %)) 0))) ICounted (-count [coll] (alength keys)) From e0fb270d64024e88cf260b9fe530aa5b6220e72e Mon Sep 17 00:00:00 2001 From: davidnolen Date: Wed, 30 Jul 2025 16:53:37 -0400 Subject: [PATCH 14/53] - formatting --- src/main/cljs/cljs/core.cljs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/cljs/cljs/core.cljs b/src/main/cljs/cljs/core.cljs index f3cede02f..61474705c 100644 --- a/src/main/cljs/cljs/core.cljs +++ b/src/main/cljs/cljs/core.cljs @@ -12417,7 +12417,7 @@ reduces them without incurring seq initialization" IFind (-find [coll k] (when (and (string? k) - (not (nil? (scan-array 1 k keys)))) + (not (nil? (scan-array 1 k keys)))) (MapEntry. k (unchecked-get strobj k) nil))) IKVReduce From ae604a4e9843bbe8b00f6b18a4b9c653ccc48f32 Mon Sep 17 00:00:00 2001 From: davidnolen Date: Wed, 30 Jul 2025 16:53:58 -0400 Subject: [PATCH 15/53] - formatting --- src/main/cljs/cljs/core.cljs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/main/cljs/cljs/core.cljs b/src/main/cljs/cljs/core.cljs index 61474705c..d8c219302 100644 --- a/src/main/cljs/cljs/core.cljs +++ b/src/main/cljs/cljs/core.cljs @@ -12491,9 +12491,7 @@ reduces them without incurring seq initialization" (-conj [coll entry] (if (vector? entry) (-assoc coll (-nth entry 0) (-nth entry 1)) - (reduce -conj - coll - entry))) + (reduce -conj coll entry))) IEmptyableCollection (-empty [coll] (with-meta (. HashMap -EMPTY) meta)) From f32909773e33942c98720a4e694211e483ca8bea Mon Sep 17 00:00:00 2001 From: davidnolen Date: Wed, 30 Jul 2025 16:54:46 -0400 Subject: [PATCH 16/53] - modernize HashMap --- src/main/cljs/cljs/core.cljs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/main/cljs/cljs/core.cljs b/src/main/cljs/cljs/core.cljs index d8c219302..ea5718b0d 100644 --- a/src/main/cljs/cljs/core.cljs +++ b/src/main/cljs/cljs/core.cljs @@ -12527,7 +12527,7 @@ reduces them without incurring seq initialization" bucket (aget hashobj h)] (if bucket (let [new-bucket (aclone bucket) - new-hashobj (goog.object/clone hashobj)] + new-hashobj (gobject/clone hashobj)] (aset new-hashobj h new-bucket) (if-let [i (scan-array 2 k new-bucket)] (do ; found key, replace @@ -12536,11 +12536,11 @@ reduces them without incurring seq initialization" (do ; did not find key, append (.push new-bucket k v) (HashMap. meta (inc count) new-hashobj nil)))) - (let [new-hashobj (goog.object/clone hashobj)] ; did not find bucket - (aset new-hashobj h (array k v)) + (let [new-hashobj (gobject/clone hashobj)] ; did not find bucket + (unchecked-set new-hashobj h (array k v)) (HashMap. meta (inc count) new-hashobj nil))))) (-contains-key? [coll k] - (let [bucket (aget hashobj (hash k)) + (let [bucket (unchecked-get hashobj (hash k)) i (when bucket (scan-array 2 k bucket))] (if i true @@ -12549,16 +12549,16 @@ reduces them without incurring seq initialization" IMap (-dissoc [coll k] (let [h (hash k) - bucket (aget hashobj h) + bucket (unchecked-get hashobj h) i (when bucket (scan-array 2 k bucket))] (if (not i) coll ; key not found, return coll unchanged - (let [new-hashobj (goog.object/clone hashobj)] - (if (> 3 (.-length bucket)) + (let [new-hashobj (gobject/clone hashobj)] + (if (> 3 (alength bucket)) (js-delete new-hashobj h) (let [new-bucket (aclone bucket)] (.splice new-bucket i 2) - (aset new-hashobj h new-bucket))) + (unchecked-set new-hashobj h new-bucket))) (HashMap. meta (dec count) new-hashobj nil))))) IFn From de3b500c6d8dc3170338035dcdf129170fcd422e Mon Sep 17 00:00:00 2001 From: davidnolen Date: Wed, 30 Jul 2025 17:15:59 -0400 Subject: [PATCH 17/53] - fix bootstrapped --- src/main/clojure/cljs/core.cljc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/clojure/cljs/core.cljc b/src/main/clojure/cljs/core.cljc index de6242553..46445dd31 100644 --- a/src/main/clojure/cljs/core.cljc +++ b/src/main/clojure/cljs/core.cljc @@ -1511,7 +1511,7 @@ ;; Elide all toString methods in :lite-mode (remove (core/fn [[f]] - (and (comp/lite-mode?) (= 'toString f)))) + (core/and (comp/lite-mode?) (core/= 'toString f)))) (map (core/fn [[f & meths :as form]] (core/let [[f meths] (if (vector? (first meths)) From 294073830722f5387ea49e83c5599a78401181e2 Mon Sep 17 00:00:00 2001 From: davidnolen Date: Wed, 30 Jul 2025 17:26:00 -0400 Subject: [PATCH 18/53] LITE_MODE goog-define so we can elide chunked logic from std lib --- src/main/cljs/cljs/core.cljs | 12 ++++++++++-- src/main/clojure/cljs/closure.clj | 4 ++++ 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/src/main/cljs/cljs/core.cljs b/src/main/cljs/cljs/core.cljs index ea5718b0d..7d4cb1f67 100644 --- a/src/main/cljs/cljs/core.cljs +++ b/src/main/cljs/cljs/core.cljs @@ -53,6 +53,11 @@ , and \"global\" supported. "} *global* "default") +(goog-define + ^{:doc "Boolean flag for LITE_MODE" + :jsdoc ["@type {boolean}"]} + LITE_MODE false) + (def ^{:dynamic true :doc "Var bound to the current namespace. Only used for bootstrapping." @@ -2262,7 +2267,10 @@ reduces them without incurring seq initialization" (defn chunked-seq? "Return true if x satisfies IChunkedSeq." - [x] (implements? IChunkedSeq x)) + [x] + (if-not ^boolean LITE_MODE + (implements? IChunkedSeq x) + false)) ;;;;;;;;;;;;;;;;;;;; js primitives ;;;;;;;;;;;; (defn js-obj @@ -12506,7 +12514,7 @@ reduces them without incurring seq initialization" (-seq [coll] (when (pos? count) (let [hashes (.sort (js-keys hashobj))] - (mapcat #(map vec (partition 2 (aget hashobj %))) + (mapcat #(map (fn [[k v]] (MapEntry. k v)) (partition 2 (unchecked-get hashobj %))) hashes)))) ICounted diff --git a/src/main/clojure/cljs/closure.clj b/src/main/clojure/cljs/closure.clj index c0ed3499a..5dc7db1a3 100644 --- a/src/main/clojure/cljs/closure.clj +++ b/src/main/clojure/cljs/closure.clj @@ -2519,6 +2519,10 @@ :cache-analysis-format (:cache-analysis-format opts :transit)) (update-in [:preamble] #(into (or % []) ["cljs/imul.js"]))) + (:lite-mode opts) + (assoc-in [:closure-defines (str (comp/munge 'cljs.core/LITE_MODE))] + (:lite-mode opts)) + (:target opts) (assoc-in [:closure-defines (str (comp/munge 'cljs.core/*target*))] (name (:target opts))) From d1a6b1da9619e03ff87cab59e103efd62e42ea35 Mon Sep 17 00:00:00 2001 From: davidnolen Date: Wed, 30 Jul 2025 18:00:58 -0400 Subject: [PATCH 19/53] fix MapEntry construction --- src/main/cljs/cljs/core.cljs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/main/cljs/cljs/core.cljs b/src/main/cljs/cljs/core.cljs index 7d4cb1f67..5d2becabc 100644 --- a/src/main/cljs/cljs/core.cljs +++ b/src/main/cljs/cljs/core.cljs @@ -12514,7 +12514,7 @@ reduces them without incurring seq initialization" (-seq [coll] (when (pos? count) (let [hashes (.sort (js-keys hashobj))] - (mapcat #(map (fn [[k v]] (MapEntry. k v)) (partition 2 (unchecked-get hashobj %))) + (mapcat #(map (fn [[k v]] (MapEntry. k v nil)) (partition 2 (unchecked-get hashobj %))) hashes)))) ICounted @@ -12588,8 +12588,6 @@ reduces them without incurring seq initialization" (recur (inc i) (assoc out (aget ks i) (aget vs i))) out))))) -;; FIXME: calling this (simple-hash-map) expands the codesize significantly, -;; not clear why at the moment, seems to do less than (hash-map) (defn simple-hash-map "keyval => key val Returns a new hash map with supplied mappings." From fa643f13e9fef2787eafc5a1ca06353eed2b488d Mon Sep 17 00:00:00 2001 From: davidnolen Date: Wed, 30 Jul 2025 18:03:08 -0400 Subject: [PATCH 20/53] ->> to core/->> --- src/main/clojure/cljs/core.cljc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/clojure/cljs/core.cljc b/src/main/clojure/cljs/core.cljc index 46445dd31..eccb58533 100644 --- a/src/main/clojure/cljs/core.cljc +++ b/src/main/clojure/cljs/core.cljc @@ -1507,7 +1507,7 @@ ~@body)))) (core/defn- add-obj-methods [type type-sym sigs] - (->> sigs + (core/->> sigs ;; Elide all toString methods in :lite-mode (remove (core/fn [[f]] From d975d2588e6ace801c7a0015dc73b809a67cf7bc Mon Sep 17 00:00:00 2001 From: davidnolen Date: Wed, 30 Jul 2025 18:35:52 -0400 Subject: [PATCH 21/53] remove call to vec from simple-vector --- src/main/cljs/cljs/core.cljs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/cljs/cljs/core.cljs b/src/main/cljs/cljs/core.cljs index 5d2becabc..66074c9c1 100644 --- a/src/main/cljs/cljs/core.cljs +++ b/src/main/cljs/cljs/core.cljs @@ -12334,7 +12334,7 @@ reduces them without incurring seq initialization" [& args] (if (and (instance? IndexedSeq args) (zero? (.-i args))) (.fromArray Vector (.-arr args) (not (array? (.-arr args)))) - (vec args))) + (Vector. nil (into-array args) nil))) ; The keys field is an array of all keys of this map, in no particular ; order. Any string, keyword, or symbol key is used as a property name From 614d1800a446a36ea2e6963c4f403c396457e066 Mon Sep 17 00:00:00 2001 From: davidnolen Date: Thu, 31 Jul 2025 07:34:15 -0400 Subject: [PATCH 22/53] add simple-vec --- src/main/cljs/cljs/core.cljs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/main/cljs/cljs/core.cljs b/src/main/cljs/cljs/core.cljs index 66074c9c1..68cddcc17 100644 --- a/src/main/cljs/cljs/core.cljs +++ b/src/main/cljs/cljs/core.cljs @@ -12336,6 +12336,21 @@ reduces them without incurring seq initialization" (.fromArray Vector (.-arr args) (not (array? (.-arr args)))) (Vector. nil (into-array args) nil))) +(defn simple-vec + [coll] + (cond + (map-entry? coll) + [(key coll) (val coll)] + + (vector? coll) + (with-meta coll nil) + + (array? coll) + (.fromArray Vector coll) + + :else + (into [] coll))) + ; The keys field is an array of all keys of this map, in no particular ; order. Any string, keyword, or symbol key is used as a property name ; to store the value in strobj. If a key is assoc'ed when that same From 2d34791bf1c110ca4dc48443dd782ef0b57460b3 Mon Sep 17 00:00:00 2001 From: davidnolen Date: Thu, 31 Jul 2025 08:08:00 -0400 Subject: [PATCH 23/53] implement the transient protocols as identity and the standard ops. impossible to respect the O(1) copy contract, but too much of cljs.core relies on the protocol, we have to pretend we support it --- src/main/cljs/cljs/core.cljs | 62 ++++++++++++++++++++++++++++++++++-- 1 file changed, 59 insertions(+), 3 deletions(-) diff --git a/src/main/cljs/cljs/core.cljs b/src/main/cljs/cljs/core.cljs index 68cddcc17..02aad72b7 100644 --- a/src/main/cljs/cljs/core.cljs +++ b/src/main/cljs/cljs/core.cljs @@ -12323,6 +12323,16 @@ reduces them without incurring seq initialization" (-invoke [coll k not-found] (-lookup coll k not-found)) + IEditableCollection + (-as-transient [coll] + coll) + + ITransientCollection + (-conj! [coll val] + (-conj coll val)) + (-persistent! [coll] + coll) + IPrintWithWriter (-pr-writer [coll writer opts] (pr-sequential-writer writer pr-writer "[" " " "]" opts coll))) @@ -12473,9 +12483,23 @@ reduces them without incurring seq initialization" (-invoke [coll k not-found] (-lookup coll k not-found)) - ;IEditableCollection - ;(-as-transient [coll] - ; (transient (into (simple-hash-map) coll))) + IEditableCollection + (-as-transient [coll] + coll) + + ITransientCollection + (-conj! [coll val] + (-conj coll val)) + (-persistent! [coll] + coll) + + ITransientAssociative + (-assoc! [coll key val] + (-assoc coll key val)) + + ITransientMap + (-dissoc! [coll key] + (-dissoc coll key)) IPrintWithWriter (-pr-writer [coll writer opts] @@ -12590,6 +12614,24 @@ reduces them without incurring seq initialization" (-invoke [coll k not-found] (-lookup coll k not-found)) + IEditableCollection + (-as-transient [coll] + coll) + + ITransientCollection + (-conj! [coll val] + (-conj coll val)) + (-persistent! [coll] + coll) + + ITransientAssociative + (-assoc! [coll key val] + (-assoc coll key val)) + + ITransientMap + (-dissoc! [coll key] + (-dissoc coll key)) + IPrintWithWriter (-pr-writer [coll writer opts] (print-map coll pr-writer writer opts))) @@ -12655,6 +12697,20 @@ reduces them without incurring seq initialization" (-disjoin [coll v] (Set. meta (dissoc hash-map v) nil)) + IEditableCollection + (-as-transient [coll] + coll) + + ITransientCollection + (-conj! [coll val] + (-conj coll val)) + (-persistent! [coll] + coll) + + ITransientSet + (-disjoin! [coll key] + (-disjoin coll key)) + IFn (-invoke [coll k] (-lookup coll k)) From f67fb7bc2c3d9eb59e941289cd446fcf93c91627 Mon Sep 17 00:00:00 2001 From: davidnolen Date: Thu, 31 Jul 2025 11:28:54 -0400 Subject: [PATCH 24/53] sketch for vector and vec replace compiler passes --- src/main/cljs/cljs/analyzer/passes/lite.cljc | 28 ++++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 src/main/cljs/cljs/analyzer/passes/lite.cljc diff --git a/src/main/cljs/cljs/analyzer/passes/lite.cljc b/src/main/cljs/cljs/analyzer/passes/lite.cljc new file mode 100644 index 000000000..2abf83271 --- /dev/null +++ b/src/main/cljs/cljs/analyzer/passes/lite.cljc @@ -0,0 +1,28 @@ +;; Copyright (c) Rich Hickey. All rights reserved. +;; The use and distribution terms for this software are covered by the +;; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) +;; which can be found in the file epl-v10.html at the root of this distribution. +;; By using this software in any fashion, you are agreeing to be bound by +;; the terms of this license. +;; You must not remove this notice, or any other, from this software. + +(ns cljs.analyzer.passes.lite) + +(defn var? [ast] + (= :var (:op ast))) + +(def replace + '{cljs.core/vector cljs.core/simple-vector + cljs.core/vec cljs.core/simple-vec}) + +(defn update-var [{:keys [name] :as ast}] + (update-in ast :name (get replace name))) + +(defn replace-var? [ast] + (and (var? ast) + (contains? replace (:name ast)))) + +(defn use-lite-types + [env ast _] + (cond-> ast + (replace-var? ast) update-var)) \ No newline at end of file From d9eb63ea077e4e8e386b789bce002d54d54f17f3 Mon Sep 17 00:00:00 2001 From: davidnolen Date: Thu, 31 Jul 2025 14:24:23 -0400 Subject: [PATCH 25/53] move lite-mode? predicate into the analyzer --- src/main/clojure/cljs/analyzer.cljc | 3 +++ src/main/clojure/cljs/compiler.cljc | 7 ++----- src/main/clojure/cljs/core.cljc | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/main/clojure/cljs/analyzer.cljc b/src/main/clojure/cljs/analyzer.cljc index 709531e59..6e23cb9db 100644 --- a/src/main/clojure/cljs/analyzer.cljc +++ b/src/main/clojure/cljs/analyzer.cljc @@ -492,6 +492,9 @@ (def ^:dynamic *cljs-warning-handlers* [default-warning-handler]) +(defn lite-mode? [] + (get-in @env/*compiler* [:options :lite-mode])) + #?(:clj (defmacro with-warning-handlers [handlers & body] `(binding [*cljs-warning-handlers* ~handlers] diff --git a/src/main/clojure/cljs/compiler.cljc b/src/main/clojure/cljs/compiler.cljc index dcbf11e9e..65f9be5ed 100644 --- a/src/main/clojure/cljs/compiler.cljc +++ b/src/main/clojure/cljs/compiler.cljc @@ -522,9 +522,6 @@ (and (every? #(= (:op %) :const) keys) (= (count (into #{} keys)) (count keys))))) -(defn lite-mode? [] - (get-in @env/*compiler* [:options :lite-mode])) - (defn obj-map-key [x] (if (keyword? x) (str \" "\\uFDD0" \' @@ -570,7 +567,7 @@ (defmethod emit* :map [{:keys [env form keys vals]}] (emit-wrap env - (if (lite-mode?) + (if (ana/lite-mode?) (let [form-keys (clojure.core/keys form)] (if (every? #(or (string? %) (keyword? %)) form-keys) (emit-obj-map (map obj-map-key form-keys) vals comma-sep distinct-keys?) @@ -599,7 +596,7 @@ (defmethod emit* :vector [{:keys [items env]}] (emit-wrap env - (if (lite-mode?) + (if (ana/lite-mode?) (emit-lite-vector items comma-sep) (emit-vector items comma-sep)))) diff --git a/src/main/clojure/cljs/core.cljc b/src/main/clojure/cljs/core.cljc index eccb58533..70ef0d267 100644 --- a/src/main/clojure/cljs/core.cljc +++ b/src/main/clojure/cljs/core.cljc @@ -1511,7 +1511,7 @@ ;; Elide all toString methods in :lite-mode (remove (core/fn [[f]] - (core/and (comp/lite-mode?) (core/= 'toString f)))) + (core/and (ana/lite-mode?) (core/= 'toString f)))) (map (core/fn [[f & meths :as form]] (core/let [[f meths] (if (vector? (first meths)) From 23492aeddb6b024968c752648e0fdb686bfe0a72 Mon Sep 17 00:00:00 2001 From: davidnolen Date: Thu, 31 Jul 2025 14:49:41 -0400 Subject: [PATCH 26/53] fix pass, add lite-mode tests --- src/main/cljs/cljs/analyzer/passes/lite.cljc | 9 +++++---- src/main/clojure/cljs/analyzer.cljc | 8 ++++---- src/test/clojure/cljs/analyzer_pass_tests.clj | 17 +++++++++++++++++ 3 files changed, 26 insertions(+), 8 deletions(-) diff --git a/src/main/cljs/cljs/analyzer/passes/lite.cljc b/src/main/cljs/cljs/analyzer/passes/lite.cljc index 2abf83271..8f8f77b00 100644 --- a/src/main/cljs/cljs/analyzer/passes/lite.cljc +++ b/src/main/cljs/cljs/analyzer/passes/lite.cljc @@ -6,21 +6,22 @@ ;; the terms of this license. ;; You must not remove this notice, or any other, from this software. -(ns cljs.analyzer.passes.lite) +(ns cljs.analyzer.passes.lite + (:refer-clojure :exclude [var?])) (defn var? [ast] (= :var (:op ast))) -(def replace +(def ctor->simple-ctor '{cljs.core/vector cljs.core/simple-vector cljs.core/vec cljs.core/simple-vec}) (defn update-var [{:keys [name] :as ast}] - (update-in ast :name (get replace name))) + (update ast :name ctor->simple-ctor)) (defn replace-var? [ast] (and (var? ast) - (contains? replace (:name ast)))) + (contains? ctor->simple-ctor (:name ast)))) (defn use-lite-types [env ast _] diff --git a/src/main/clojure/cljs/analyzer.cljc b/src/main/clojure/cljs/analyzer.cljc index 6e23cb9db..aaf7085b2 100644 --- a/src/main/clojure/cljs/analyzer.cljc +++ b/src/main/clojure/cljs/analyzer.cljc @@ -16,6 +16,7 @@ #?(:clj (:require [cljs.analyzer.impl :as impl] [cljs.analyzer.impl.namespaces :as nses] [cljs.analyzer.passes.and-or :as and-or] + [cljs.analyzer.passes.lite :as lite] [cljs.env :as env :refer [ensure]] [cljs.externs :as externs] [cljs.js-deps :as deps] @@ -30,6 +31,7 @@ :cljs (:require [cljs.analyzer.impl :as impl] [cljs.analyzer.impl.namespaces :as nses] [cljs.analyzer.passes.and-or :as and-or] + [cljs.analyzer.passes.lite :as lite] [cljs.env :as env] [cljs.reader :as edn] [cljs.tagged-literals :as tags] @@ -4455,10 +4457,8 @@ :cljs [infer-type and-or/optimize check-invoke-arg-types])) (defn analyze* [env form name opts] - (let [passes *passes* - passes (if (nil? passes) - default-passes - passes) + (let [passes (cond-> (or *passes* default-passes) + (lite-mode?) (conj lite/use-lite-types)) form (if (instance? LazySeq form) (if (seq form) form ()) form) diff --git a/src/test/clojure/cljs/analyzer_pass_tests.clj b/src/test/clojure/cljs/analyzer_pass_tests.clj index c87ec7bce..d0d4ba06c 100644 --- a/src/test/clojure/cljs/analyzer_pass_tests.clj +++ b/src/test/clojure/cljs/analyzer_pass_tests.clj @@ -178,8 +178,25 @@ (map (fn [x] x) s))))]))))] (is (empty? (re-seq #"or_" code)))))) +(deftest test-lite-mode-pass + (let [aenv (assoc (ana/empty-env) :context :expr) + env (env/default-compiler-env {:lite-mode true})] + (is (= 'cljs.core/simple-vec + (-> (env/with-compiler-env env + (comp/with-core-cljs {} + (fn [] + (analyze aenv 'cljs.core/vec)))) + :name))) + (is (= 'cljs.core/simple-vector + (-> (env/with-compiler-env env + (comp/with-core-cljs {} + (fn [] + (analyze aenv 'cljs.core/vector)))) + :name))))) + (comment (test/run-tests) (require '[clojure.pprint :refer [pprint]]) + ) From 94c1886ba074b6ad99d3f6b664b4366449a9a82f Mon Sep 17 00:00:00 2001 From: davidnolen Date: Thu, 31 Jul 2025 15:24:45 -0400 Subject: [PATCH 27/53] for fn invokes to be replace we also need to update :info --- src/main/cljs/cljs/analyzer/passes/lite.cljc | 5 ++++- src/test/clojure/cljs/analyzer_pass_tests.clj | 22 ++++++++++--------- 2 files changed, 16 insertions(+), 11 deletions(-) diff --git a/src/main/cljs/cljs/analyzer/passes/lite.cljc b/src/main/cljs/cljs/analyzer/passes/lite.cljc index 8f8f77b00..08a7e03de 100644 --- a/src/main/cljs/cljs/analyzer/passes/lite.cljc +++ b/src/main/cljs/cljs/analyzer/passes/lite.cljc @@ -17,7 +17,10 @@ cljs.core/vec cljs.core/simple-vec}) (defn update-var [{:keys [name] :as ast}] - (update ast :name ctor->simple-ctor)) + (let [replacement (get ctor->simple-ctor name)] + (-> ast + (assoc :name replacement) + (assoc-in [:info :name] replacement)))) (defn replace-var? [ast] (and (var? ast) diff --git a/src/test/clojure/cljs/analyzer_pass_tests.clj b/src/test/clojure/cljs/analyzer_pass_tests.clj index d0d4ba06c..1a451d491 100644 --- a/src/test/clojure/cljs/analyzer_pass_tests.clj +++ b/src/test/clojure/cljs/analyzer_pass_tests.clj @@ -181,18 +181,20 @@ (deftest test-lite-mode-pass (let [aenv (assoc (ana/empty-env) :context :expr) env (env/default-compiler-env {:lite-mode true})] - (is (= 'cljs.core/simple-vec - (-> (env/with-compiler-env env - (comp/with-core-cljs {} - (fn [] - (analyze aenv 'cljs.core/vec)))) - :name))) - (is (= 'cljs.core/simple-vector - (-> (env/with-compiler-env env + (let [ast (env/with-compiler-env env (comp/with-core-cljs {} (fn [] - (analyze aenv 'cljs.core/vector)))) - :name))))) + (analyze aenv 'cljs.core/vec))))] + (is (= 'cljs.core/simple-vec + (-> ast :name) + (-> ast :info :name)))) + (let [ast (env/with-compiler-env env + (comp/with-core-cljs {} + (fn [] + (analyze aenv 'cljs.core/vector))))] + (is (= 'cljs.core/simple-vector + (-> ast :name) + (-> ast :info :name)))))) (comment (test/run-tests) From c31e77c30182fdb3ebb8db56935ae1249b257f3d Mon Sep 17 00:00:00 2001 From: davidnolen Date: Thu, 31 Jul 2025 20:24:45 -0400 Subject: [PATCH 28/53] `vector` is an inlining macro, so can't handle it only as a pass - need to add a case to macro expansion --- src/main/clojure/cljs/analyzer.cljc | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/main/clojure/cljs/analyzer.cljc b/src/main/clojure/cljs/analyzer.cljc index aaf7085b2..87733cf05 100644 --- a/src/main/clojure/cljs/analyzer.cljc +++ b/src/main/clojure/cljs/analyzer.cljc @@ -4077,8 +4077,10 @@ (if (and (some? nsym) (symbol? nsym)) (.findInternedVar ^clojure.lang.Namespace #?(:clj (find-ns nsym) :cljs (find-macros-ns nsym)) sym) - (.findInternedVar ^clojure.lang.Namespace - #?(:clj (find-ns 'cljs.core) :cljs (find-macros-ns impl/CLJS_CORE_MACROS_SYM)) sym))))))) + ;; can't be done as compiler pass because macros get to run first + (when-not (and (lite-mode?) (= 'vector sym)) + (.findInternedVar ^clojure.lang.Namespace + #?(:clj (find-ns 'cljs.core) :cljs (find-macros-ns impl/CLJS_CORE_MACROS_SYM)) sym)))))))) (defn get-expander "Given a sym, a symbol identifying a macro, and env, an analysis environment From 4f4842a61aa711f52cee3d4d9415090c28b32a69 Mon Sep 17 00:00:00 2001 From: davidnolen Date: Thu, 31 Jul 2025 20:35:25 -0400 Subject: [PATCH 29/53] handle sets --- src/main/cljs/cljs/core.cljs | 12 ++++++++++++ src/main/clojure/cljs/compiler.cljc | 9 ++++++++- 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/src/main/cljs/cljs/core.cljs b/src/main/cljs/cljs/core.cljs index 02aad72b7..46329b8ff 100644 --- a/src/main/cljs/cljs/core.cljs +++ b/src/main/cljs/cljs/core.cljs @@ -12721,3 +12721,15 @@ reduces them without incurring seq initialization" (-pr-writer [coll writer opts] (pr-sequential-writer writer pr-writer "#{" " " "}" opts coll))) (set! (. Set -EMPTY) (Set. nil (. HashMap -EMPTY) empty-unordered-hash)) + +(defn simple-set + [coll] + (if (set? coll) + (with-meta coll nil) + (let [in (seq coll)] + (if (nil? in) + #{} + (loop [in in out (. Set -EMPTY)] + (if-not (nil? in) + (recur (next in) (conj out (first in))) + out)))))) diff --git a/src/main/clojure/cljs/compiler.cljc b/src/main/clojure/cljs/compiler.cljc index 65f9be5ed..ce90f1f34 100644 --- a/src/main/clojure/cljs/compiler.cljc +++ b/src/main/clojure/cljs/compiler.cljc @@ -616,10 +616,17 @@ :else (emits "cljs.core.PersistentHashSet.createAsIfByAssoc([" (comma-sep items) "])"))) +(defn emit-lite-set [items comma-sep distinct-constants?] + (if (empty? items) + (emits "cljs.core.Set.EMPTY") + (emits "cljs.core.simple_set([" (comma-sep items) "])"))) + (defmethod emit* :set [{:keys [items env]}] (emit-wrap env - (emit-set items comma-sep distinct-constants?))) + (if (ana/lite-mode?) + (emit-lite-set items comma-sep distinct-constants?) + (emit-set items comma-sep distinct-constants?)))) (defn emit-js-object [items emit-js-object-val] (emits "({") From 5873009542956caa8cdc1cf2618f97892a3799b6 Mon Sep 17 00:00:00 2001 From: davidnolen Date: Thu, 31 Jul 2025 22:41:26 -0400 Subject: [PATCH 30/53] avoid lazyseq stuff in HashMap impl --- src/main/cljs/cljs/core.cljs | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/src/main/cljs/cljs/core.cljs b/src/main/cljs/cljs/core.cljs index 46329b8ff..2cf7a10fd 100644 --- a/src/main/cljs/cljs/core.cljs +++ b/src/main/cljs/cljs/core.cljs @@ -12552,9 +12552,20 @@ reduces them without incurring seq initialization" ISeqable (-seq [coll] (when (pos? count) - (let [hashes (.sort (js-keys hashobj))] - (mapcat #(map (fn [[k v]] (MapEntry. k v nil)) (partition 2 (unchecked-get hashobj %))) - hashes)))) + (let [hashes (.sort (js-keys hashobj)) + cnt (alength hashes) + arr (array)] + (loop [i 0] + (if (< i cnt) + (let [bckt (unchecked-get hashobj (aget hashes i)) + len (alength bkt)] + (loop [j 0] + (when (< j len) + (do + (.push arr (MapEntry. (aget bkt j) (aget bkt (inc j)) nil)) + (recur (+ j 2))))) + (recur (inc i))) + (prim-seq arr)))))) ICounted (-count [coll] count) From 9a2c2e86df593a3329f7e90c896b29fdb9d3acc1 Mon Sep 17 00:00:00 2001 From: davidnolen Date: Thu, 31 Jul 2025 23:07:54 -0400 Subject: [PATCH 31/53] typos --- src/main/cljs/cljs/core.cljs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/cljs/cljs/core.cljs b/src/main/cljs/cljs/core.cljs index 2cf7a10fd..60937b3d8 100644 --- a/src/main/cljs/cljs/core.cljs +++ b/src/main/cljs/cljs/core.cljs @@ -12414,7 +12414,7 @@ reduces them without incurring seq initialization" (when (pos? (alength keys)) (prim-seq (.map (.sort keys obj-map-compare-keys) - #(unchecked-get strobj %)) 0))) + #(MapEntry. % (unchecked-get strobj %)))))) ICounted (-count [coll] (alength keys)) @@ -12558,11 +12558,11 @@ reduces them without incurring seq initialization" (loop [i 0] (if (< i cnt) (let [bckt (unchecked-get hashobj (aget hashes i)) - len (alength bkt)] + len (alength bckt)] (loop [j 0] (when (< j len) (do - (.push arr (MapEntry. (aget bkt j) (aget bkt (inc j)) nil)) + (.push arr (MapEntry. (aget bckt j) (aget bckt (inc j)) nil)) (recur (+ j 2))))) (recur (inc i))) (prim-seq arr)))))) From c81817a31f839e476eee40ab9d3ee512c52e03ff Mon Sep 17 00:00:00 2001 From: davidnolen Date: Thu, 31 Jul 2025 23:17:19 -0400 Subject: [PATCH 32/53] avoid full blown map entry --- src/main/cljs/cljs/core.cljs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/main/cljs/cljs/core.cljs b/src/main/cljs/cljs/core.cljs index 60937b3d8..01110b0f3 100644 --- a/src/main/cljs/cljs/core.cljs +++ b/src/main/cljs/cljs/core.cljs @@ -10383,7 +10383,7 @@ reduces them without incurring seq initialization" (implements? IMeta obj) (not (nil? (meta obj))))) -(defn- pr-map-entry [k v] +(defn- simple-map-entry [k v] (reify IMapEntry (-key [_] k) @@ -10429,7 +10429,7 @@ reduces them without incurring seq initialization" (.map (js-keys obj) (fn [k] - (pr-map-entry + (simple-map-entry (cond-> k (some? (.match k #"^[A-Za-z_\*\+\?!\-'][\w\*\+\?!\-']*$")) keyword) (unchecked-get obj k)))) pr-writer writer opts)) @@ -10610,10 +10610,10 @@ reduces them without incurring seq initialization" (when (or (keyword? k) (symbol? k)) (if ns (when (= ns (namespace k)) - (.push lm (pr-map-entry (strip-ns k) v)) + (.push lm (simple-map-entry (strip-ns k) v)) (recur ns entries)) (when-let [new-ns (namespace k)] - (.push lm (pr-map-entry (strip-ns k) v)) + (.push lm (simple-map-entry (strip-ns k) v)) (recur new-ns entries)))) #js [ns lm]))))) @@ -12414,7 +12414,7 @@ reduces them without incurring seq initialization" (when (pos? (alength keys)) (prim-seq (.map (.sort keys obj-map-compare-keys) - #(MapEntry. % (unchecked-get strobj %)))))) + #(simple-map-entry % (unchecked-get strobj %)))))) ICounted (-count [coll] (alength keys)) @@ -12562,7 +12562,7 @@ reduces them without incurring seq initialization" (loop [j 0] (when (< j len) (do - (.push arr (MapEntry. (aget bckt j) (aget bckt (inc j)) nil)) + (.push arr (simple-map-entry (aget bckt j) (aget bckt (inc j)) nil)) (recur (+ j 2))))) (recur (inc i))) (prim-seq arr)))))) From 6ce216c258bd5f0280e58dc9316c3cd17e430dd0 Mon Sep 17 00:00:00 2001 From: davidnolen Date: Thu, 31 Jul 2025 23:33:34 -0400 Subject: [PATCH 33/53] - more std-lib avoidance, micro sizing opts - fix str keys --- src/main/cljs/cljs/core.cljs | 22 +++++++++++----------- src/main/clojure/cljs/compiler.cljc | 2 +- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/main/cljs/cljs/core.cljs b/src/main/cljs/cljs/core.cljs index 01110b0f3..9318067d0 100644 --- a/src/main/cljs/cljs/core.cljs +++ b/src/main/cljs/cljs/core.cljs @@ -12401,7 +12401,7 @@ reduces them without incurring seq initialization" (reduce -conj coll entry))) IEmptyableCollection - (-empty [coll] (with-meta (. ObjMap -EMPTY) meta)) + (-empty [coll] (-with-meta (. ObjMap -EMPTY) meta)) IEquiv (-equiv [coll other] (equiv-map coll other)) @@ -12433,14 +12433,14 @@ reduces them without incurring seq initialization" (if-not (nil? (scan-array 1 k keys)) (let [new-strobj (obj-clone strobj keys)] (gobject/set new-strobj k v) - (ObjMap. meta keys new-strobj nil)) ; overwrite - (let [new-strobj (obj-clone strobj keys) ; append - new-keys (aclone keys)] + (ObjMap. meta keys new-strobj nil)) ; overwrite + (let [new-strobj (obj-clone strobj keys) ; append + new-keys (aclone keys)] (gobject/set new-strobj k v) (.push new-keys k) (ObjMap. meta new-keys new-strobj nil))) ; non-string key. game over. - (with-meta (into (simple-hash-map k v) (seq coll)) meta))) + (-with-meta (apply simple-hash-map k v (-seq coll)) meta))) (-contains-key? [coll k] (if (and (string? k) (not (nil? (scan-array 1 k keys)))) @@ -12662,7 +12662,7 @@ reduces them without incurring seq initialization" [& keyvals] (loop [in (seq keyvals), out (. HashMap -EMPTY)] (if in - (recur (nnext in) (assoc out (first in) (second in))) + (recur (nnext in) (-assoc out (first in) (second in))) out))) (deftype Set [meta hash-map ^:mutable __hash] @@ -12683,7 +12683,7 @@ reduces them without incurring seq initialization" (-equiv [coll other] (and (set? other) - (= (count coll) (count other)) + (= (-count coll) (count other)) (every? #(contains? coll %) other))) @@ -12694,7 +12694,7 @@ reduces them without incurring seq initialization" (-seq [coll] (keys hash-map)) ICounted - (-count [coll] (count (seq coll))) + (-count [coll] (-count (-seq coll))) ILookup (-lookup [coll v] @@ -12706,7 +12706,7 @@ reduces them without incurring seq initialization" ISet (-disjoin [coll v] - (Set. meta (dissoc hash-map v) nil)) + (Set. meta (-dissoc hash-map v) nil)) IEditableCollection (-as-transient [coll] @@ -12736,11 +12736,11 @@ reduces them without incurring seq initialization" (defn simple-set [coll] (if (set? coll) - (with-meta coll nil) + (-with-meta coll nil) (let [in (seq coll)] (if (nil? in) #{} (loop [in in out (. Set -EMPTY)] (if-not (nil? in) - (recur (next in) (conj out (first in))) + (recur (next in) (-conj out (first in))) out)))))) diff --git a/src/main/clojure/cljs/compiler.cljc b/src/main/clojure/cljs/compiler.cljc index ce90f1f34..faba462b5 100644 --- a/src/main/clojure/cljs/compiler.cljc +++ b/src/main/clojure/cljs/compiler.cljc @@ -529,7 +529,7 @@ (str (namespace x) "/") "") (name x) \") - x)) + (str \" x \"))) (defn emit-obj-map [str-keys vals comma-sep distinct-keys?] (if (zero? (count str-keys)) From a2373cb009305293a9b81451c6d0b5d500de5765 Mon Sep 17 00:00:00 2001 From: davidnolen Date: Fri, 1 Aug 2025 00:12:07 -0400 Subject: [PATCH 34/53] - use kv-reduce to save some more space --- src/main/cljs/cljs/core.cljs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/main/cljs/cljs/core.cljs b/src/main/cljs/cljs/core.cljs index 9318067d0..9945154d7 100644 --- a/src/main/cljs/cljs/core.cljs +++ b/src/main/cljs/cljs/core.cljs @@ -12440,7 +12440,12 @@ reduces them without incurring seq initialization" (.push new-keys k) (ObjMap. meta new-keys new-strobj nil))) ; non-string key. game over. - (-with-meta (apply simple-hash-map k v (-seq coll)) meta))) + (-with-meta + (-kv-reduce coll + (fn [ret k v] + (-assoc ret k v)) + (. HashMap -EMPTY) ) + meta))) (-contains-key? [coll k] (if (and (string? k) (not (nil? (scan-array 1 k keys)))) From 1967067540c6b7c60a1b04f8b3753d7ca8290f8d Mon Sep 17 00:00:00 2001 From: davidnolen Date: Fri, 1 Aug 2025 00:13:01 -0400 Subject: [PATCH 35/53] - formatting --- src/main/cljs/cljs/core.cljs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/cljs/cljs/core.cljs b/src/main/cljs/cljs/core.cljs index 9945154d7..e9734a585 100644 --- a/src/main/cljs/cljs/core.cljs +++ b/src/main/cljs/cljs/core.cljs @@ -12433,8 +12433,8 @@ reduces them without incurring seq initialization" (if-not (nil? (scan-array 1 k keys)) (let [new-strobj (obj-clone strobj keys)] (gobject/set new-strobj k v) - (ObjMap. meta keys new-strobj nil)) ; overwrite - (let [new-strobj (obj-clone strobj keys) ; append + (ObjMap. meta keys new-strobj nil)) ;overwrite + (let [new-strobj (obj-clone strobj keys) ; append new-keys (aclone keys)] (gobject/set new-strobj k v) (.push new-keys k) From 67ee02bcdbc0f092e8724736067cedbd71a03568 Mon Sep 17 00:00:00 2001 From: David Nolen Date: Sat, 2 Aug 2025 22:21:41 -0400 Subject: [PATCH 36/53] - before core fns knew about the ObjMap key rep - now it needs to be an internal detail - testing stuff wip --- resources/lite_test.edn | 10 +++ src/main/cljs/cljs/core.cljs | 87 ++++++++++--------- src/test/cljs/cljs/lite_collections_test.cljs | 11 +++ src/test/cljs/lite_test_runner.cljs | 21 +++++ 4 files changed, 90 insertions(+), 39 deletions(-) create mode 100644 resources/lite_test.edn create mode 100644 src/test/cljs/cljs/lite_collections_test.cljs create mode 100644 src/test/cljs/lite_test_runner.cljs diff --git a/resources/lite_test.edn b/resources/lite_test.edn new file mode 100644 index 000000000..5b4520dde --- /dev/null +++ b/resources/lite_test.edn @@ -0,0 +1,10 @@ +{:optimizations :advanced + :main lite-test-runner + :output-to "builds/out-lite/lite-test.js" + :output-dir "builds/out-lite" + :output-wrapper true + :verbose true + :compiler-stats true + :parallel-build true + :closure-warnings {:non-standard-jsdoc :off :global-this :off} + :language-out :es5} diff --git a/src/main/cljs/cljs/core.cljs b/src/main/cljs/cljs/core.cljs index e9734a585..316a5c8e1 100644 --- a/src/main/cljs/cljs/core.cljs +++ b/src/main/cljs/cljs/core.cljs @@ -12371,9 +12371,9 @@ reduces them without incurring seq initialization" (let [a (hash a) b (hash b)] (cond - (< a b) -1 - (> a b) 1 - :else 0))) + (< a b) -1 + (> a b) 1 + :else 0))) (defn- obj-clone [obj ks] (let [new-obj (js-obj) @@ -12387,6 +12387,10 @@ reduces them without incurring seq initialization" (declare simple-hash-map) +(defn- keyword->obj-map-key + [k] + (str "\uFDD0" "'" (. k -fqn))) + (deftype ObjMap [meta keys strobj ^:mutable __hash] IWithMeta (-with-meta [coll meta] (ObjMap. meta keys strobj __hash)) @@ -12422,41 +12426,45 @@ reduces them without incurring seq initialization" ILookup (-lookup [coll k] (-lookup coll k nil)) (-lookup [coll k not-found] - (if (and (string? k) - (not (nil? (scan-array 1 k keys)))) - (unchecked-get strobj k) - not-found)) + (let [k (if-not (keyword? k) k (keyword->obj-map-key k))] + (if (and (string? k) + (not (nil? (scan-array 1 k keys)))) + (unchecked-get strobj k) + not-found))) IAssociative (-assoc [coll k v] - (if (string? k) - (if-not (nil? (scan-array 1 k keys)) - (let [new-strobj (obj-clone strobj keys)] - (gobject/set new-strobj k v) - (ObjMap. meta keys new-strobj nil)) ;overwrite - (let [new-strobj (obj-clone strobj keys) ; append - new-keys (aclone keys)] - (gobject/set new-strobj k v) - (.push new-keys k) - (ObjMap. meta new-keys new-strobj nil))) - ; non-string key. game over. - (-with-meta - (-kv-reduce coll - (fn [ret k v] - (-assoc ret k v)) - (. HashMap -EMPTY) ) - meta))) + (let [k (if-not (keyword? k) k (keyword->obj-map-key k))] + (if (string? k) + (if-not (nil? (scan-array 1 k keys)) + (let [new-strobj (obj-clone strobj keys)] + (gobject/set new-strobj k v) + (ObjMap. meta keys new-strobj nil)) ;overwrite + (let [new-strobj (obj-clone strobj keys) ; append + new-keys (aclone keys)] + (gobject/set new-strobj k v) + (.push new-keys k) + (ObjMap. meta new-keys new-strobj nil))) + ; non-string key. game over. + (-with-meta + (-kv-reduce coll + (fn [ret k v] + (-assoc ret k v)) + (. HashMap -EMPTY)) + meta)))) (-contains-key? [coll k] - (if (and (string? k) - (not (nil? (scan-array 1 k keys)))) - true - false)) + (let [k (if-not (keyword? k) k (keyword->obj-map-key k))] + (if (and (string? k) + (not (nil? (scan-array 1 k keys)))) + true + false))) IFind (-find [coll k] - (when (and (string? k) - (not (nil? (scan-array 1 k keys)))) - (MapEntry. k (unchecked-get strobj k) nil))) + (let [k (if-not (keyword? k) k (keyword->obj-map-key k))] + (when (and (string? k) + (not (nil? (scan-array 1 k keys)))) + (MapEntry. k (unchecked-get strobj k) nil)))) IKVReduce (-kv-reduce [coll f init] @@ -12473,14 +12481,15 @@ reduces them without incurring seq initialization" IMap (-dissoc [coll k] - (if (and (string? k) - (not (nil? (scan-array 1 k keys)))) - (let [new-keys (aclone keys) - new-strobj (obj-clone strobj keys)] - (.splice new-keys (scan-array 1 k new-keys) 1) - (js-delete new-strobj k) - (ObjMap. meta new-keys new-strobj nil)) - coll)) ; key not found, return coll unchanged + (let [k (if-not (keyword? k) k (keyword->obj-map-key k))] + (if (and (string? k) + (not (nil? (scan-array 1 k keys)))) + (let [new-keys (aclone keys) + new-strobj (obj-clone strobj keys)] + (.splice new-keys (scan-array 1 k new-keys) 1) + (js-delete new-strobj k) + (ObjMap. meta new-keys new-strobj nil)) + coll))) ; key not found, return coll unchanged IFn (-invoke [coll k] diff --git a/src/test/cljs/cljs/lite_collections_test.cljs b/src/test/cljs/cljs/lite_collections_test.cljs new file mode 100644 index 000000000..9545f7f07 --- /dev/null +++ b/src/test/cljs/cljs/lite_collections_test.cljs @@ -0,0 +1,11 @@ +; Copyright (c) Rich Hickey. All rights reserved. +; The use and distribution terms for this software are covered by the +; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) +; which can be found in the file epl-v10.html at the root of this distribution. +; By using this software in any fashion, you are agreeing to be bound by +; the terms of this license. +; You must not remove this notice, or any other, from this software. + +(ns cljs.lite-collections-test + (:require [cljs.test :refer-macros [deftest testing is are run-tests]] + [clojure.test.check.clojure-test :refer-macros [defspec]])) \ No newline at end of file diff --git a/src/test/cljs/lite_test_runner.cljs b/src/test/cljs/lite_test_runner.cljs new file mode 100644 index 000000000..4869410ef --- /dev/null +++ b/src/test/cljs/lite_test_runner.cljs @@ -0,0 +1,21 @@ +;; Copyright (c) Rich Hickey. All rights reserved. +;; The use and distribution terms for this software are covered by the +;; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) +;; which can be found in the file epl-v10.html at the root of this distribution. +;; By using this software in any fashion, you are agreeing to be bound by +;; the terms of this license. +;; You must not remove this notice, or any other, from this software. + +(ns lite-test-runner + (:require [cljs.lite-collections-test])) + +(set! *print-newline* false) + +;; When testing Windows we default to Node.js +(if (exists? js/print) + (set-print-fn! js/print) + (enable-console-print!)) + +(run-tests + 'cljs.collections-test + ) From 28f513352603720a068e22e9955eabd7caf1960c Mon Sep 17 00:00:00 2001 From: David Nolen Date: Sun, 3 Aug 2025 07:04:29 -0400 Subject: [PATCH 37/53] - lite testing wip --- deps.edn | 2 ++ resources/lite_test.edn | 21 +++++++++++-------- src/test/cljs/cljs/lite_collections_test.cljs | 10 +++++++-- src/test/cljs/lite_test_runner.cljs | 5 +++-- 4 files changed, 25 insertions(+), 13 deletions(-) diff --git a/deps.edn b/deps.edn index 012e22069..e3a236c2a 100644 --- a/deps.edn +++ b/deps.edn @@ -19,6 +19,8 @@ "-e" "(cljs.test-runner/-main)"]} :runtime.test.build {:extra-paths ["src/test/cljs"] :main-opts ["-m" "cljs.main" "-co" "resources/test.edn" "-c"]} + :lite.test.build {:extra-paths ["src/test/cljs"] + :main-opts ["-m" "cljs.main" "-co" "resources/lite_test.edn" "-c"]} :selfhost.test.build {:extra-paths ["src/test/self"] :main-opts ["-m" "cljs.main" "-co" "resources/self_host_test.edn" "-c"]} :selfparity.test.build {:extra-paths ["src/test/self"] diff --git a/resources/lite_test.edn b/resources/lite_test.edn index 5b4520dde..11b3d3f9f 100644 --- a/resources/lite_test.edn +++ b/resources/lite_test.edn @@ -1,10 +1,13 @@ -{:optimizations :advanced - :main lite-test-runner - :output-to "builds/out-lite/lite-test.js" - :output-dir "builds/out-lite" - :output-wrapper true - :verbose true - :compiler-stats true - :parallel-build true +{:optimizations :advanced + :main lite-test-runner + :lite-mode true + :output-to "builds/out-lite/lite-test.js" + :output-dir "builds/out-lite" + :output-wrapper true + :verbose true + :compiler-stats true + :parallel-build true :closure-warnings {:non-standard-jsdoc :off :global-this :off} - :language-out :es5} + :language-out :es5 + :pseudo-names true + :pretty-print true} diff --git a/src/test/cljs/cljs/lite_collections_test.cljs b/src/test/cljs/cljs/lite_collections_test.cljs index 9545f7f07..474099617 100644 --- a/src/test/cljs/cljs/lite_collections_test.cljs +++ b/src/test/cljs/cljs/lite_collections_test.cljs @@ -7,5 +7,11 @@ ; You must not remove this notice, or any other, from this software. (ns cljs.lite-collections-test - (:require [cljs.test :refer-macros [deftest testing is are run-tests]] - [clojure.test.check.clojure-test :refer-macros [defspec]])) \ No newline at end of file + (:require [cljs.test :refer-macros [deftest testing is are run-tests]])) + +;; NOTE: ** this name space must be tested with :lite-mode true ** + +(deftest test-obj-map + (let [a (. ObjMap -EMPTY) + b {}] + (is (identical? a b)))) \ No newline at end of file diff --git a/src/test/cljs/lite_test_runner.cljs b/src/test/cljs/lite_test_runner.cljs index 4869410ef..baa7b0435 100644 --- a/src/test/cljs/lite_test_runner.cljs +++ b/src/test/cljs/lite_test_runner.cljs @@ -7,7 +7,8 @@ ;; You must not remove this notice, or any other, from this software. (ns lite-test-runner - (:require [cljs.lite-collections-test])) + (:require [cljs.test :refer-macros [run-tests]] + [cljs.lite-collections-test])) (set! *print-newline* false) @@ -17,5 +18,5 @@ (enable-console-print!)) (run-tests - 'cljs.collections-test + 'cljs.lite-collections-test ) From c447abb904df64742f6690baf84b44fd73c9db15 Mon Sep 17 00:00:00 2001 From: David Nolen Date: Sun, 3 Aug 2025 07:05:02 -0400 Subject: [PATCH 38/53] - cannot pass arrays to ci-reduce, use array-reduce --- src/main/cljs/cljs/core.cljs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/cljs/cljs/core.cljs b/src/main/cljs/cljs/core.cljs index 316a5c8e1..817fb0914 100644 --- a/src/main/cljs/cljs/core.cljs +++ b/src/main/cljs/cljs/core.cljs @@ -12313,9 +12313,9 @@ reduces them without incurring seq initialization" IReduce (-reduce [v f] - (ci-reduce array f)) + (array-reduce array f)) (-reduce [v f start] - (ci-reduce array f start)) + (array-reduce array f start)) IFn (-invoke [coll k] From 8246266503a04552b5d6a12f7347036af8b99253 Mon Sep 17 00:00:00 2001 From: David Nolen Date: Sun, 3 Aug 2025 07:16:01 -0400 Subject: [PATCH 39/53] - fix simple-map-entryff call --- src/main/cljs/cljs/core.cljs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/cljs/cljs/core.cljs b/src/main/cljs/cljs/core.cljs index 817fb0914..8ee9dfef5 100644 --- a/src/main/cljs/cljs/core.cljs +++ b/src/main/cljs/cljs/core.cljs @@ -12576,7 +12576,7 @@ reduces them without incurring seq initialization" (loop [j 0] (when (< j len) (do - (.push arr (simple-map-entry (aget bckt j) (aget bckt (inc j)) nil)) + (.push arr (simple-map-entry (aget bckt j) (aget bckt (inc j)))) (recur (+ j 2))))) (recur (inc i))) (prim-seq arr)))))) From 73c5b89f1c7a05de6a12332c6ceee5838c985922 Mon Sep 17 00:00:00 2001 From: David Nolen Date: Sun, 3 Aug 2025 07:30:11 -0400 Subject: [PATCH 40/53] - missing declare --- src/main/cljs/cljs/core.cljs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/cljs/cljs/core.cljs b/src/main/cljs/cljs/core.cljs index 8ee9dfef5..8fbc47423 100644 --- a/src/main/cljs/cljs/core.cljs +++ b/src/main/cljs/cljs/core.cljs @@ -12385,7 +12385,7 @@ reduces them without incurring seq initialization" (recur (inc i))))) new-obj)) -(declare simple-hash-map) +(declare simple-hash-map HashMap) (defn- keyword->obj-map-key [k] From 393a5941d0df2b6aa5422d8a0c827af3f83a2983 Mon Sep 17 00:00:00 2001 From: David Nolen Date: Sun, 3 Aug 2025 07:55:55 -0400 Subject: [PATCH 41/53] - simple-map-entry needs to satisfy IVector and IIndexed --- src/main/cljs/cljs/core.cljs | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/main/cljs/cljs/core.cljs b/src/main/cljs/cljs/core.cljs index 8fbc47423..e40cf12ab 100644 --- a/src/main/cljs/cljs/core.cljs +++ b/src/main/cljs/cljs/core.cljs @@ -10385,11 +10385,22 @@ reduces them without incurring seq initialization" (defn- simple-map-entry [k v] (reify + IVector + (-assoc-n [_ n x] + (case n + 0 (simple-map-entry x v) + 1 (simple-map-entry k x) + (throw (js/Error. "Index out of bounds")))) IMapEntry (-key [_] k) (-val [_] v) ISeqable - (-seq [_] (IndexedSeq. #js [k v] 0 nil)))) + (-seq [_] (IndexedSeq. #js [k v] 0 nil)) + IIndexed + (-nth [_ i] + (case i, 0 k, 1 v, (throw (js/Error. "Index out of bounds")))) + (-nth [_ i not-found] + (case i, 0 k, 1 v, not-found)))) (defn- pr-writer-impl [obj writer opts] From 8eae3806ed70e5bf0cad84f46b4afdffe034b009 Mon Sep 17 00:00:00 2001 From: David Nolen Date: Sun, 3 Aug 2025 20:31:30 -0400 Subject: [PATCH 42/53] - remove doseq from printing - don't leak internal key rep from ObjMap --- src/main/cljs/cljs/core.cljs | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/src/main/cljs/cljs/core.cljs b/src/main/cljs/cljs/core.cljs index e40cf12ab..1373516ba 100644 --- a/src/main/cljs/cljs/core.cljs +++ b/src/main/cljs/cljs/core.cljs @@ -10347,8 +10347,10 @@ reduces them without incurring seq initialization" (-write writer end))))) (defn write-all [writer & ss] - (doseq [s ss] - (-write writer s))) + (loop [ss (seq ss)] + (when-not (nil? ss) + (-write writer (first ss)) + (recur (next ss))))) (defn string-print [x] (when (nil? *print-fn*) @@ -10509,9 +10511,11 @@ reduces them without incurring seq initialization" (defn pr-seq-writer [objs writer opts] (pr-writer (first objs) writer opts) - (doseq [obj (next objs)] - (-write writer " ") - (pr-writer obj writer opts))) + (loop [objs (next objs)] + (when-not (nil? objs) + (-write writer " ") + (pr-writer (first objs) writer opts) + (recur (next objs))))) (defn- pr-sb-with-opts [objs opts] (let [sb (StringBuffer.) @@ -12402,6 +12406,12 @@ reduces them without incurring seq initialization" [k] (str "\uFDD0" "'" (. k -fqn))) +(defn- obj-map-key->keyword + [k] + (if (.startsWith k "\uFDD0") + (keyword (.substring k 2 (. k -length))) + k)) + (deftype ObjMap [meta keys strobj ^:mutable __hash] IWithMeta (-with-meta [coll meta] (ObjMap. meta keys strobj __hash)) @@ -12429,7 +12439,7 @@ reduces them without incurring seq initialization" (when (pos? (alength keys)) (prim-seq (.map (.sort keys obj-map-compare-keys) - #(simple-map-entry % (unchecked-get strobj %)))))) + #(simple-map-entry (obj-map-key->keyword %) (unchecked-get strobj %)))))) ICounted (-count [coll] (alength keys)) @@ -12484,7 +12494,7 @@ reduces them without incurring seq initialization" init init] (if (seq keys) (let [k (first keys) - init (f init k (unchecked-get strobj k))] + init (f init (obj-map-key->keyword k) (unchecked-get strobj k))] (if (reduced? init) @init (recur (rest keys) init))) @@ -12494,7 +12504,7 @@ reduces them without incurring seq initialization" (-dissoc [coll k] (let [k (if-not (keyword? k) k (keyword->obj-map-key k))] (if (and (string? k) - (not (nil? (scan-array 1 k keys)))) + (not (nil? (scan-array 1 k keys)))) (let [new-keys (aclone keys) new-strobj (obj-clone strobj keys)] (.splice new-keys (scan-array 1 k new-keys) 1) From 5611cd503723b0a8e6f7b42e89eb854cb98afda5 Mon Sep 17 00:00:00 2001 From: David Nolen Date: Sun, 3 Aug 2025 21:09:00 -0400 Subject: [PATCH 43/53] - obj-map is definitely incomplete, but fix the obvious problem now --- src/main/cljs/cljs/core.cljs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/main/cljs/cljs/core.cljs b/src/main/cljs/cljs/core.cljs index 1373516ba..063bb4b25 100644 --- a/src/main/cljs/cljs/core.cljs +++ b/src/main/cljs/cljs/core.cljs @@ -12552,9 +12552,10 @@ reduces them without incurring seq initialization" obj (js-obj)] (loop [kvs (seq keyvals)] (if kvs - (do (.push ks (first kvs)) - (gobject/set obj (first kvs) (second kvs)) - (recur (nnext kvs))) + (let [k (-> kvs first keyword->obj-map-key)] + (.push ks k) + (gobject/set obj k (second kvs)) + (recur (nnext kvs))) (.fromObject ObjMap ks obj))))) ; The keys field is an array of all keys of this map, in no particular From e4bc146ca3e70bc4f9cbf06e56076f5a93554a59 Mon Sep 17 00:00:00 2001 From: David Nolen Date: Mon, 4 Aug 2025 08:30:14 -0400 Subject: [PATCH 44/53] - simple-map-entry IEquiv --- src/main/cljs/cljs/core.cljs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/cljs/cljs/core.cljs b/src/main/cljs/cljs/core.cljs index 063bb4b25..f2fd26dbf 100644 --- a/src/main/cljs/cljs/core.cljs +++ b/src/main/cljs/cljs/core.cljs @@ -10387,6 +10387,8 @@ reduces them without incurring seq initialization" (defn- simple-map-entry [k v] (reify + IEquiv + (-equiv [coll other] (equiv-sequential coll other)) IVector (-assoc-n [_ n x] (case n From dadba060eee2bd3752d69debb04ecdcd84598b37 Mon Sep 17 00:00:00 2001 From: David Nolen Date: Mon, 4 Aug 2025 08:30:53 -0400 Subject: [PATCH 45/53] - test-obj-map in collections test - cleanup ns form --- src/test/cljs/cljs/collections_test.cljs | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/src/test/cljs/cljs/collections_test.cljs b/src/test/cljs/cljs/collections_test.cljs index 44d5e3f46..6027a3acf 100644 --- a/src/test/cljs/cljs/collections_test.cljs +++ b/src/test/cljs/cljs/collections_test.cljs @@ -9,12 +9,9 @@ (ns cljs.collections-test (:refer-clojure :exclude [iter]) (:require [cljs.test :refer-macros [deftest testing is are run-tests]] - [clojure.test.check :as tc] [clojure.test.check.clojure-test :refer-macros [defspec]] [clojure.test.check.generators :as gen] - [clojure.test.check.properties :as prop :include-macros true] - [clojure.string :as s] - [clojure.set :as set])) + [clojure.test.check.properties :as prop :include-macros true])) (deftest test-map-operations (testing "Test basic map collection operations" @@ -1157,6 +1154,22 @@ (let [things (zipmap (range 15000) (repeat 0))] (is (zero? (count (filter #(-> % key string?) things)))))) +(deftest test-obj-map + (let [a (obj-map)] + (is (empty? a)) + (is (zero? (count a)))) + (let [b (obj-map :a 1)] + (is (not (empty? b))) + (is (== 1 (count b)))) + (let [c (obj-map :a 1 :b 2 :c 3)] + (is (== 3 (count c))) + (is (= 1 (get c :a))) + (is (= 1 (:a c))) + (is (every? keyword? (keys c))) + (is (= (set [:a :b :c]) (set (keys c))))) + (is (= (obj-map :a 1 :b 2 :c 3) + (obj-map :a 1 :b 2 :c 3)))) + (comment (run-tests) From 2b4a93739023d9989596924f0c0664a90288f289 Mon Sep 17 00:00:00 2001 From: David Nolen Date: Mon, 4 Aug 2025 23:17:13 -0400 Subject: [PATCH 46/53] - fix up HashMap issues --- src/main/cljs/cljs/core.cljs | 47 +++++++++++++++++++++--------------- 1 file changed, 28 insertions(+), 19 deletions(-) diff --git a/src/main/cljs/cljs/core.cljs b/src/main/cljs/cljs/core.cljs index f2fd26dbf..d31f5ec9f 100644 --- a/src/main/cljs/cljs/core.cljs +++ b/src/main/cljs/cljs/core.cljs @@ -6560,15 +6560,6 @@ reduces them without incurring seq initialization" (= (get y (first xkv) never-equiv) (second xkv))) x)))))) - -(defn- scan-array [incr k array] - (let [len (alength array)] - (loop [i 0] - (when (< i len) - (if (identical? k (aget array i)) - i - (recur (+ i incr))))))) - ;; Record Iterator (deftype RecordIter [^:mutable i record base-count fields ext-map-iter] Object @@ -12414,6 +12405,14 @@ reduces them without incurring seq initialization" (keyword (.substring k 2 (. k -length))) k)) +(defn- scan-array [incr k array] + (let [len (alength array)] + (loop [i 0] + (when (< i len) + (if (identical? k (aget array i)) + i + (recur (+ i incr))))))) + (deftype ObjMap [meta keys strobj ^:mutable __hash] IWithMeta (-with-meta [coll meta] (ObjMap. meta keys strobj __hash)) @@ -12560,6 +12559,14 @@ reduces them without incurring seq initialization" (recur (nnext kvs))) (.fromObject ObjMap ks obj))))) +(defn- scan-array-equiv [incr k array] + (let [len (alength array)] + (loop [i 0] + (when (< i len) + (if (= k (aget array i)) + i + (recur (+ i incr))))))) + ; The keys field is an array of all keys of this map, in no particular ; order. Each key is hashed and the result used as a property name of ; hashobj. Each values in hashobj is actually a bucket in order to handle hash @@ -12611,25 +12618,27 @@ reduces them without incurring seq initialization" ILookup (-lookup [coll k] (-lookup coll k nil)) (-lookup [coll k not-found] - (let [bucket (aget hashobj (hash k)) - i (when bucket (scan-array 2 k bucket))] - (if i + (let [bucket (unchecked-get hashobj (hash k)) + i (when bucket (scan-array-equiv 2 k bucket))] + (if (some? i) (aget bucket (inc i)) not-found))) IAssociative (-assoc [coll k v] (let [h (hash k) - bucket (aget hashobj h)] + bucket (unchecked-get hashobj h)] (if bucket (let [new-bucket (aclone bucket) new-hashobj (gobject/clone hashobj)] (aset new-hashobj h new-bucket) - (if-let [i (scan-array 2 k new-bucket)] - (do ; found key, replace + (if-let [i (scan-array-equiv 2 k new-bucket)] + (do + ; found key, replace (aset new-bucket (inc i) v) (HashMap. meta count new-hashobj nil)) - (do ; did not find key, append + (do + ; did not find key, append (.push new-bucket k v) (HashMap. meta (inc count) new-hashobj nil)))) (let [new-hashobj (gobject/clone hashobj)] ; did not find bucket @@ -12637,8 +12646,8 @@ reduces them without incurring seq initialization" (HashMap. meta (inc count) new-hashobj nil))))) (-contains-key? [coll k] (let [bucket (unchecked-get hashobj (hash k)) - i (when bucket (scan-array 2 k bucket))] - (if i + i (when bucket (scan-array-equiv 2 k bucket))] + (if (some? i) true false))) @@ -12646,7 +12655,7 @@ reduces them without incurring seq initialization" (-dissoc [coll k] (let [h (hash k) bucket (unchecked-get hashobj h) - i (when bucket (scan-array 2 k bucket))] + i (when bucket (scan-array-equiv 2 k bucket))] (if (not i) coll ; key not found, return coll unchanged (let [new-hashobj (gobject/clone hashobj)] From a656ecabb3f8d6317dc473d229cc73c388d6ee10 Mon Sep 17 00:00:00 2001 From: David Nolen Date: Mon, 4 Aug 2025 23:17:56 -0400 Subject: [PATCH 47/53] - test ObjMap & HashMap --- src/test/cljs/cljs/collections_test.cljs | 55 +++++++++++++++++++++++- 1 file changed, 54 insertions(+), 1 deletion(-) diff --git a/src/test/cljs/cljs/collections_test.cljs b/src/test/cljs/cljs/collections_test.cljs index 6027a3acf..0645622e7 100644 --- a/src/test/cljs/cljs/collections_test.cljs +++ b/src/test/cljs/cljs/collections_test.cljs @@ -1168,10 +1168,63 @@ (is (every? keyword? (keys c))) (is (= (set [:a :b :c]) (set (keys c))))) (is (= (obj-map :a 1 :b 2 :c 3) - (obj-map :a 1 :b 2 :c 3)))) + (obj-map :a 1 :b 2 :c 3))) + (is (= (obj-map :a 1 :b 2) + (into (obj-map) [[:a 1] [:b 2]]))) + (is (= (merge-with + + (obj-map :a 1 :b 2) + (obj-map :a 1 :b 2)) + (into (obj-map) [[:a 2] [:b 4]]))) + (is (= (transient (obj-map :a 1 :b 2)) + (obj-map :a 1 :b 2)))) + +(deftest test-hash-map + (let [a (simple-hash-map)] + (is (empty? a)) + (is (zero? (count a)))) + (let [b (simple-hash-map :a 1)] + (is (not (empty? b))) + (is (== 1 (count b)))) + (let [c (simple-hash-map :a 1 :b 2 :c 3)] + (is (== 3 (count c))) + (is (= 1 (get c :a))) + (is (= 1 (:a c))) + (is (every? keyword? (keys c))) + (is (= (set [:a :b :c]) (set (keys c))))) + (is (= (simple-hash-map :a 1 :b 2 :c 3) + (simple-hash-map :a 1 :b 2 :c 3))) + (is (= (simple-hash-map :a 1 :b 2) + (into (simple-hash-map) [[:a 1] [:b 2]]))) + (is (= (merge-with + + (simple-hash-map :a 1 :b 2) + (simple-hash-map :a 1 :b 2)) + (into (simple-hash-map) [[:a 2] [:b 4]]))) + (is (= (transient (simple-hash-map :a 1 :b 2)) + (simple-hash-map :a 1 :b 2)))) (comment (run-tests) + (defn simple-group-by + [f coll] + (persistent! + (reduce + (fn [ret x] + (let [k (f x)] + (assoc! ret k (conj (get ret k (. Vector -EMPTY)) x)))) + (transient (. ObjMap -EMPTY)) coll))) + + (simple-group-by + :ns + '[{:ns foo :name woz} + {:ns bar :name goz} + {:ns bar :name baz} + {:ns foo :name naz}]) + + (get (simple-hash-map :a 1 :b 2 :c 3) :a) + + (#'scan-array-equiv 2 :a + (unchecked-get (. (simple-hash-map :a 1 :b 2 :c 3) -hashobj) (hash :a))) + ) From 4de7a718bf3fe77ce37959e94ecb8dfbcca28a54 Mon Sep 17 00:00:00 2001 From: David Nolen Date: Tue, 5 Aug 2025 07:59:11 -0400 Subject: [PATCH 48/53] - fix simple hash-map --- src/main/cljs/cljs/core.cljs | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/src/main/cljs/cljs/core.cljs b/src/main/cljs/cljs/core.cljs index d31f5ec9f..4dace1f59 100644 --- a/src/main/cljs/cljs/core.cljs +++ b/src/main/cljs/cljs/core.cljs @@ -12472,7 +12472,7 @@ reduces them without incurring seq initialization" (-kv-reduce coll (fn [ret k v] (-assoc ret k v)) - (. HashMap -EMPTY)) + (simple-hash-map k v)) meta)))) (-contains-key? [coll k] (let [k (if-not (keyword? k) k (keyword->obj-map-key k))] @@ -12628,11 +12628,12 @@ reduces them without incurring seq initialization" (-assoc [coll k v] (let [h (hash k) bucket (unchecked-get hashobj h)] - (if bucket + (if (some? bucket) (let [new-bucket (aclone bucket) - new-hashobj (gobject/clone hashobj)] + new-hashobj (gobject/clone hashobj) + i (scan-array-equiv 2 k new-bucket)] (aset new-hashobj h new-bucket) - (if-let [i (scan-array-equiv 2 k new-bucket)] + (if (some? i) (do ; found key, replace (aset new-bucket (inc i) v) @@ -12641,7 +12642,8 @@ reduces them without incurring seq initialization" ; did not find key, append (.push new-bucket k v) (HashMap. meta (inc count) new-hashobj nil)))) - (let [new-hashobj (gobject/clone hashobj)] ; did not find bucket + (let [new-hashobj (gobject/clone hashobj)] + ; did not find bucket (unchecked-set new-hashobj h (array k v)) (HashMap. meta (inc count) new-hashobj nil))))) (-contains-key? [coll k] @@ -12656,15 +12658,16 @@ reduces them without incurring seq initialization" (let [h (hash k) bucket (unchecked-get hashobj h) i (when bucket (scan-array-equiv 2 k bucket))] - (if (not i) - coll ; key not found, return coll unchanged + (if (some? i) (let [new-hashobj (gobject/clone hashobj)] (if (> 3 (alength bucket)) (js-delete new-hashobj h) (let [new-bucket (aclone bucket)] (.splice new-bucket i 2) (unchecked-set new-hashobj h new-bucket))) - (HashMap. meta (dec count) new-hashobj nil))))) + (HashMap. meta (dec count) new-hashobj nil)) + ; key not found, return coll unchanged + coll))) IFn (-invoke [coll k] From 3ceb397c750915fb48f01fff9d41d85ecdd0665e Mon Sep 17 00:00:00 2001 From: David Nolen Date: Tue, 5 Aug 2025 08:00:01 -0400 Subject: [PATCH 49/53] - add toString methods --- src/main/cljs/cljs/core.cljs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/main/cljs/cljs/core.cljs b/src/main/cljs/cljs/core.cljs index 4dace1f59..52499bcd0 100644 --- a/src/main/cljs/cljs/core.cljs +++ b/src/main/cljs/cljs/core.cljs @@ -12249,6 +12249,10 @@ reduces them without incurring seq initialization" ;;; Vector (deftype Vector [meta array ^:mutable __hash] + Object + (toString [coll] + (pr-str* coll)) + IWithMeta (-with-meta [coll meta] (Vector. meta array __hash)) @@ -12414,6 +12418,10 @@ reduces them without incurring seq initialization" (recur (+ i incr))))))) (deftype ObjMap [meta keys strobj ^:mutable __hash] + Object + (toString [coll] + (pr-str* coll)) + IWithMeta (-with-meta [coll meta] (ObjMap. meta keys strobj __hash)) @@ -12573,6 +12581,10 @@ reduces them without incurring seq initialization" ; collisions. A bucket is an array of alternating keys (not their hashes) and ; vals. (deftype HashMap [meta count hashobj ^:mutable __hash] + Object + (toString [coll] + (pr-str* coll)) + IWithMeta (-with-meta [coll meta] (HashMap. meta count hashobj __hash)) @@ -12716,6 +12728,10 @@ reduces them without incurring seq initialization" out))) (deftype Set [meta hash-map ^:mutable __hash] + Object + (toString [coll] + (pr-str* coll)) + IWithMeta (-with-meta [coll meta] (Set. meta hash-map __hash)) From bc0ebad57f52214bd641f2e15d025d484f5ddf54 Mon Sep 17 00:00:00 2001 From: David Nolen Date: Tue, 5 Aug 2025 08:00:45 -0400 Subject: [PATCH 50/53] - cleanup collections test --- src/test/cljs/cljs/collections_test.cljs | 23 +---------------------- 1 file changed, 1 insertion(+), 22 deletions(-) diff --git a/src/test/cljs/cljs/collections_test.cljs b/src/test/cljs/cljs/collections_test.cljs index 0645622e7..be8c240ee 100644 --- a/src/test/cljs/cljs/collections_test.cljs +++ b/src/test/cljs/cljs/collections_test.cljs @@ -1200,31 +1200,10 @@ (simple-hash-map :a 1 :b 2)) (into (simple-hash-map) [[:a 2] [:b 4]]))) (is (= (transient (simple-hash-map :a 1 :b 2)) - (simple-hash-map :a 1 :b 2)))) + (simple-hash-map :a 1 :b 2)))) (comment (run-tests) - (defn simple-group-by - [f coll] - (persistent! - (reduce - (fn [ret x] - (let [k (f x)] - (assoc! ret k (conj (get ret k (. Vector -EMPTY)) x)))) - (transient (. ObjMap -EMPTY)) coll))) - - (simple-group-by - :ns - '[{:ns foo :name woz} - {:ns bar :name goz} - {:ns bar :name baz} - {:ns foo :name naz}]) - - (get (simple-hash-map :a 1 :b 2 :c 3) :a) - - (#'scan-array-equiv 2 :a - (unchecked-get (. (simple-hash-map :a 1 :b 2 :c 3) -hashobj) (hash :a))) - ) From fea514f6d44be85e6f15f8f342b27d9e5697c021 Mon Sep 17 00:00:00 2001 From: David Nolen Date: Tue, 5 Aug 2025 08:01:18 -0400 Subject: [PATCH 51/53] - add lite collections assertions, cleanup --- src/test/cljs/cljs/lite_collections_test.cljs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/test/cljs/cljs/lite_collections_test.cljs b/src/test/cljs/cljs/lite_collections_test.cljs index 474099617..976a44c74 100644 --- a/src/test/cljs/cljs/lite_collections_test.cljs +++ b/src/test/cljs/cljs/lite_collections_test.cljs @@ -7,11 +7,13 @@ ; You must not remove this notice, or any other, from this software. (ns cljs.lite-collections-test - (:require [cljs.test :refer-macros [deftest testing is are run-tests]])) + (:require [cljs.test :refer [deftest testing is]])) -;; NOTE: ** this name space must be tested with :lite-mode true ** +;; NOTE: ** this namespace must be tested with :lite-mode true ** (deftest test-obj-map (let [a (. ObjMap -EMPTY) b {}] - (is (identical? a b)))) \ No newline at end of file + (is (identical? a b))) + (let [a {:foo 1}] + (is (== 1 (:foo a))))) \ No newline at end of file From 5e99038d9ce9e5d0a02fbebde89435508cb97d97 Mon Sep 17 00:00:00 2001 From: David Nolen Date: Tue, 5 Aug 2025 08:03:49 -0400 Subject: [PATCH 52/53] - add lite test action --- .github/workflows/test.yaml | 57 +++++++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index e98aa8818..4420e9d0b 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -59,6 +59,63 @@ jobs: /System/Library/Frameworks/JavaScriptCore.framework/Versions/A/Helpers/jsc builds/out-adv/core-advanced-test.js | tee test-out.txt grep -qxF '0 failures, 0 errors.' test-out.txt + # Lite Tests + lite-test: + name: Lite Tests + runs-on: macos-14 + steps: + - uses: actions/checkout@v2 + + - uses: actions/setup-java@v4 + with: + distribution: 'temurin' + java-version: '21' + + - uses: DeLaGuardo/setup-clojure@3.1 + with: + tools-deps: '1.10.1.763' + + - name: Cache maven + uses: actions/cache@v4 + env: + cache-name: cache-maven + with: + path: ~/.m2 + key: ${{ runner.os }}-${{ env.cache-name }}-${{ hashFiles('**/deps.edn') }} + restore-keys: | + ${{ runner.os }}-${{ env.cache-name }}- + + - name: Cache gitlibs + uses: actions/cache@v4 + env: + cache-name: cache-gitlibs + with: + path: ~/.gitlibs + key: ${{ runner.os }}-${{ env.cache-name }}-${{ hashFiles('**/deps.edn') }} + restore-keys: | + ${{ runner.os }}-${{ env.cache-name }}- + + # - name: Cache JSC + # uses: actions/cache@v4 + # env: + # cache-name: cache-jsc + # with: + # path: WebKit + # key: ${{ runner.os }}-jsc + # restore-keys: | + # ${{ runner.os }}-jsc + + - name: Build tests + run: clojure -M:lite.test.build + + # - name: Install JSC + # run: ./ci/install_jsc.sh + + - name: Run tests + run: | + /System/Library/Frameworks/JavaScriptCore.framework/Versions/A/Helpers/jsc builds/out-lite/lite-test.js | tee test-out.txt + grep -qxF '0 failures, 0 errors.' test-out.txt + # Runtime Tests runtime-windows-test: name: Runtime Windows Tests From 665619090fa97a968733fbfa0b0feee1484b3537 Mon Sep 17 00:00:00 2001 From: David Nolen Date: Tue, 5 Aug 2025 08:35:48 -0400 Subject: [PATCH 53/53] - :elide-to-string compiler flag --- src/main/clojure/cljs/analyzer.cljc | 3 +++ src/main/clojure/cljs/closure.clj | 3 ++- src/main/clojure/cljs/core.cljc | 2 +- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/main/clojure/cljs/analyzer.cljc b/src/main/clojure/cljs/analyzer.cljc index 87733cf05..ceebbe973 100644 --- a/src/main/clojure/cljs/analyzer.cljc +++ b/src/main/clojure/cljs/analyzer.cljc @@ -497,6 +497,9 @@ (defn lite-mode? [] (get-in @env/*compiler* [:options :lite-mode])) +(defn elide-to-string? [] + (get-in @env/*compiler* [:options :elide-to-string])) + #?(:clj (defmacro with-warning-handlers [handlers & body] `(binding [*cljs-warning-handlers* ~handlers] diff --git a/src/main/clojure/cljs/closure.clj b/src/main/clojure/cljs/closure.clj index 5dc7db1a3..550fd68d5 100644 --- a/src/main/clojure/cljs/closure.clj +++ b/src/main/clojure/cljs/closure.clj @@ -211,7 +211,8 @@ :watch :watch-error-fn :watch-fn :install-deps :process-shim :rename-prefix :rename-prefix-namespace :closure-variable-map-in :closure-property-map-in :closure-variable-map-out :closure-property-map-out :stable-names :ignore-js-module-exts :opts-cache :aot-cache :elide-strict :fingerprint :spec-skip-macros - :nodejs-rt :target-fn :deps-cmd :bundle-cmd :global-goog-object&array :node-modules-dirs :lite-mode}) + :nodejs-rt :target-fn :deps-cmd :bundle-cmd :global-goog-object&array :node-modules-dirs :lite-mode + :elide-to-string}) (def string->charset {"iso-8859-1" StandardCharsets/ISO_8859_1 diff --git a/src/main/clojure/cljs/core.cljc b/src/main/clojure/cljs/core.cljc index 70ef0d267..b326a3fa6 100644 --- a/src/main/clojure/cljs/core.cljc +++ b/src/main/clojure/cljs/core.cljc @@ -1511,7 +1511,7 @@ ;; Elide all toString methods in :lite-mode (remove (core/fn [[f]] - (core/and (ana/lite-mode?) (core/= 'toString f)))) + (core/and (ana/elide-to-string?) (core/= 'toString f)))) (map (core/fn [[f & meths :as form]] (core/let [[f meths] (if (vector? (first meths))