try

special formsince v0.0-927 clojure.core/tryEdit
(try expr* catch-clause* finally-clause?)

Details:

The expressions (expr*) are evaluated and, if no exceptions occur, the value of the last is returned.

If an exception occurs and catch clauses (catch-clause*) are provided, each is examined in turn and the first for which the thrown exception is an instance of the named class is considered a matching catch clause. If there is a matching catch clause, its expressions are evaluated in a context in which name is bound to the thrown exception, and the value of the last is the return value of the function.

If there is no matching catch clause, the exception propagates out of the function. Before returning, normally or abnormally, any finally-clause? expressions will be evaluated for their side effects.

try is one of ClojureScript's special forms.


See Also:


Source docstring:
catch-clause => (catch classname name expr*)
finally-clause => (finally expr*)
Catches and handles JavaScript exceptions.
Parser code @ clojurescript:src/main/clojure/cljs/analyzer.cljc
(defmethod parse 'try
  [op env [_ & body :as form] name _]
  (let [catchenv (update-in env [:context] #(if (= :expr %) :return %))
        catch? (every-pred seq? #(= (first %) 'catch))
        default? (every-pred catch? #(= (second %) :default))
        finally? (every-pred seq? #(= (first %) 'finally))

        {:keys [body cblocks dblock fblock]}
        (loop [parser {:state :start :forms body
                       :body [] :cblocks [] :dblock nil :fblock nil}]
          (if (seq? (:forms parser))
            (let [[form & forms*] (:forms parser)
                  parser* (assoc parser :forms forms*)]
              (case (:state parser)
                :start (cond
                         (catch? form) (recur (assoc parser :state :catches))
                         (finally? form) (recur (assoc parser :state :finally))
                         :else (recur (update-in parser* [:body] conj form)))
                :catches (cond
                           (default? form) (recur (assoc parser* :dblock form :state :finally))
                           (catch? form) (recur (update-in parser* [:cblocks] conj form))
                           (finally? form) (recur (assoc parser :state :finally))
                           :else (throw (error env "Invalid try form")))
                :finally (recur (assoc parser* :fblock form :state :done))
                :done (throw (error env "Unexpected form after finally"))))
            parser))

        finally (when (seq fblock)
                  (-> (disallowing-recur (analyze (assoc env :context :statement) `(do ~@(rest fblock))))
                      (assoc :body? true)))
        e (when (or (seq cblocks) dblock) (gensym "e"))
        default (if-let [[_ _ name & cb] dblock]
                  `(cljs.core/let [~name ~e] ~@cb)
                  `(throw ~e))
        cblock (if (seq cblocks)
                 `(cljs.core/cond
                   ~@(mapcat
                      (fn [[_ type name & cb]]
                        (when name (assert (not (namespace name)) "Can't qualify symbol in catch"))
                        `[(cljs.core/instance? ~type ~e)
                          (cljs.core/let [~name ~e] ~@cb)])
                      cblocks)
                   :else ~default)
                 default)
        locals (:locals catchenv)
        locals (if e
                 (assoc locals e
                        {:name e
                         :line (get-line e env)
                         :column (get-col e env)})
                 locals)
        catch (when cblock
                (disallowing-recur (analyze (assoc catchenv :locals locals) cblock)))
        try (disallowing-recur (analyze (if (or e finally) catchenv env) `(do ~@body)))]

    {:env env :op :try :form form
     :body (assoc try :body? true)
     :finally finally
     :name e
     :catch catch
     :children (vec
                 (concat [:body]
                         (when catch
                           [:catch])
                         (when finally
                           [:finally])))}))

Emitting code @ clojurescript:src/main/clojure/cljs/compiler.cljc
(defmethod emit* :try
  [{try :body :keys [env catch name finally]}]
  (let [context (:context env)]
    (if (or name finally)
      (do
        (when (= :expr context)
          (emits "(function (){"))
        (emits "try{" try "}")
        (when name
          (emits "catch (" (munge name) "){" catch "}"))
        (when finally
          (assert (not= :const (:op (ana/unwrap-quote finally))) "finally block cannot contain constant")
          (emits "finally {" finally "}"))
        (when (= :expr context)
          (emits "})()")))
      (emits try))))