From fc51d70b0fbfc583f359c5c28064edb131bf4b09 Mon Sep 17 00:00:00 2001 From: Nathan Marz Date: Sat, 12 Dec 2015 12:03:59 -0500 Subject: [PATCH] renamed defparamspath and defparamscollector to defpath and defcollector, defpath without params now produces compiledpath directly, implemented protocolpaths --- src/com/rpl/specter.cljx | 28 ++++----- src/com/rpl/specter/impl.cljx | 22 +++++++ src/com/rpl/specter/macros.clj | 111 +++++++++++++++++++++++++-------- 3 files changed, 120 insertions(+), 41 deletions(-) diff --git a/src/com/rpl/specter.cljx b/src/com/rpl/specter.cljx index 79f794f..a01941f 100644 --- a/src/com/rpl/specter.cljx +++ b/src/com/rpl/specter.cljx @@ -5,8 +5,8 @@ [pathed-collector variable-pathed-path fixed-pathed-path - defparamscollector - defparamspath + defcollector + defpath paramscollector paramspath ]] @@ -16,8 +16,8 @@ [pathed-collector variable-pathed-path fixed-pathed-path - defparamscollector - defparamspath + defcollector + defpath paramscollector paramspath]] ) @@ -143,7 +143,7 @@ (def FIRST (comp-paths (i/->PosStructurePath first i/set-first))) -(defparamspath +(defpath ^{:doc "Uses start-fn and end-fn to determine the bounds of the subsequence to select when navigating. Each function takes in the structure as input."} srange-dynamic @@ -154,7 +154,7 @@ (i/srange-transform structure (start-fn structure) (end-fn structure) next-fn) )) -(defparamspath +(defpath ^{:doc "Navigates to the subsequence bound by the indexes start (inclusive) and end (exclusive)"} srange @@ -169,7 +169,7 @@ (def END (srange-dynamic count count)) -(defparamspath +(defpath ^{:doc "Navigates to the specified subset (by taking an intersection). In a transform, that subset in the original set is changed to the new value of the subset."} @@ -185,7 +185,7 @@ (set/union newset)) ))) -(defparamspath +(defpath walker [afn] (select* [this structure next-fn] @@ -193,7 +193,7 @@ (transform* [this structure next-fn] (i/walk-until afn next-fn structure))) -(defparamspath +(defpath codewalker [afn] (select* [this structure next-fn] @@ -225,14 +225,14 @@ ))) -(defparamspath keypath [key] +(defpath keypath [key] (select* [this structure next-fn] (next-fn (get structure key))) (transform* [this structure next-fn] (assoc structure key (next-fn (get structure key))) )) -(defparamspath view [afn] +(defpath view [afn] (select* [this structure next-fn] (next-fn (afn structure))) (transform* [this structure next-fn] @@ -309,7 +309,7 @@ (transform* [aset structure next-fn] (i/filter-transform aset structure next-fn))) -(defparamspath +(defpath ^{:doc "Keeps the element only if it matches the supplied predicate. This is the late-bound parameterized version of using a function directly in a path."} pred @@ -319,7 +319,7 @@ (transform* [this structure next-fn] (i/filter-transform afn structure next-fn))) -(defparamspath +(defpath ^{:doc "Navigates to the provided val if the structure is nil. Otherwise it stays navigated at the structure."} nil->val @@ -345,7 +345,7 @@ (compiled-select-one late structure) ))) -(defparamscollector +(defcollector ^{:doc "Adds an external value to the collected vals. Useful when additional arguments are required to the transform function that would otherwise require partial diff --git a/src/com/rpl/specter/impl.cljx b/src/com/rpl/specter/impl.cljx index c1ad3ed..edb9743 100644 --- a/src/com/rpl/specter/impl.cljx +++ b/src/com/rpl/specter/impl.cljx @@ -553,3 +553,25 @@ (if (afn structure) (next-fn structure) structure)) + +(defn compiled-selector [^com.rpl.specter.impl.CompiledPath path] + (-> path .-transform-fns .-selector)) + +(defn compiled-transformer [^com.rpl.specter.impl.CompiledPath path] + (-> path .-transform-fns .-transformer)) + +(defn params-needed-selector [^com.rpl.specter.impl.ParamsNeededPath path] + (-> path .-transform-fns .-selector)) + +(defn params-needed-transformer [^com.rpl.specter.impl.ParamsNeededPath path] + (-> path .-transform-fns .-transformer)) + + +(defn extend-protocolpath* [protpath-prot extensions] + (let [extensions (partition 2 extensions) + m (-> protpath-prot :sigs keys first)] + (doseq [[atype apath] extensions] + ;;TODO: validate that the path has the correct number of args + (let [p (comp-paths* apath)] + (extend atype protpath-prot {m (fn [_] p)}) + )))) diff --git a/src/com/rpl/specter/macros.clj b/src/com/rpl/specter/macros.clj index 6ee6757..b25738a 100644 --- a/src/com/rpl/specter/macros.clj +++ b/src/com/rpl/specter/macros.clj @@ -18,31 +18,40 @@ (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 - ))) + (if (= 0 num-params) + `(no-params-compiled-path + (->TransformFunctions + StructurePathExecutor + (fn [~s-structure-sym ~s-next-fn-sym] + ~@select-body) + (fn [~t-structure-sym ~t-next-fn-sym] + ~@transform-body) + )) + `(->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#] @@ -130,10 +139,10 @@ (paramscollector* retrieve-params num-params impl) )) -(defmacro defparamspath [name & body] +(defmacro defpath [name & body] `(def ~name (paramspath ~@body))) -(defmacro defparamscollector [name & body] +(defmacro defcollector [name & body] `(def ~name (paramscollector ~@body))) (defmacro fixed-pathed-path @@ -190,3 +199,51 @@ ) )) +(defn- protpath-sym [name] + (-> name (str "-prot") symbol)) + +(defmacro defprotocolpath [name params] + (let [prot-name (protpath-sym name) + m (-> name (str "-retrieve") symbol) + num-params (count params) + ssym (gensym "structure") + sargs [ssym (gensym "next-fn")] + rargs [(gensym "params") (gensym "pidx") (gensym "vals") ssym (gensym "next-fn")] + retrieve `(~m ~ssym) + ] + `(do + (defprotocol ~prot-name (~m [structure#])) + (def ~name + (if (= ~num-params 0) + (no-params-compiled-path + (->TransformFunctions + StructurePathExecutor + (fn ~sargs + (let [path# ~retrieve + selector# (compiled-selector path#)] + (selector# ~@sargs) + )) + (fn ~sargs + (let [path# ~retrieve + transformer# (compiled-transformer path#)] + (transformer# ~@sargs) + )))) + (->ParamsNeededPath + (->TransformFunctions + RichPathExecutor + (fn ~rargs + (let [path# ~retrieve + selector# (params-needed-selector path#)] + (selector# ~@rargs) + )) + (fn ~rargs + (let [path# ~retrieve + transformer# (params-needed-transformer path#)] + (transformer# ~@rargs) + ))) + ~num-params + ) + ))))) + +(defmacro extend-protocolpath [protpath & extensions] + `(extend-protocolpath* ~(protpath-sym protpath) ~(vec extensions)))