      :load - library resolution function, see *load-fn*
 
    cb (function)
-     callback, will be invoked with the evalution result."
+     callback, will be invoked with a map. If successful the map will contain
+     a :value key with the result of evalution. If unsuccessful the map wil
+     contain a :error key with an ex-info instance describing the cause of
+     failure."
   ([state form cb]
    (eval state form nil cb))
   ([state form opts cb]

;; -----------------------------------------------------------------------------
;; Eval

;; TODO: ns form handling, source mapping

(defn eval* [bound-vars form opts cb]
  (binding [env/*compiler*   (:*compiler* bound-vars)
            *eval-fn*        (:*eval-fn* bound-vars)
            ana/*cljs-ns*    (:*cljs-ns* bound-vars)
            *ns*             (:*ns* bound-vars)
            r/*data-readers* (:*data-readers* bound-vars)]
    (let [aenv (ana/empty-env)
          aenv (cond-> (assoc aenv :ns (ana/get-namespace ana/*cljs-ns*))
                 (:context opts) (assoc :context (:context opts))
                 (:def-emits-var opts) (assoc :def-emits-var true))]
      (cb (*eval-fn*
            {:lang   :clj
             :source (with-out-str
                       (comp/emit (ana/analyze aenv form nil opts)))})))))

(defn eval
  "Evaluate a single ClojureScript form. The parameters:

      :*cljs-ns*      'cljs.user
      :*ns*           (create-ns 'cljs.user)
      :*data-readers* tags/*cljs-data-readers*
      :*analyze-deps* (or (:analyze-deps opts) true)
      :*load-macros*  (or (:load-macros opts) true)
      :*load-fn*      (or (:load opts) *load-fn*)
      :*eval-fn*      (or (:eval opts) *eval-fn*)}
     form opts cb)))
