Compare commits

...

1 commit

Author SHA1 Message Date
Nathan Marz
8d7c786fe9 inline-next-fn implementation 2016-08-13 18:49:42 -04:00
4 changed files with 78 additions and 26 deletions

View file

@ -328,6 +328,7 @@
In a transform, that subset in the original set is changed to the In a transform, that subset in the original set is changed to the
new value of the subset."} new value of the subset."}
subset subset
{:inline-next-fn true}
[aset] [aset]
(select* [this structure next-fn] (select* [this structure next-fn]
(next-fn (set/intersection structure aset))) (next-fn (set/intersection structure aset)))
@ -344,6 +345,7 @@
In a transform, that submap in the original map is changed to the new In a transform, that submap in the original map is changed to the new
value of the submap."} value of the submap."}
submap submap
{:inline-next-fn true}
[m-keys] [m-keys]
(select* [this structure next-fn] (select* [this structure next-fn]
(next-fn (select-keys structure m-keys))) (next-fn (select-keys structure m-keys)))
@ -371,7 +373,7 @@
(select* [this structure next-fn] (select* [this structure next-fn]
(n/walk-select afn next-fn structure)) (n/walk-select afn next-fn structure))
(transform* [this structure next-fn] (transform* [this structure next-fn]
(n/codewalk-until afn next-fn structure))) (i/codewalk-until afn next-fn structure)))
(defpathedfn subselect (defpathedfn subselect
"Navigates to a sequence that contains the results of (select ...), "Navigates to a sequence that contains the results of (select ...),
@ -397,6 +399,7 @@
(defnav (defnav
^{:doc "Navigates to the specified key, navigating to nil if it does not exist."} ^{:doc "Navigates to the specified key, navigating to nil if it does not exist."}
keypath keypath
{:inline-next-fn true}
[key] [key]
(select* [this structure next-fn] (select* [this structure next-fn]
(next-fn (get structure key))) (next-fn (get structure key)))
@ -407,6 +410,7 @@
(defnav (defnav
^{:doc "Navigates to the key only if it exists in the map."} ^{:doc "Navigates to the key only if it exists in the map."}
must must
{:inline-next-fn true}
[k] [k]
(select* [this structure next-fn] (select* [this structure next-fn]
(if (contains? structure k) (if (contains? structure k)
@ -421,6 +425,7 @@
(defnav (defnav
^{:doc "Navigates to result of running `afn` on the currently navigated value."} ^{:doc "Navigates to result of running `afn` on the currently navigated value."}
view view
{:inline-next-fn true}
[afn] [afn]
(select* [this structure next-fn] (select* [this structure next-fn]
(next-fn (afn structure))) (next-fn (afn structure)))
@ -433,6 +438,7 @@
transforms, the transformed value then has `unparse-fn` run on transforms, the transformed value then has `unparse-fn` run on
it to get the final value at this point."} it to get the final value at this point."}
parser parser
{:inline-next-fn true}
[parse-fn unparse-fn] [parse-fn unparse-fn]
(select* [this structure next-fn] (select* [this structure next-fn]
(next-fn (parse-fn structure))) (next-fn (parse-fn structure)))
@ -518,6 +524,7 @@
^{:doc "Keeps the element only if it matches the supplied predicate. This is the ^{: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."} late-bound parameterized version of using a function directly in a path."}
pred pred
{:inline-next-fn true}
[afn] [afn]
(select* [this structure next-fn] (select* [this structure next-fn]
(if (afn structure) (next-fn structure) NONE)) (if (afn structure) (next-fn structure) NONE))
@ -546,6 +553,7 @@
^{:doc "Navigates to the provided val if the structure is nil. Otherwise it stays ^{:doc "Navigates to the provided val if the structure is nil. Otherwise it stays
navigated at the structure."} navigated at the structure."}
nil->val nil->val
{:inline-next-fn true}
[v] [v]
(select* [this structure next-fn] (select* [this structure next-fn]
(next-fn (if (nil? structure) v structure))) (next-fn (if (nil? structure) v structure)))

View file

@ -9,6 +9,7 @@
(:require [com.rpl.specter.protocols :as p] (:require [com.rpl.specter.protocols :as p]
[clojure.string :as s] [clojure.string :as s]
[clojure.walk :as walk]
#?(:clj [com.rpl.specter.defhelpers :as dh]) #?(:clj [com.rpl.specter.defhelpers :as dh])
#?(:clj [riddley.walk :as riddley])) #?(:clj [riddley.walk :as riddley]))
@ -652,6 +653,14 @@
#?(:cljs (instance? cljs.core.LazySeq f)) #?(:cljs (instance? cljs.core.LazySeq f))
(list? f))) (list? f)))
(defn codewalk-until [pred on-match-fn structure]
(if (pred structure)
(on-match-fn structure)
(let [ret (walk/walk (partial codewalk-until pred on-match-fn) identity structure)]
(if (and (fn-invocation? structure) (fn-invocation? ret))
(with-meta ret (meta structure))
ret))))
(defrecord LayeredNav [underlying]) (defrecord LayeredNav [underlying])
(defn layered-nav? [o] (instance? LayeredNav o)) (defn layered-nav? [o] (instance? LayeredNav o))

View file

@ -62,13 +62,13 @@
`(let [~@binding-fn-declarations] `(let [~@binding-fn-declarations]
~body))) ~body)))
(defmacro ^:no-doc rich-nav-with-bindings [num-params-code bindings & impls]
(defn- rich-nav-with-bindings-not-inlined [num-params-code bindings impls]
(let [{[[_ s-structure-sym s-next-fn-sym] & s-body] 'select* (let [{[[_ s-structure-sym s-next-fn-sym] & s-body] 'select*
[[_ t-structure-sym t-next-fn-sym] & t-body] 'transform*} [[_ t-structure-sym t-next-fn-sym] & t-body] 'transform*}
(determine-params-impls impls) (determine-params-impls impls)
params-sym (gensym "params") params-sym (gensym "params")
params-idx-sym (gensym "params-idx")] params-idx-sym (gensym "params-idx")]
(operation-with-bindings (operation-with-bindings
bindings bindings
params-sym params-sym
@ -95,6 +95,44 @@
structure#))] structure#))]
~@t-body))))))) ~@t-body)))))))
(defn inline-next-fn [body next-fn-sym extra-params]
(i/codewalk-until
#(and (i/fn-invocation? %) (= next-fn-sym (first %)))
(fn [code]
(let [code (map #(inline-next-fn % next-fn-sym extra-params) code)]
(concat [next-fn-sym] extra-params (rest code))))
body))
(defn- rich-nav-with-bindings-inlined [num-params-code bindings impls]
(let [{[[_ s-structure-sym s-next-fn-sym] & s-body] 'select*
[[_ t-structure-sym t-next-fn-sym] & t-body] 'transform*}
(determine-params-impls impls)
params-sym (gensym "params")
params-idx-sym (gensym "params-idx")
vals-sym (gensym "vals")
next-params-idx-sym (gensym "next-params-idx")
s-body (inline-next-fn s-body s-next-fn-sym [params-sym next-params-idx-sym vals-sym])
t-body (inline-next-fn t-body t-next-fn-sym [params-sym next-params-idx-sym vals-sym])]
(operation-with-bindings
bindings
params-sym
params-idx-sym
(fn [binding-declarations]
`(reify RichNavigator
(~'rich-select* [this# ~params-sym ~params-idx-sym ~vals-sym ~s-structure-sym ~s-next-fn-sym]
(let [~@binding-declarations
~next-params-idx-sym (+ ~params-idx-sym ~num-params-code)]
~@s-body))
(~'rich-transform* [this# ~params-sym ~params-idx-sym ~vals-sym ~t-structure-sym ~t-next-fn-sym]
(let [~@binding-declarations
~next-params-idx-sym (+ ~params-idx-sym ~num-params-code)]
~@t-body)))))))
(defmacro ^:no-doc rich-nav-with-bindings [opts num-params-code bindings & impls]
(if (:inline-next-fn opts)
(rich-nav-with-bindings-inlined num-params-code bindings impls)
(rich-nav-with-bindings-not-inlined num-params-code bindings impls)))
(defmacro ^:no-doc collector-with-bindings [num-params-code bindings impl] (defmacro ^:no-doc collector-with-bindings [num-params-code bindings impl]
@ -130,7 +168,10 @@
with other navigators without knowing the parameters. When precompiled with other with other navigators without knowing the parameters. When precompiled with other
navigators, the resulting path takes in parameters for all navigators in the path navigators, the resulting path takes in parameters for all navigators in the path
that needed parameters (in the order in which they were declared)." that needed parameters (in the order in which they were declared)."
[params & impls] [& impl]
(let [[opts params & impls] (if (map? (first impl))
impl
(cons {} impl))]
(if (empty? params) (if (empty? params)
`(i/lean-compiled-path (lean-nav* ~@impls)) `(i/lean-compiled-path (lean-nav* ~@impls))
`(vary-meta `(vary-meta
@ -140,11 +181,12 @@
{:type :lean {:type :lean
:params-needed-path :params-needed-path
(i/->ParamsNeededPath (i/->ParamsNeededPath
(rich-nav-with-bindings ~(count params) (rich-nav-with-bindings ~opts
~(count params)
~(delta-param-bindings params) ~(delta-param-bindings params)
~@impls) ~@impls)
~(count params))}))) ~(count params))}))))
(defmacro collector (defmacro collector
@ -214,7 +256,8 @@
(i/lean-compiled-path (lean-nav* ~@impls))) (i/lean-compiled-path (lean-nav* ~@impls)))
(i/->ParamsNeededPath (i/->ParamsNeededPath
(rich-nav-with-bindings ~total-params-sym (rich-nav-with-bindings {}
~total-params-sym
~runtime-bindings ~runtime-bindings
~@impls) ~@impls)

View file

@ -460,14 +460,6 @@
(walk/walk (partial walk-until pred on-match-fn) identity structure))) (walk/walk (partial walk-until pred on-match-fn) identity structure)))
(defn codewalk-until [pred on-match-fn structure]
(if (pred structure)
(on-match-fn structure)
(let [ret (walk/walk (partial codewalk-until pred on-match-fn) identity structure)]
(if (and (i/fn-invocation? structure) (i/fn-invocation? ret))
(with-meta ret (meta structure))
ret))))
(def DISPENSE* (def DISPENSE*
(i/no-params-rich-compiled-path (i/no-params-rich-compiled-path