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

View file

@ -9,6 +9,7 @@
(:require [com.rpl.specter.protocols :as p]
[clojure.string :as s]
[clojure.walk :as walk]
#?(:clj [com.rpl.specter.defhelpers :as dh])
#?(:clj [riddley.walk :as riddley]))
@ -652,6 +653,14 @@
#?(:cljs (instance? cljs.core.LazySeq 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])
(defn layered-nav? [o] (instance? LayeredNav o))

View file

@ -62,13 +62,13 @@
`(let [~@binding-fn-declarations]
~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*
[[_ t-structure-sym t-next-fn-sym] & t-body] 'transform*}
(determine-params-impls impls)
params-sym (gensym "params")
params-idx-sym (gensym "params-idx")]
(operation-with-bindings
bindings
params-sym
@ -95,6 +95,44 @@
structure#))]
~@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]
@ -130,21 +168,25 @@
with other navigators without knowing the parameters. When precompiled with other
navigators, the resulting path takes in parameters for all navigators in the path
that needed parameters (in the order in which they were declared)."
[params & impls]
(if (empty? params)
`(i/lean-compiled-path (lean-nav* ~@impls))
`(vary-meta
(fn ~params (i/lean-compiled-path (lean-nav* ~@impls)))
assoc
:highernav
{:type :lean
:params-needed-path
(i/->ParamsNeededPath
(rich-nav-with-bindings ~(count params)
~(delta-param-bindings params)
~@impls)
[& impl]
(let [[opts params & impls] (if (map? (first impl))
impl
(cons {} impl))]
(if (empty? params)
`(i/lean-compiled-path (lean-nav* ~@impls))
`(vary-meta
(fn ~params (i/lean-compiled-path (lean-nav* ~@impls)))
assoc
:highernav
{:type :lean
:params-needed-path
(i/->ParamsNeededPath
(rich-nav-with-bindings ~opts
~(count params)
~(delta-param-bindings params)
~@impls)
~(count params))})))
~(count params))}))))
(defmacro collector
@ -214,7 +256,8 @@
(i/lean-compiled-path (lean-nav* ~@impls)))
(i/->ParamsNeededPath
(rich-nav-with-bindings ~total-params-sym
(rich-nav-with-bindings {}
~total-params-sym
~runtime-bindings
~@impls)

View file

@ -460,14 +460,6 @@
(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*
(i/no-params-rich-compiled-path