special form | since v0.0-927 | clojure.core/set! | Edit |
(set! var-symbol expr)
(set! (.- instance-expr instanceFieldName-symbol) expr)
Sets js-var
to val
using the JavaScript =
operator.
Used to set vars and JavaScript object fields
(defmethod parse 'set!
[_ env [_ target val alt :as form] _ _]
(let [[target val] (if (= 4 (count form))
;; (set! o -prop val)
[`(. ~target ~val) alt]
[target val])]
(disallowing-recur
(binding [*private-var-access-nowarn* true]
(let [enve (assoc env :context :expr)
texpr (cond
(symbol? target)
(do
(cond
(and (= target '*unchecked-if*) ;; TODO: proper resolve
(or (true? val) (false? val)))
(set! *unchecked-if* val)
(and (= target '*unchecked-arrays*) ;; TODO: proper resolve
(or (true? val) (false? val)))
(set! *unchecked-arrays* val)
(and (= target '*warn-on-infer*)
(or (true? val) (false? val)))
(set! *cljs-warnings* (assoc *cljs-warnings* :infer-warning val)))
(when (some? (:const (resolve-var (dissoc env :locals) target)))
(throw (error env "Can't set! a constant")))
(let [local (handle-symbol-local target (-> env :locals target))]
(when-not (or (nil? local)
(and (:field local)
(or (:mutable local)
(:unsynchronized-mutable local)
(:volatile-mutable local))))
(throw (error env "Can't set! local var or non-mutable field"))))
(analyze-symbol enve target))
:else
(when (seq? target)
(let [texpr (if (-> target meta :extend-type)
;; we're setting a prototype via extend-type macro
;; nothing to warn
(binding [*cljs-warnings*
(assoc *cljs-warnings* :infer-warning false)]
(analyze-seq enve target nil))
(analyze-seq enve target nil))]
(when (:field texpr)
texpr))))
vexpr (analyze enve val)]
;; as top level fns are decomposed for Closure cross-module code motion, we need to
;; restore their :methods information
(when (seq? target)
(let [sym (some-> target second)
meta (meta sym)]
(when-let [info (and (= :fn (:op vexpr)) (:top-fn meta))]
(swap! env/*compiler* update-in
[::namespaces (-> env :ns :name) :defs sym :methods]
(fnil conj [])
;; just use original fn meta, as the fn method is already desugared
;; only get tag from analysis
(merge
(select-keys info [:fixed-arity :variadic?])
(select-keys (-> vexpr :methods first) [:tag]))))))
(when-not texpr
(throw (error env "set! target must be a field or a symbol naming a var")))
(cond
(and (not (:def-emits-var env)) ;; non-REPL context
(some? ('#{*unchecked-if* *unchecked-arrays* *warn-on-infer*} target)))
{:env env :op :no-op}
:else
{:env env :op :set! :form form :target texpr :val vexpr
:children [:target :val]}))))))
(defmethod emit* :set!
[{:keys [target val env]}]
(emit-wrap env (emits "(" target " = " val ")")))