我正在尝试编写一个宏,给定一个表单,将所有缺失的符号定义为它们。
到目前为止,我有以下内容:
(def ^:private missing-symbol-pattern #"Unable to resolve symbol: (.+) in this context")
(cl/defn ^:private missing-symbol [s]
(cl/when-let [[_ sym] (cl/re-find missing-symbol-pattern s)] sym))
(cl/defmacro try-eval [expr]
`(try (do (cl/println '~expr) (cl/eval '~expr))
(catch Exception e#
(cl/if-let [sym# (do (cl/println (.getMessage e#)) (missing-symbol (.getMessage e#)))]
(cl/eval `(do
(def ~(cl/symbol sym#) '~(cl/symbol sym#))
(cl/println ~sym#)
(try-eval ~'~expr)))
(cl/eval `(throw ~e#))))))
(cl
这里是clojure.core
的别名)
我知道副作用可能存在问题,但这里并不重要(尽管没有副作用问题的解决方案会更好)
如果有多个缺失(不可解析)符号,我会收到以下异常:
java.lang.RuntimeException: Can't embed object in code, maybe print-dup not defined: java.lang.ClassCastException: clojure.lang.Symbol cannot be cast to clojure.lang.IDeref, compiling:(shen/primitives.clj:517)
有谁知道要改变什么?是否有一些“现成的”解决方案?
干杯
答案 0 :(得分:3)
不是使用try / catch查找无法解析的符号,也许您可以使用&env
中可用的defmacro
符号执行某些操作。 &env
的键是本地定义的符号。
(Article about &env and &form.)
使用resolve
和(keys &env)
的组合可以隔离未定义的符号,然后您可以选择def (not (or (resolve sym) (contains? &env sym))
我们在Midje source code中做了类似于此的事情,以确定表格测试中的哪些符号已经定义,哪些符号不是:
[注意:以下代码locals
实际上是(keys &env)
]
(defn- headings-rows+values [table locals]
(letfn [(table-variable? [s]
(and (symbol? s)
(not (metaconstant-symbol? s))
(not (resolve s))
(not (contains? locals s))))]
(split-with table-variable? (remove-pipes+where table))))