            {:id "four-a-c" :inputs ["four" "a" "c"] :node {:type :cljs :fn *}}
            {:id "result" :inputs ["b-squared" "four-a-c"] :node {:type :cljs :fn -}}]})
 
+(defn bind [var pattern]
+  {:type :match/bind
+   :var var
+   :pattern pattern})
+
 (def example-b
   {:type :match
-   :branches [{:branch {"a" ^{:var "a"} {:type :cljs :fn number?} "b" ^{:var "b"} {:type :cljs :fn number?}}
+   :branches [{:pattern {"a" (bind "a" {:type :cljs :fn number?}) "b" (bind "b" {:type :cljs :fn number?})}
                :inputs ["a" "b"]
                :node {:type :cljs :fn -}}
-              {:branch [^{:var "x"} {:type :value :value true} "foo"]
+              {:pattern [(bind "x" {:type :value :value true}) "foo"]
                :inputs ["x" "y"]
                :node {:type :cljs :fn identity}}]})
 

(ns aurora.interpreter)

(declare run-node)

(defn run-value [node inputs actions]
  (:value node))

      (aset vars id value))
    (doseq [{:keys [id inputs node]} (:nodes node)]
      (aset vars id (run-node node (map #(aget vars %) inputs) actions)))
    (aget vars (-> node :nodes last :id))))

(defrecord MatchFailure [])

(defn check [bool]
  (when-not bool (throw (MatchFailure.))))

(defn run-match [node inputs actions]
  (assert (= 1 (count inputs)))
  (let [input (first inputs)]
    (loop [branches (:branches node)]
      (if-let [[{:keys [pattern inputs node]} & branches] (seq branches)]
        (try
          (let [vars #js {}]
            (run-match-pattern pattern input actions vars)
            (run-node node (map #(aget vars %) inputs) actions))
          (catch MatchFailure _
            (recur branches)))
        (throw (MatchFailure.))))))

(defn run-match-pattern [pattern input actions vars]
  (cond
   (= (:type pattern) :match/bind) (do (aset vars (:var pattern) input)
                                    (run-match-pattern (:pattern pattern) input actions vars))
   (:type pattern) (check (run-node pattern [input] actions))
   (or (number? pattern) (string? pattern)) (check (= pattern input))
   (or (nil? pattern) (sequential? pattern)) (if-let [[first-pattern & rest-pattern] (seq pattern)]
                                             (do (check (and (sequential? input) (seq input)))
                                               (let [[first-input & rest-input] input]
                                                 (run-match-pattern first-pattern first-input actions vars)
                                                 (run-match-pattern rest-pattern rest-input actions vars)))
                                             (check (empty? input)))
   (map? pattern) (do (check (map? input))
                   (doseq [[key val] pattern]
                     (check (contains? input key))
                     (run-match-pattern val (get input key) actions vars)))
   :otherwise (assert false)))

(def example-a
  {:type :pipe
