How can I make functions available to ClojureScript's eval?

给你一囗甜甜゛ 提交于 2019-12-12 20:03:32

问题


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)))

If I have some function x that I want to be able to call from inside the eval string, how can I do that?


回答1:


There are two parts to the answer, assuming x is a var associated with a ClojureScript function:

  1. The compiler analysis metadata for x needs to be present in the state passed as the first argument to cljs.js/eval. This is so that, during compilation, things like the arity of x is known, for example.
  2. 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 the cljs.js/eval call, and not just referenced.)

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.

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).

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



来源:https://stackoverflow.com/questions/50828008/how-can-i-make-functions-available-to-clojurescripts-eval

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!