generate a real higher order function from defnav and defcollector that returns a lean compiled path when invoked but coerces to equivalent paramsneededpath when composed, change nav constructors to recognize this and use a lean proxy for this case
This commit is contained in:
parent
7bfad80e00
commit
56da47aca5
3 changed files with 78 additions and 33 deletions
|
|
@ -64,7 +64,7 @@
|
|||
(defn throw-illegal [& args]
|
||||
(throw (js/Error. (apply str args))))
|
||||
|
||||
;; need to get the expansion function like this so that
|
||||
;; need to get the expansion function like this so that
|
||||
;; this code compiles in a clojure environment where cljs.analyzer
|
||||
;; namespace does not exist
|
||||
#+clj
|
||||
|
|
@ -221,7 +221,7 @@
|
|||
p11 p12 p13 p14 p15 p16 p17 p18 p19 p20
|
||||
rest]
|
||||
(let [a (object-array
|
||||
(concat
|
||||
(concat
|
||||
[p01 p02 p03 p04 p05 p06 p07 p08 p09 p10
|
||||
p11 p12 p13 p14 p15 p16 p17 p18 p19 p20]
|
||||
rest))]
|
||||
|
|
@ -263,8 +263,12 @@
|
|||
empty?
|
||||
not))
|
||||
|
||||
(defn root-params-nav? [o]
|
||||
(and (fn? o) (-> o meta :highernav)))
|
||||
|
||||
(defn- coerce-object [this]
|
||||
(cond (satisfies? p/ImplicitNav this) (p/implicit-nav this)
|
||||
(cond (root-params-nav? this) (-> this meta :highernav :params-needed-path)
|
||||
(satisfies? p/ImplicitNav this) (p/implicit-nav this)
|
||||
:else (throw-illegal "Not a navigator: " this)
|
||||
))
|
||||
|
||||
|
|
@ -300,7 +304,7 @@
|
|||
#+cljs cljs.core/LazySeq
|
||||
#+cljs (coerce-path [this]
|
||||
(coerce-path (vec this)))
|
||||
|
||||
|
||||
#+clj Object #+cljs default
|
||||
(coerce-path [this]
|
||||
(coerce-object this)))
|
||||
|
|
@ -356,7 +360,7 @@
|
|||
|
||||
(satisfies? Navigator (:nav path))
|
||||
path
|
||||
|
||||
|
||||
:else
|
||||
(let [^ParameterizedRichNav prich-nav (:nav path)
|
||||
rich-nav (.-rich-nav prich-nav)
|
||||
|
|
@ -482,7 +486,7 @@
|
|||
(.-traverse-executor ex))
|
||||
|
||||
|
||||
;; amazingly doing this as a macro shows a big effect in the
|
||||
;; amazingly doing this as a macro shows a big effect in the
|
||||
;; benchmark for getting a value out of a nested map
|
||||
#+clj
|
||||
(defmacro compiled-traverse* [path result-fn structure]
|
||||
|
|
@ -626,8 +630,9 @@
|
|||
|
||||
(defn verify-layerable! [anav]
|
||||
(if-not
|
||||
(and (instance? ParamsNeededPath anav)
|
||||
(> (:num-needed-params anav) 0))
|
||||
(or (root-params-nav? anav)
|
||||
(and (instance? ParamsNeededPath anav)
|
||||
(> (:num-needed-params anav) 0)))
|
||||
(throw-illegal "defnavconstructor must be used on a navigator defined with
|
||||
defnav with at least one parameter")
|
||||
))
|
||||
|
|
@ -771,6 +776,30 @@
|
|||
1
|
||||
))
|
||||
|
||||
(def lean-compiled-path-proxy
|
||||
(->ParamsNeededPath
|
||||
(reify RichNavigator
|
||||
(rich-select* [this params params-idx vals structure next-fn]
|
||||
(let [^CompiledPath apath (aget ^objects params params-idx)
|
||||
^Navigator nav (.-nav apath)]
|
||||
(exec-select*
|
||||
nav
|
||||
structure
|
||||
(fn [structure-next]
|
||||
(next-fn params params-idx vals structure-next))
|
||||
)))
|
||||
(rich-transform* [this params params-idx vals structure next-fn]
|
||||
(let [^CompiledPath apath (aget ^objects params params-idx)
|
||||
^Navigator nav (.-nav apath)]
|
||||
(exec-transform*
|
||||
nav
|
||||
structure
|
||||
(fn [structure-next]
|
||||
(next-fn params params-idx vals structure-next))
|
||||
))))
|
||||
1
|
||||
))
|
||||
|
||||
(defn srange-transform* [structure start end next-fn]
|
||||
(let [structurev (vec structure)
|
||||
newpart (next-fn (-> structurev (subvec start end)))
|
||||
|
|
@ -851,14 +880,14 @@
|
|||
(if (-> v meta :dynamic)
|
||||
(magic-fail! "Var " (:sym op) " is dynamic")
|
||||
(cond
|
||||
(instance? ParamsNeededPath vv)
|
||||
(or (root-params-nav? vv) (instance? ParamsNeededPath vv))
|
||||
;;TODO: if all params are constants, then just bind the path right here
|
||||
;;otherwise, add the params
|
||||
;; - could extend this to see if it contains nested function calls which
|
||||
;; are only on constants
|
||||
(do
|
||||
(swap! params-atom #(vec (concat % ps)))
|
||||
vv
|
||||
(coerce-path vv)
|
||||
)
|
||||
|
||||
(and (fn? vv) (-> v meta :pathedfn))
|
||||
|
|
@ -899,9 +928,12 @@
|
|||
|
||||
(and (fn? vv) (-> vv meta :layerednav))
|
||||
(do
|
||||
;;TODO: if all args are constant then invoke it right here
|
||||
(swap! params-atom conj (:code p))
|
||||
rich-compiled-path-proxy
|
||||
)
|
||||
(if (= (-> vv meta :layerednav) :lean)
|
||||
lean-compiled-path-proxy
|
||||
rich-compiled-path-proxy
|
||||
))
|
||||
|
||||
:else
|
||||
(magic-fail! "Var " (:sym op) " must be either a parameterized "
|
||||
|
|
|
|||
|
|
@ -45,10 +45,10 @@
|
|||
(i/->ParamsNeededPath nav# num-params#)
|
||||
))))
|
||||
|
||||
(defmacro lean-nav* [& impls]
|
||||
(defmacro ^:no-doc lean-nav* [& impls]
|
||||
`(reify Navigator ~@impls))
|
||||
|
||||
(defn operation-with-bindings [bindings params-sym params-idx-sym op-maker]
|
||||
(defn ^:no-doc operation-with-bindings [bindings params-sym params-idx-sym op-maker]
|
||||
(let [bindings (partition 2 bindings)
|
||||
binding-fn-syms (gensyms (count bindings))
|
||||
binding-syms (map first bindings)
|
||||
|
|
@ -62,7 +62,7 @@
|
|||
~body
|
||||
)))
|
||||
|
||||
(defmacro rich-nav-with-bindings [num-params-code bindings & impls]
|
||||
(defmacro ^:no-doc rich-nav-with-bindings [num-params-code bindings & impls]
|
||||
(let [[[[_ s-structure-sym s-next-fn-sym] & s-body]
|
||||
[[_ t-structure-sym t-next-fn-sym] & t-body]]
|
||||
(apply determine-params-impls impls)
|
||||
|
|
@ -97,7 +97,7 @@
|
|||
))
|
||||
)))))
|
||||
|
||||
(defmacro collector-with-bindings [num-params-code bindings impl]
|
||||
(defmacro ^:no-doc collector-with-bindings [num-params-code bindings impl]
|
||||
(let [[_ [_ structure-sym] & body] impl
|
||||
params-sym (gensym "params")
|
||||
params-idx-sym (gensym "params")]
|
||||
|
|
@ -133,14 +133,19 @@
|
|||
[params & impls]
|
||||
(if (empty? params)
|
||||
`(i/lean-compiled-path (lean-nav* ~@impls))
|
||||
`(i/->ParamsNeededPath
|
||||
;(fn ~params (lean-nav* ~@body))
|
||||
(rich-nav-with-bindings ~(count params)
|
||||
~(delta-param-bindings params)
|
||||
~@impls
|
||||
)
|
||||
~(count params)
|
||||
)))
|
||||
`(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
|
||||
)
|
||||
~(count params))}
|
||||
)))
|
||||
|
||||
(defmacro collector
|
||||
"Defines a Collector with late bound parameters. This collector can be precompiled
|
||||
|
|
@ -155,13 +160,20 @@
|
|||
)]
|
||||
(if ~(empty? params)
|
||||
(i/no-params-rich-compiled-path rich-nav#)
|
||||
(i/->ParamsNeededPath
|
||||
; (fn ~params
|
||||
; (collector-with-bindings 0
|
||||
; ~impl-body))
|
||||
rich-nav#
|
||||
~(count params))
|
||||
)))
|
||||
(vary-meta
|
||||
(fn ~params
|
||||
(i/no-params-rich-compiled-path
|
||||
(collector-with-bindings 0 []
|
||||
~body)))
|
||||
assoc
|
||||
:highernav
|
||||
{:type :rich
|
||||
:params-needed-path
|
||||
(i/->ParamsNeededPath
|
||||
rich-nav#
|
||||
~(count params)
|
||||
)}
|
||||
))))
|
||||
|
||||
(defn ^:no-doc fixed-pathed-operation [bindings op-maker]
|
||||
(let [bindings (partition 2 bindings)
|
||||
|
|
@ -413,7 +425,8 @@
|
|||
(vary-meta
|
||||
(let [~csym (i/layered-wrapper ~anav)]
|
||||
(fn ~@checked-code))
|
||||
assoc :layerednav true))
|
||||
assoc :layerednav (or (-> ~anav meta :highernav :type) :rich)
|
||||
))
|
||||
))
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -1291,7 +1291,7 @@
|
|||
(deftest multi-path-vals-test
|
||||
(is (= {:a 1 :b 6 :c 3}
|
||||
(transform [(s/multi-path (s/collect-one :a) (s/collect-one :c)) :b]
|
||||
+
|
||||
+
|
||||
{:a 1 :b 2 :c 3})))
|
||||
(is (= [[1 2] [3 2]]
|
||||
(select [(s/multi-path (s/collect-one :a) (s/collect-one :c)) :b]
|
||||
|
|
|
|||
Loading…
Reference in a new issue