add direct nav hints

This commit is contained in:
Nathan Marz 2016-09-01 16:31:00 -04:00
parent 479cb7d023
commit f8d74d5884
2 changed files with 31 additions and 17 deletions

View file

@ -603,6 +603,14 @@
(defn dynamic-var? [v] (defn dynamic-var? [v]
(-> v meta :dynamic)) (-> v meta :dynamic))
(defn maybe-direct-nav [obj direct-nav?]
(if direct-nav?
(vary-meta obj assoc :direct-nav true)
obj))
(defn direct-nav? [o]
(-> o meta :direct-nav))
;; don't do coerce-nav here... save that for resolve-magic-code ;; don't do coerce-nav here... save that for resolve-magic-code
(defn- magic-precompilation* [o] (defn- magic-precompilation* [o]
(cond (sequential? o) (cond (sequential? o)
@ -610,11 +618,18 @@
(instance? VarUse o) (instance? VarUse o)
(if (dynamic-var? (:var o)) (if (dynamic-var? (:var o))
(->DynamicVal (:sym o)) (->DynamicVal (maybe-direct-nav
(:val o)) (:sym o)
(or (-> o :var direct-nav?)
(-> o :sym direct-nav?))))
(maybe-direct-nav
(:val o)
(or (-> o :var direct-nav?)
(-> o :sym direct-nav?)
(-> o :val direct-nav?))))
(instance? LocalSym o) (instance? LocalSym o)
;; TODO: check metadata on locals to determine if it's definitely a direct-nav or not
(->DynamicVal (:sym o)) (->DynamicVal (:sym o))
(instance? SpecialFormUse o) (instance? SpecialFormUse o)
@ -692,22 +707,17 @@
(resolve-magic-code path))) (resolve-magic-code path)))
(instance? DynamicVal o) (instance? DynamicVal o)
;;TODO: check ^:nav hint to see whether this is necessary (if (-> o :code direct-nav?)
;;this is relevant for localsyms and dynamicvars (:code o)
;;for localsyms can check metadata in the env as well as metadata on the symbol itself `(coerce-nav ~(:code o)))
;;for dynamic vars check the var metadata
`(coerce-nav ~(:code o))
(instance? DynamicFunction o) (instance? DynamicFunction o)
;;TODO: check ^:nav hint on op to see whether coerce-nav is necessary
;; checked when resolving varuse on the function to know if it returns a direct-nav or not
;; ":direct-nav-fn" metadata as opposed to :direct-nav metadata which is used for symbols/values
(let [op (resolve-dynamic-fn-arg (:op o)) (let [op (resolve-dynamic-fn-arg (:op o))
params (map resolve-dynamic-fn-arg (:params o))] params (map resolve-dynamic-fn-arg (:params o))]
(if (all-static? (conj params op)) (if (all-static? (conj params op))
(coerce-nav (apply op params)) (coerce-nav (apply op params))
`(coerce-nav (~(resolve-dynamic-fn-arg-code op) (let [code `(~(resolve-dynamic-fn-arg-code op) ~@(map resolve-dynamic-fn-arg-code params))]
~@(map resolve-dynamic-fn-arg-code params))))) (if (direct-nav? op) code `(coerce-nav ~code)))))
:else :else
(coerce-nav o))) (coerce-nav o)))

View file

@ -14,9 +14,11 @@
(defmacro richnav [params & impls] (defmacro richnav [params & impls]
(if (empty? params) (if (empty? params)
`(reify RichNavigator ~@impls) `(reify RichNavigator ~@impls)
`(fn ~params `(vary-meta
(reify RichNavigator (fn ~params
~@impls)))) (reify RichNavigator
~@impls))
assoc :direct-nav true)))
(defmacro nav [params & impls] (defmacro nav [params & impls]
@ -196,7 +198,9 @@
(symbol? path) (symbol? path)
(if (contains? locals-set path) (if (contains? locals-set path)
`(com.rpl.specter.impl/->LocalSym ~path (quote ~path)) (let [s (get locals-set path)
embed (i/maybe-direct-nav path (-> s meta :direct-nav))]
`(com.rpl.specter.impl/->LocalSym ~path (quote ~embed)))
;; var-get doesn't work in cljs, so capture the val in the macro instead ;; var-get doesn't work in cljs, so capture the val in the macro instead
`(com.rpl.specter.impl/->VarUse ~path (var ~path) (quote ~path))) `(com.rpl.specter.impl/->VarUse ~path (var ~path) (quote ~path)))