问题描述
在中提供了 eval-str
来运行包含ClojureScript的字符串:
In this blog post by Dmitri Sotnikov a function eval-str
is provided for running a string containing ClojureScript:
(defn eval-str [s]
(eval (empty-state)
(read-string s)
{:eval js-eval
:source-map true
:context :expr}
(fn [result] result)))
如果我想在eval字符串中调用某些函数 x
,我该怎么做?
If I have some function x
that I want to be able to call from inside the eval string, how can I do that?
推荐答案
答案有两部分,假设 x
是与ClojureScript函数关联的变量:
There are two parts to the answer, assuming x
is a var associated with a ClojureScript function:
-
x
的编译器分析元数据必须以通过的状态存在作为cljs.js / eval
的第一个参数。这样一来,在编译过程中,例如,会知道x
的Arity之类的东西。 - 该函数的JavaScript实现与
x
关联的代码需要出现在JavaScript运行时中。 (尤其是如果在cljs.js / eval
调用期间实际上是调用的函数,而不仅仅是引用了该函数。)
- The compiler analysis metadata for
x
needs to be present in the state passed as the first argument tocljs.js/eval
. This is so that, during compilation, things like the arity ofx
is known, for example. - The JavaScript implementation of the function associated with
x
needs to be present in the JavaScript runtime. (This is especially true if the function is actually called during thecljs.js/eval
call, and not just referenced.)
如果 x
是核心功能(例如var #'例如clcl.core / map
),那么这两个条件都会自动满足。特别地,元数据将在调用 cljs.js / empty-state
时生成(假设是 true
),并且实现
If x
is a core function (say the var #'cljs.core/map
for example), then both of these conditions is automatically satisfied. In particular, the metadata will be produced when cljs.js/empty-state
is called (assuming :dump-core
is true
), and the implementation of the core functions will have already been loaded into the JavaScript runtime.
但是,可以说 x
完全是您希望在自托管环境中编译的新函数。 技巧是建立并重新使用编译器状态:例如,将(cljs.js.empty-state)
的结果放入var中,并将其传递给每个 cljs.js / eval
调用。如果这样做,则 cljs.js / eval
调用之一涉及为<$ c $编译 defn
c> x ,那么编译器状态将被修改(实际上是一个原子),结果是 x
会进入状态,当然还会在JavaScript环境中设置 x
的JavaScript实现(通过评估JavaScript
But, let's say x
is a wholly new function that you wish to have compiled in the self-hosted environment. The "trick" is to set up and reuse compiler state: For example put the result of (cljs.js.empty-state)
into a var, and pass it to every cljs.js/eval
call. If you do that, and one of the cljs.js/eval
calls involves compiling a defn
for x
, then the compiler state will be modified (it is actually an atom), with the result being that the compiler metadata for x
will be put in the state, along with, of course, the JavaScript implementation for x
being set within the JavaScript environment (by virtue of evaluating the JavaScript produced for the 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!
函数作为此用例的帮助程序存在,并且一个独立的示例位于
If, on the other hand, x
is a function that is part of your "ambient" ClojureScript environment (say, pre-compiled via the JVM ClojureScript compiler, but nevertheless available in the JavaScript runtime), then it will be up to you to somehow to arrange to get the compiler analysis metadata for x
into the state passed to cljs.js/eval
. If you look at the output of the JVM-based compiler, you will see <ns-name>.cache.json
files containing such metadata. Take a look at the data that is in these files and you can ascertain its structure; with that you can see how to swap the needed information into the compiler state under [:cljs.analyzer/namespaces <ns-name>]
. The cljs.js/load-analysis-cache!
function exists as a helper for this use case, and a self-contained example is at https://stackoverflow.com/a/51575204/4284484
这篇关于如何使函数可用于ClojureScript的评估?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!