首页 > 解决方案 > 如何使函数可用于 ClojureScript 的 eval?

问题描述

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 字符串内部调用的函数,我该怎么做?

标签: evalclojurescript

解决方案


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

  1. 的编译器分析元数据x需要以作为第一个参数传递给cljs.js/eval. 这样,例如,在编译期间,诸如 arity 之类的东西x是已知的。
  2. 相关函数的 JavaScript 实现x需要存在于 JavaScript 运行时中。(如果在调用过程中实际调用cljs.js/eval了函数,而不仅仅是引用,则尤其如此。)

如果x是一个核心函数(例如 var #'cljs.core/map),那么这两个条件都会自动满足。特别是,元数据将在cljs.js/empty-state被调用时生成(假设:dump-coretrue),并且核心函数的实现已经加载到 JavaScript 运行时中。

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

另一方面,如果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


推荐阅读