get macroexpansion for clojurescript working correctly so that collected? works inside inline paths

This commit is contained in:
Nathan Marz 2016-06-13 17:23:23 -04:00
parent 1f21fa5a9d
commit 8c128816f5
3 changed files with 53 additions and 38 deletions

View file

@ -48,28 +48,29 @@
(defn throw-illegal [& args] (defn throw-illegal [& args]
(throw (js/Error. (apply str args)))) (throw (js/Error. (apply str args))))
;; these macroexpand functions are for path macro in bootstrap cljs environment
#+cljs
(defn macroexpand'
[form]
(let [orig-eval-fn ^:cljs.analyzer/no-resolve cljs.js/*eval-fn*]
(try
(set! ^:cljs.analyzer/no-resolve cljs.js/*eval-fn* ^:cljs.analyzer/no-resolve cljs.js/js-eval)
(^:cljs.analyzer/no-resolve cljs.js/eval (^:cljs.analyzer/no-resolve cljs.js/empty-state)
`(macroexpand (quote ~form))
identity)
(finally
(set! ^:cljs.analyzer/no-resolve cljs.js/*eval-fn* orig-eval-fn)))))
#+cljs ;; these macroexpand functions are for path macro in bootstrap cljs environment
(defn do-macroexpand-all ; #+cljs
"Recursively performs all possible macroexpansions in form." ; (defn macroexpand'
{:added "1.1"} ; [form]
[form] ; (let [orig-eval-fn ^:cljs.analyzer/no-resolve cljs.js/*eval-fn*]
(walk/prewalk (fn [x] ; (try
(if (seq? x) ; (set! ^:cljs.analyzer/no-resolve cljs.js/*eval-fn* ^:cljs.analyzer/no-resolve cljs.js/js-eval)
(macroexpand' x) ; (^:cljs.analyzer/no-resolve cljs.js/eval (^:cljs.analyzer/no-resolve cljs.js/empty-state)
x)) form)) ; `(macroexpand (quote ~form))
; identity)
; (finally
; (set! ^:cljs.analyzer/no-resolve cljs.js/*eval-fn* orig-eval-fn)))))
; #+cljs
; (defn do-macroexpand-all
; "Recursively performs all possible macroexpansions in form."
; {:added "1.1"}
; [form]
; (walk/prewalk (fn [x]
; (if (seq? x)
; (macroexpand' x)
; x)) form))
#+clj #+clj
(defn intern* [ns name val] (intern ns name val)) (defn intern* [ns name val] (intern ns name val))
@ -78,10 +79,6 @@
(defn intern* [ns name val] (defn intern* [ns name val]
(throw-illegal "intern not supported in ClojureScript")) (throw-illegal "intern not supported in ClojureScript"))
#+clj
(defn do-macroexpand-all [form]
(riddley/macroexpand-all form))
;; so that macros.clj compiles appropriately when ;; so that macros.clj compiles appropriately when
;; run in cljs (this code isn't called in that case) ;; run in cljs (this code isn't called in that case)
#+cljs #+cljs

View file

@ -1,6 +1,7 @@
(ns com.rpl.specter.macros (ns com.rpl.specter.macros
(:require [com.rpl.specter.impl :as i] (:require [com.rpl.specter.impl :as i]
[clojure.walk :as cljwalk]) [clojure.walk :as cljwalk]
[riddley.walk :as riddley])
) )
(defn ^:no-doc gensyms [amt] (defn ^:no-doc gensyms [amt]
@ -444,6 +445,27 @@
path path
))) )))
(defn cljs-macroexpand [env form]
(require 'cljs.analyzer)
(let [expand-fn (eval 'cljs.analyzer/macroexpand-1)
mform (expand-fn env form)]
(cond (identical? form mform) mform
(and (seq? mform) (#{'js*} (first mform))) form
:else (cljs-macroexpand env mform))))
(defn cljs-macroexpand-all* [env form]
(if (and (seq? form)
(#{'fn 'fn* 'cljs.core/fn} (first form)))
form
(let [expanded (if (seq? form) (cljs-macroexpand env form) form)]
(cljwalk/walk #(cljs-macroexpand-all* env %) identity expanded)
)))
(defn cljs-macroexpand-all [env form]
(let [ret (cljs-macroexpand-all* env form)]
ret
))
;; still possible to mess this up with alter-var-root ;; still possible to mess this up with alter-var-root
(defmacro path (defmacro path
"Same as calling comp-paths, except it caches the composition of the static part "Same as calling comp-paths, except it caches the composition of the static part
@ -470,7 +492,10 @@
;; note: very important to use riddley's macroexpand-all here, so that ;; note: very important to use riddley's macroexpand-all here, so that
;; &env is preserved in any potential nested calls to select (like via ;; &env is preserved in any potential nested calls to select (like via
;; a view function) ;; a view function)
expanded (i/do-macroexpand-all (vec path)) expanded (if (= platform :clj)
(riddley/macroexpand-all (vec path))
(cljs-macroexpand-all &env (vec path)))
prepared-path (ic-prepare-path local-syms expanded) prepared-path (ic-prepare-path local-syms expanded)
possible-params (vec (ic-possible-params expanded)) possible-params (vec (ic-possible-params expanded))
@ -624,11 +649,8 @@
"Creates a filter function navigator that takes in all the collected values "Creates a filter function navigator that takes in all the collected values
as input. For arguments, can use `(collected? [a b] ...)` syntax to look as input. For arguments, can use `(collected? [a b] ...)` syntax to look
at each collected value as individual arguments, or `(collected? v ...)` syntax at each collected value as individual arguments, or `(collected? v ...)` syntax
to capture all the collected values as a single vector. to capture all the collected values as a single vector."
For ClojureScript, since can't use macros inside path when that path will be
inline factored/cached, to use collected? declare the logic in a global
variable such as (def my-collected (collected? [v] (= v 1)))"
[params & body] [params & body]
`(i/collected?* (fn [~params] ~@body)) (let [platform (if (contains? &env :locals) :cljs :clj)]
) `(i/collected?* (~'fn [~params] ~@body))
))

View file

@ -1224,10 +1224,6 @@
m) m)
))) )))
;; clojure only because inability to use macroexpand inside path macro in
;; clojurescript makes it impossible to use macros inside the path
#+clj
(deftest collected?-test (deftest collected?-test
(let [data {:active-id 1 :items [{:id 1 :name "a"} {:id 2 :name "b"}]}] (let [data {:active-id 1 :items [{:id 1 :name "a"} {:id 2 :name "b"}]}]
(is (= {:id 1 :name "a"} (is (= {:id 1 :name "a"}