如何使函数可用于ClojureScript的eval?

时间:2018-06-13 01:39:53

标签: eval clojurescript

this blog post by Dmitri Sotnikov中,提供了一个函数eval-str来运行包含ClojureScript的字符串:

(defn eval-str [s]
  (eval (empty-state)
        (read-string s)
        {:eval       js-eval
         :source-map true
         :context    :expr}
        (fn [result] result)))

如果我有一些函数x我希望能够从eval字符串中调用,我该怎么做?

1 个答案:

答案 0 :(得分:2)

答案分为两部分,假设x是与ClojureScript函数关联的var:

  1. x的编译器分析元数据需要存在于作为cljs.js/eval的第一个参数传递的状态中。这样,在编译期间,例如x的arity之类的东西是已知的。
  2. x相关联的函数的JavaScript实现需要存在于JavaScript运行时中。 (如果在cljs.js/eval调用期间函数实际上是调用,并且不仅仅是引用,则尤其如此。)
  3. 如果x是核心函数(例如var #'cljs.core/map),则会自动满足这两个条件。特别是,在调用cljs.js/empty-state时(假设:dump-coretrue)将生成元数据,并且核心函数的实现将已加载到JavaScript运行时。

    但是,假设x是一个全新的函数,您希望在自托管环境中编译。 “技巧”是设置和重用编译器状态:例如,将(cljs.js.empty-state)的结果放入var中,并将其传递给每个cljs.js/eval调用。如果你这样做,并且其中一个cljs.js/eval调用涉及为defn编译x,则编译器状态将被修改(它实际上是一个原子),结果是x的编译器元数据将被置于状态,当然,在JavaScript环境中设置x的JavaScript实现(通过评估为defn生成的JavaScript。

    另一方面,如果x是一个函数,它是“环境”ClojureScript环境的一部分(比如,通过JVM ClojureScript编译器预编译,但在JavaScript运行时仍可用),那么您将以某种方式安排将x的编译器分析元数据放入传递给cljs.js/eval的状态。如果查看基于JVM的编译器的输出,您将看到包含此​​类元数据的<ns-name>.cache.json个文件。查看这些文件中的数据,您可以确定其结构;您可以看到如何将所需信息交换到[:cljs.analyzer/namespaces <ns-name>]下的编译器状态。 cljs.js/load-analysis-cache!函数作为此用例的帮助程序存在,自包含的示例位于https://stackoverflow.com/a/51575204/4284484