问题陈述
正在为ClojureScript编写宏的作者没有一种将符号解析为变量的功能。也就是说,在宏扩展时将符号展开为其完全限定形式
+ ;; -> cljs.core/+
s/def ;; -> cljs.spec.alpha/def
在JVM中,这绝对是一种可能性。
在cljs中,没有这样的可能性,至少不是那么干净。
- 存在一个
cljs.core/resolve
宏,但我认为它是针对cljs最终代码设计的,而不是针对cljs的宏。
- 具体来说,
cljs.core/resolve
期望一个引用的符号,这对于宏编写者来说是一个不必要的限制。
cljs.core/resolve
返回一个新的变量,而不是原始变量。这会丢失用户提供的元数据。
- 因此,宏编写者无法观察用户提供的元数据来执行宏扩展时自定义逻辑
请求
使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))))