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:
Nathan Marz 2016-08-05 17:59:12 -04:00
parent 7bfad80e00
commit 56da47aca5
3 changed files with 78 additions and 33 deletions

View file

@ -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 "

View file

@ -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)
))
))

View file

@ -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]