问题描述
编写 clojurescript 宏的作者没有符号到 var 解析的功能。也就是说,在宏展开时期将符号扩展为其完全限定形式。
+ ;; -> cljs.core/+
s/def ;; -> cljs.spec.alpha/def
在 JVM 中,这当然是一个可能。
在 cljs 中,没有这样的可能性,至少干净的做法没有。
- 存在
cljs.core/resolve
宏,但我认为它是针对 cljs 最终代码的,而不是针对 cljs 的宏。
- 具体来说,
cljs.core/resolve
预期一个引用过的符号,这对于宏编写者来说是一个不必要的限制。
cljs.core/resolve
返回一个新的 var,而不是原始的 var。这将丢弃用户提供的元数据。
- 因此,宏编写者无法观察用户提供的元数据以执行宏展开时期的自定义逻辑
请求
使 cljs.core/resolve
更灵活,或者创建一个专门针对宏编写者的独立解析函数
用例
我有一些现有的 JVM 宏,使用 resolve
在宏展开时期,需要迁移到 cljs。也就是说,这个请求来自实际需求。
解决方案
以下函数工作良好,满足了描述的要求。
但是,合理地认为它是在玩 cljs 内部,因此它可能与新的 cljs 发布版不兼容。
(defn cljs-resolve
[env sym]
(let [[var meta] (try
(let [var (cljs.analyzer/resolve-var env sym (cljs.analyzer/confirm-var-exists-throw))]
[var (cljs.analyzer/var-meta var)])
(catch Throwable t
[(cljs.analyzer/resolve-var env sym) nil]))]
(some-> var
:name
(vary-meta assoc :cljs.analyzer/no-resolve true)
(vary-meta merge meta))))