From 7a4caa5b61f391bade0d239883e461fe74b25ae0 Mon Sep 17 00:00:00 2001 From: Nathan Marz Date: Fri, 11 Sep 2015 16:06:31 -0400 Subject: [PATCH] partial refactoring to prepare for cljs compatibility --- src/com/rpl/specter.cljc | 34 ++++---- src/com/rpl/specter/defhelpers.clj | 21 +++++ src/com/rpl/specter/impl.cljc | 132 ++++------------------------- src/com/rpl/specter/macros.clj | 97 +++++++++++++++++++++ 4 files changed, 153 insertions(+), 131 deletions(-) create mode 100644 src/com/rpl/specter/defhelpers.clj create mode 100644 src/com/rpl/specter/macros.clj diff --git a/src/com/rpl/specter.cljc b/src/com/rpl/specter.cljc index 0f59968..4bfbe19 100644 --- a/src/com/rpl/specter.cljc +++ b/src/com/rpl/specter.cljc @@ -1,6 +1,8 @@ (ns com.rpl.specter - (:use [com.rpl.specter.protocols :only [StructurePath]]) - (:require [com.rpl.specter.impl :as i]) + (:use [com.rpl.specter.protocols :only [StructurePath]] + ) + (:require [com.rpl.specter.impl :as i] + [com.rpl.specter.macros :as m]) ) (defn comp-paths [& paths] @@ -118,8 +120,8 @@ that needed parameters (in the order in which they were declared)." [params & impls] (let [num-params (count params) - retrieve-params (i/make-param-retrievers params)] - (i/paramspath* retrieve-params num-params impls) + retrieve-params (m/make-param-retrievers params)] + (m/paramspath* retrieve-params num-params impls) )) (defmacro paramscollector @@ -130,8 +132,8 @@ " [params impl] (let [num-params (count params) - retrieve-params (i/make-param-retrievers params)] - (i/paramscollector* retrieve-params num-params impl) + retrieve-params (m/make-param-retrievers params)] + (m/paramscollector* retrieve-params num-params impl) )) (defmacro defparamspath [name & body] @@ -150,13 +152,13 @@ paths (mapv second bindings) names (mapv first bindings) latefns-sym (gensym "latefns") - latefn-syms (vec (i/gensyms (count paths)))] - (i/pathed-path* - i/paramspath* + latefn-syms (vec (m/gensyms (count paths)))] + (m/pathed-path* + m/paramspath* paths latefns-sym [latefn-syms latefns-sym] - (mapcat (fn [n l] [n `(~l ~i/PARAMS-SYM ~i/PARAMS-IDX-SYM)]) names latefn-syms) + (mapcat (fn [n l] [n `(~l ~m/PARAMS-SYM ~m/PARAMS-IDX-SYM)]) names latefn-syms) impls))) (defmacro variable-pathed-path @@ -166,12 +168,12 @@ are required, then the result is executable." [[latepaths-seq-sym paths-seq] & impls] (let [latefns-sym (gensym "latefns")] - (i/pathed-path* - i/paramspath* + (m/pathed-path* + m/paramspath* paths-seq latefns-sym [] - [latepaths-seq-sym `(map (fn [l#] (l# ~i/PARAMS-SYM ~i/PARAMS-IDX-SYM)) + [latepaths-seq-sym `(map (fn [l#] (l# ~m/PARAMS-SYM ~m/PARAMS-IDX-SYM)) ~latefns-sym)] impls ))) @@ -184,12 +186,12 @@ [[name path] impl] (let [latefns-sym (gensym "latefns") latefn (gensym "latefn")] - (i/pathed-path* - i/paramscollector* + (m/pathed-path* + m/paramscollector* [path] latefns-sym [[latefn] latefns-sym] - [name `(~latefn ~i/PARAMS-SYM ~i/PARAMS-IDX-SYM)] + [name `(~latefn ~m/PARAMS-SYM ~m/PARAMS-IDX-SYM)] impl ) )) diff --git a/src/com/rpl/specter/defhelpers.clj b/src/com/rpl/specter/defhelpers.clj new file mode 100644 index 0000000..eea0220 --- /dev/null +++ b/src/com/rpl/specter/defhelpers.clj @@ -0,0 +1,21 @@ +(ns com.rpl.specter.defhelpers) + +(defn gensyms [amt] + (vec (repeatedly amt gensym))) + +(defmacro define-ParamsNeededPath [fn-type] + (let [a (with-meta (gensym "array") {:tag 'objects}) + impls (for [i (range 21) + :let [args (vec (gensyms i)) + setters (for [j (range i)] `(aset ~a ~j ~(get args j)))]] + `(~'invoke [this# ~@args] + (let [~a (object-array ~i)] + ~@setters + (com.rpl.specter.impl/bind-params* this# ~a 0) + )))] + `(defrecord ~'ParamsNeededPath [~'transform-fns ~'num-needed-params] + ~fn-type + ~@impls + (~'applyTo [this# args#] + (let [a# (object-array args#)] + (com.rpl.specter.impl/bind-params* this# a# 0)))))) diff --git a/src/com/rpl/specter/impl.cljc b/src/com/rpl/specter/impl.cljc index dd9c40e..286bb69 100644 --- a/src/com/rpl/specter/impl.cljc +++ b/src/com/rpl/specter/impl.cljc @@ -1,21 +1,23 @@ (ns com.rpl.specter.impl - #?(:cljs (:require-macros [com.rpl.specter.prot-opt-invoke - :refer [mk-optimized-invocation]])) + #?(:cljs (:require-macros + [com.rpl.specter.prot-opt-invoke + :refer [mk-optimized-invocation]] + [com.rpl.specter.defhelpers :refer [define-ParamsNeededPath]] + )) (:use [com.rpl.specter.protocols :only [select* transform* collect-val]]) (:require [com.rpl.specter.protocols :as p] [clojure.walk :as walk] [clojure.core.reducers :as r] - [clojure.string :as s]) + [clojure.string :as s] + #?(:clj [com.rpl.specter.defhelpers :as dh]) + ) ) (defn spy [e] (println e) e) -(defn gensyms [amt] - (vec (repeatedly amt gensym))) - (defprotocol PathComposer (comp-paths* [paths])) @@ -70,31 +72,22 @@ (defrecord CompiledPath [transform-fns params params-idx]) +(defn compiled-path? [o] + (instance? CompiledPath o)) + (defn no-params-compiled-path [transform-fns] (->CompiledPath transform-fns nil 0)) (declare bind-params*) -(defmacro define-ParamsNeededPath [] - (let [a (with-meta (gensym "array") {:tag 'objects}) - impls (for [i (range 21) - :let [args (vec (gensyms i)) - setters (for [j (range i)] `(aset ~a ~j ~(get args j)))]] - `(~'invoke [this# ~@args] - (let [~a (object-array ~i)] - ~@setters - (bind-params* this# ~a 0) - )))] - `(defrecord ~'ParamsNeededPath [~'transform-fns ~'num-needed-params] - clojure.lang.IFn - ~@impls - (~'applyTo [this# args#] - (let [a# (object-array args#)] - (bind-params* this# a# 0)))))) +#?( +:clj +(dh/define-ParamsNeededPath clojure.lang.IFn) - -(define-ParamsNeededPath) +:cljs +(dh/define-ParamsNeededPath cljs.core/IFn) +) (defn bind-params* [^ParamsNeededPath params-needed-path params idx] @@ -340,102 +333,11 @@ )))) -;; parameterized path helpers - -(defn determine-params-impls [[name1 & impl1] [name2 & impl2]] - (if (= name1 'select*) - [impl1 impl2] - [impl2 impl1])) - - -(def PARAMS-SYM (vary-meta (gensym "params") assoc :tag 'objects)) -(def PARAMS-IDX-SYM (gensym "params-idx")) - -(defn paramspath* [bindings num-params [impl1 impl2]] - (let [[[[_ s-structure-sym s-next-fn-sym] & select-body] - [[_ t-structure-sym t-next-fn-sym] & transform-body]] - (determine-params-impls impl1 impl2)] - `(->ParamsNeededPath - (->TransformFunctions - RichPathExecutor - (fn [~PARAMS-SYM ~PARAMS-IDX-SYM vals# ~s-structure-sym next-fn#] - (let [~s-next-fn-sym (fn [structure#] - (next-fn# - ~PARAMS-SYM - (+ ~PARAMS-IDX-SYM ~num-params) - vals# - structure#)) - ~@bindings] - ~@select-body - )) - (fn [~PARAMS-SYM ~PARAMS-IDX-SYM vals# ~t-structure-sym next-fn#] - (let [~t-next-fn-sym (fn [structure#] - (next-fn# - ~PARAMS-SYM - (+ ~PARAMS-IDX-SYM ~num-params) - vals# - structure#)) - ~@bindings] - ~@transform-body - ))) - ~num-params - ))) - -(defn paramscollector* [post-bindings num-params [_ [_ structure-sym] & body]] - `(let [collector# (fn [~PARAMS-SYM ~PARAMS-IDX-SYM vals# ~structure-sym next-fn#] - (let [~@post-bindings ~@[] ; to avoid syntax highlighting issues - c# (do ~@body)] - (next-fn# - ~PARAMS-SYM - (+ ~PARAMS-IDX-SYM ~num-params) - (conj vals# c#) - ~structure-sym) - ))] - (->ParamsNeededPath - (->TransformFunctions - RichPathExecutor - collector# - collector# ) - ~num-params - ))) - (defn num-needed-params [path] (if (instance? CompiledPath path) 0 (:num-needed-params path))) -(defn pathed-path* [builder paths-seq latefns-sym pre-bindings post-bindings impls] - (let [num-params-sym (gensym "num-params")] - `(let [paths# (map comp-paths* ~paths-seq) - needed-params# (map num-needed-params paths#) - offsets# (cons 0 (reductions + needed-params#)) - ~num-params-sym (last offsets#) - ~latefns-sym (map - (fn [o# p#] - (if (instance? CompiledPath p#) - (fn [params# params-idx#] - p# ) - (fn [params# params-idx#] - (bind-params* p# params# (+ params-idx# o#)) - ))) - offsets# - paths#) - ~@pre-bindings - ret# ~(builder post-bindings num-params-sym impls) - ] - (if (= 0 ~num-params-sym) - (bind-params* ret# nil 0) - ret# - )))) - -(defn make-param-retrievers [params] - (->> params - (map-indexed - (fn [i p] - [p `(aget ~PARAMS-SYM - (+ ~PARAMS-IDX-SYM ~i))] - )) - (apply concat))) ;; cell implementation idea taken from prismatic schema library (defprotocol PMutableCell diff --git a/src/com/rpl/specter/macros.clj b/src/com/rpl/specter/macros.clj new file mode 100644 index 0000000..24ec408 --- /dev/null +++ b/src/com/rpl/specter/macros.clj @@ -0,0 +1,97 @@ +(ns com.rpl.specter.macros + (:use [com.rpl.specter impl]) + ) + +(defn gensyms [amt] + (vec (repeatedly amt gensym))) + +(defn determine-params-impls [[name1 & impl1] [name2 & impl2]] + (if (= name1 'select*) + [impl1 impl2] + [impl2 impl1])) + + +(def PARAMS-SYM (vary-meta (gensym "params") assoc :tag 'objects)) +(def PARAMS-IDX-SYM (gensym "params-idx")) + +(defn paramspath* [bindings num-params [impl1 impl2]] + (let [[[[_ s-structure-sym s-next-fn-sym] & select-body] + [[_ t-structure-sym t-next-fn-sym] & transform-body]] + (determine-params-impls impl1 impl2)] + `(->ParamsNeededPath + (->TransformFunctions + RichPathExecutor + (fn [~PARAMS-SYM ~PARAMS-IDX-SYM vals# ~s-structure-sym next-fn#] + (let [~s-next-fn-sym (fn [structure#] + (next-fn# + ~PARAMS-SYM + (+ ~PARAMS-IDX-SYM ~num-params) + vals# + structure#)) + ~@bindings] + ~@select-body + )) + (fn [~PARAMS-SYM ~PARAMS-IDX-SYM vals# ~t-structure-sym next-fn#] + (let [~t-next-fn-sym (fn [structure#] + (next-fn# + ~PARAMS-SYM + (+ ~PARAMS-IDX-SYM ~num-params) + vals# + structure#)) + ~@bindings] + ~@transform-body + ))) + ~num-params + ))) + +(defn paramscollector* [post-bindings num-params [_ [_ structure-sym] & body]] + `(let [collector# (fn [~PARAMS-SYM ~PARAMS-IDX-SYM vals# ~structure-sym next-fn#] + (let [~@post-bindings ~@[] ; to avoid syntax highlighting issues + c# (do ~@body)] + (next-fn# + ~PARAMS-SYM + (+ ~PARAMS-IDX-SYM ~num-params) + (conj vals# c#) + ~structure-sym) + ))] + (->ParamsNeededPath + (->TransformFunctions + RichPathExecutor + collector# + collector# ) + ~num-params + ))) + +(defn pathed-path* [builder paths-seq latefns-sym pre-bindings post-bindings impls] + (let [num-params-sym (gensym "num-params")] + `(let [paths# (map comp-paths* ~paths-seq) + needed-params# (map num-needed-params paths#) + offsets# (cons 0 (reductions + needed-params#)) + ~num-params-sym (last offsets#) + ~latefns-sym (map + (fn [o# p#] + (if (compiled-path? p#) + (fn [params# params-idx#] + p# ) + (fn [params# params-idx#] + (bind-params* p# params# (+ params-idx# o#)) + ))) + offsets# + paths#) + ~@pre-bindings + ret# ~(builder post-bindings num-params-sym impls) + ] + (if (= 0 ~num-params-sym) + (bind-params* ret# nil 0) + ret# + )))) + +(defn make-param-retrievers [params] + (->> params + (map-indexed + (fn [i p] + [p `(aget ~PARAMS-SYM + (+ ~PARAMS-IDX-SYM ~i))] + )) + (apply concat))) +