refactor to unify cljs and clj inline caching code
This commit is contained in:
parent
5400e3fd65
commit
8a71d5241d
3 changed files with 122 additions and 44 deletions
|
|
@ -7,6 +7,7 @@
|
|||
#?(:clj [com.rpl.specter.util-macros :only [doseqres mk-comp-navs]]))
|
||||
|
||||
(:require [com.rpl.specter.protocols :as p]
|
||||
[clojure.pprint]
|
||||
[clojure.string :as s]
|
||||
[clojure.walk :as walk]
|
||||
#?(:clj [riddley.walk :as riddley]))
|
||||
|
|
@ -699,54 +700,111 @@
|
|||
o))))
|
||||
|
||||
|
||||
#?(:cljs
|
||||
(do
|
||||
(defprotocol LateResolve
|
||||
(late-resolve [this dynamic-params]))
|
||||
|
||||
;; one of the "possible params"
|
||||
(defrecord LocalParam [idx]
|
||||
LateResolve
|
||||
(late-resolve [this dynamic-params]
|
||||
(nth dynamic-params idx)))
|
||||
|
||||
;; statically precomputed
|
||||
(defrecord StaticParam [val]
|
||||
LateResolve
|
||||
(late-resolve [this dynamic-params]
|
||||
val))
|
||||
|
||||
(mk-late-fn-records)
|
||||
(mk-late-fn)))
|
||||
|
||||
#?(:clj
|
||||
(defn static-fn-code [afn args]
|
||||
`(~afn ~@args))
|
||||
|
||||
:cljs
|
||||
(defn static-fn-code [afn args]
|
||||
(late-fn (->StaticParam afn) args)))
|
||||
|
||||
#?(:clj
|
||||
(defn dynamic-fn-code [afn args]
|
||||
`(~afn ~@args))
|
||||
|
||||
:cljs
|
||||
(defn dynamic-fn-code [afn args]
|
||||
(late-fn afn args)))
|
||||
|
||||
#?(:clj
|
||||
(defn dynamic-val-code [code possible-params]
|
||||
code)
|
||||
|
||||
:cljs
|
||||
(defn dynamic-val-code [code possible-params]
|
||||
;;TODO: need to compute index from possible-params
|
||||
(maybe-direct-nav
|
||||
(local-param possible-params code)
|
||||
(direct-nav? code))))
|
||||
|
||||
#?(:clj
|
||||
(defn static-val-code [o]
|
||||
o)
|
||||
|
||||
:cljs
|
||||
(defn static-val-code [o]
|
||||
(maybe-direct-nav
|
||||
(->StaticParam o)
|
||||
(direct-nav? o))))
|
||||
|
||||
|
||||
(declare resolve-nav-code)
|
||||
|
||||
(defn resolve-arg-code [o]
|
||||
(defn resolve-arg-code [o possible-params]
|
||||
(cond (instance? DynamicFunction o)
|
||||
(let [op (resolve-arg-code (:op o))
|
||||
params (map resolve-arg-code (:params o))]
|
||||
(let [op (resolve-arg-code (:op o) possible-params)
|
||||
params (map #(resolve-arg-code % possible-params) (:params o))]
|
||||
(maybe-direct-nav
|
||||
`(~(original-obj op) ~@params)
|
||||
(dynamic-fn-code (original-obj op) params)
|
||||
(direct-nav? (:op o))))
|
||||
|
||||
(instance? DynamicVal o)
|
||||
(:code o)
|
||||
(dynamic-val-code (:code o) possible-params)
|
||||
|
||||
(instance? DynamicPath o)
|
||||
(resolve-nav-code o)
|
||||
(resolve-nav-code o possible-params)
|
||||
|
||||
:else
|
||||
o))
|
||||
(static-val-code o)))
|
||||
|
||||
|
||||
(defn resolve-nav-code [o]
|
||||
(defn resolve-nav-code [o possible-params]
|
||||
(cond
|
||||
(instance? DynamicPath o)
|
||||
(let [path (:path o)]
|
||||
(if (sequential? path)
|
||||
(let [resolved (vec (map resolve-nav-code path))]
|
||||
(cond (empty? resolved) STAY*
|
||||
(let [resolved (vec (map #(resolve-nav-code % possible-params) path))]
|
||||
(cond (empty? resolved) (static-val-code STAY*)
|
||||
(= 1 (count resolved)) (first resolved)
|
||||
:else `(comp-navs ~@resolved)))
|
||||
(resolve-nav-code path)))
|
||||
:else (static-fn-code comp-navs resolved)))
|
||||
(resolve-nav-code path possible-params)))
|
||||
|
||||
(instance? DynamicVal o)
|
||||
(let [code (:code o)]
|
||||
(cond (direct-nav? code)
|
||||
code
|
||||
(dynamic-val-code code possible-params)
|
||||
|
||||
(or (set? code) (and (fn-invocation? code) (= 'fn* (first code))))
|
||||
`(pred* ~code)
|
||||
(static-fn-code pred* [code])
|
||||
|
||||
:else
|
||||
`(coerce-nav ~code)))
|
||||
(static-fn-code coerce-nav [code])))
|
||||
|
||||
(instance? DynamicFunction o)
|
||||
(let [res (resolve-arg-code o)]
|
||||
(if (direct-nav? res) res `(coerce-nav ~res)))
|
||||
(let [res (resolve-arg-code o possible-params)]
|
||||
(if (direct-nav? res) res (static-fn-code coerce-nav [res])))
|
||||
|
||||
:else
|
||||
(coerce-nav o)))
|
||||
(static-val-code (coerce-nav o))))
|
||||
|
||||
(defn used-locals [locals-set form]
|
||||
(let [used-locals-cell (mutable-cell [])]
|
||||
|
|
@ -764,9 +822,8 @@
|
|||
;; TODO: could have a global flag about whether or not to compile and cache static
|
||||
;; portions, or whether to compile everything together on each invocation (so that
|
||||
;; it can be redefined in repl
|
||||
(defn magic-precompilation [path ns-str used-locals-list]
|
||||
(let [used-locals-set (set used-locals-list)
|
||||
magic-path (-> path magic-precompilation* static-combine)]
|
||||
(defn magic-precompilation [path ns-str used-locals-list possible-params]
|
||||
(let [magic-path (-> path magic-precompilation* static-combine)]
|
||||
(when *DEBUG-INLINE-CACHING*
|
||||
(println "Inline caching debug information")
|
||||
(println "--------------------------------")
|
||||
|
|
@ -778,34 +835,17 @@
|
|||
(println "Static result:" magic-path))
|
||||
(->CachedPathInfo false magic-path))
|
||||
(let [code `(fn [~@used-locals-list]
|
||||
~(resolve-nav-code (->DynamicPath magic-path)))
|
||||
~(resolve-nav-code (->DynamicPath magic-path) possible-params))
|
||||
ns (find-ns (symbol ns-str))
|
||||
maker (binding [*ns* ns] (eval+ code))]
|
||||
|
||||
(when *DEBUG-INLINE-CACHING*
|
||||
(println "Produced code:" code))
|
||||
(println "Produced code:")
|
||||
(clojure.pprint/pprint code)
|
||||
(println))
|
||||
(->CachedPathInfo true maker)))))
|
||||
|
||||
|
||||
; ;; one of the "possible params"
|
||||
; (defrecord LocalParam [idx])
|
||||
;
|
||||
; ;; statically precomputed
|
||||
; (defrecord StaticParam [val])
|
||||
;
|
||||
; ;; what if instead of doing dynamic binding for the params, it generates code
|
||||
; ;; to construct the path
|
||||
; ;; TODO: how to parameterize the static/local params?... that could be dynamic binding
|
||||
; ;; or this makes a function that takes in static + local params, and it executes all arguments with those...
|
||||
; ;; (fn-3 comp-navs (static-param 2) (static-param 3) (local-param 0))
|
||||
;
|
||||
; ;; TODO: redo code to:
|
||||
; ;; - do magic-precompilation* for initial resolve
|
||||
; ;; - compile static parameters together as much as possible
|
||||
;
|
||||
; (defn magic-precompilation-cljs [path ns-str used-locals-list possible-params])
|
||||
|
||||
|
||||
|
||||
(defn compiled-setval* [path val structure]
|
||||
(compiled-transform* path (fast-constantly val) structure))
|
||||
|
|
|
|||
|
|
@ -277,7 +277,8 @@
|
|||
(let [~info-sym (i/magic-precompilation
|
||||
~prepared-path
|
||||
~(str *ns*)
|
||||
(quote ~used-locals))]
|
||||
(quote ~used-locals)
|
||||
nil)]
|
||||
~add-cache-code
|
||||
~info-sym)
|
||||
info#)
|
||||
|
|
|
|||
|
|
@ -28,3 +28,40 @@
|
|||
(~'comp-navs
|
||||
(~'comp-navs ~@last-syms)
|
||||
(reduce ~'comp-navs rest#))))))
|
||||
|
||||
|
||||
|
||||
;;TODO: move these definitions somewhere else
|
||||
(defn late-fn-record-name [i]
|
||||
(symbol (str "LateFn" i)))
|
||||
|
||||
(defn late-fn-record-constructor-name [i]
|
||||
(symbol (str "->LateFn" i)))
|
||||
|
||||
(defn- mk-late-fn-record [i]
|
||||
(let [fields (gensyms (inc i))
|
||||
dparams (gensym "dynamic-params")
|
||||
resolvers (for [f fields]
|
||||
`(late-resolve ~f ~dparams))]
|
||||
`(defrecord ~(late-fn-record-name i) [~@fields]
|
||||
~'LateResolve
|
||||
(~'late-resolve [this# ~dparams]
|
||||
(~@resolvers)))))
|
||||
|
||||
|
||||
(defmacro mk-late-fn-records []
|
||||
(let [impls (for [i (range 20)] (mk-late-fn-record i))]
|
||||
`(do ~@impls)))
|
||||
|
||||
(defmacro mk-late-fn []
|
||||
(let [f (gensym "afn")
|
||||
args (gensym "args")
|
||||
cases (for [i (range 19)]
|
||||
(let [gets (for [j i] `(nth ~args ~j))]
|
||||
`(~(late-fn-record-constructor-name i)
|
||||
~f
|
||||
~@gets)))]
|
||||
`(defn ~'late-fn [~f ~args]
|
||||
(case (count ~args)
|
||||
~@cases
|
||||
(com.rpl.specter.impl/throw-illegal "Cannot have late function with more than 18 args")))))
|
||||
|
|
|
|||
Loading…
Reference in a new issue