       (aset vars id value))
     (doseq [{:keys [id inputs node]} (:nodes node)]
       (assert (not= :pipe (:type node)) "No inline pipes")
-      (aset vars id (run-node program node (map #(aget vars %) inputs) calls))) ; note calls, not stack
+      (aset vars id (run-node program node (map #(aget vars %) inputs) output calls))) ; note calls, not stack
     (let [result (aget vars (-> node :nodes last :id))]
       (aset frame "result" result) ; return
       result)))
 
-(defn run-node [program node inputs stack]
+(defn run-node [program node inputs output stack]
   (case (:type node)
-    :data (run-data program node inputs stack)
-    :match (run-match program node inputs stack)
-    :ref (run-ref program node inputs stack)))
-
-(defn run-data [program node inputs stack]
+    :return (run-return program node inputs output stack)
+    :data (run-data program node inputs output stack)
+    :ref (run-ref program node inputs output stack)
+    :match (run-match program node inputs output stack)
+    :replace (run-replace program node inputs output stack)
+    :output (run-output program node inputs output stack)))
+
+(defn run-return [program node inputs output stack]
+  (assert (= 1 (count inputs)))
+  (first inputs))
+
+(defn run-data [program node inputs output stack]
   (assert (empty? inputs))
-  (Cursor. [] (run-data* program node inputs stack)))
-
-(defn run-data* [program node inputs stack]
+  (Cursor. [] (run-data* program node inputs output stack)))
+
+(defn run-data* [program node inputs output stack]
   (case (:kind node)
     :value (:value node)
     :vector (into []
                   (for [value (:value node)]
-                    (run-data* program value inputs stack)))
+                    (run-data* program value inputs output stack)))
     :map (into {}
                (for [[key value] (:value node)]
-                 [(run-data* program key inputs stack) (run-data* program value inputs stack)]))))
-
-(defn run-ref [program node inputs stack]
+                 [(run-data* program key inputs output stack) (run-data* program value inputs output stack)]))))
+
+(defn run-ref [program node inputs output stack]
   (case (:kind node)
     :cljs (Cursor. [] (apply (:fn node) (map :value inputs)))
-    :pipe (run-pipe program (get program (:id node)) inputs stack)))
+    :pipe (run-pipe program (get program (:id node)) inputs output stack)))
 
 (defrecord MatchFailure [])
 
 (defn check [bool]
   (when-not bool (throw (MatchFailure.))))
 
-(defn run-match [program node inputs stack]
+(defn run-match [program node inputs output stack]
   (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 program pattern (:path input) (:value input) stack vars)
-            (run-node program node (map #(aget vars %) inputs) stack))
+            (run-match-pattern program pattern (:path input) (:value input) output stack vars)
+            (run-node program node (map #(aget vars %) inputs) output stack))
           (catch MatchFailure _
             (recur branches)))
         (throw (MatchFailure.))))))
 
-(defn run-match-pattern [program pattern input-path input-value stack vars]
+(defn run-match-pattern [program pattern input-path input-value output stack vars]
   (condp = (:type pattern)
     :match/any nil
     :match/bind (do (aset vars (:var pattern) (Cursor. input-path input-value))
-                  (run-match-pattern program (:pattern pattern) input-path input-value stack vars))
+                  (run-match-pattern program (:pattern pattern) input-path input-value output stack vars))
     :data (case (:kind pattern)
             :value (check (= input-value (:value pattern)))
             :vector (let [value (:value pattern)]
                       (check (vector? input-value))
                       (check (= (count input-value) (count value)))
                       (dotimes [i (count value)]
-                        (run-match-pattern program (nth value i) (conj input-path i) (nth input-value i) stack vars)))
+                        (run-match-pattern program (nth value i) (conj input-path i) (nth input-value i) output stack vars)))
             :map (let [value (:value pattern)]
                    (check (map? input-value))
                    (doseq [key-pattern (keys value)]
                      (let [key (:value key-pattern)]
                        (check (contains? input-value key))
-                       (run-match-pattern program (get value key-pattern) (conj input-path key) (get input-value key) stack vars)))))
-    (check (:value (run-node program pattern [(Cursor. input-path input-value)] stack)))))
+                       (run-match-pattern program (get value key-pattern) (conj input-path key) (get input-value key) output stack vars)))))
+    (check (:value (run-node program pattern [(Cursor. input-path input-value)] output stack)))))
+
+(defn run-replace [program node inputs output stack]
+  (swap! output assoc-in (:path (first inputs)) (:value (second inputs))))
+
+(defn run-output [program node inputs output stack]
+  (swap! output update-in (:path node) cons (:value (first inputs))))
+
+(assoc-in {} [] :foo)
 
 ;; ast
+
+(def return
+  {:type :return})
 
 (defn pipe [id inputs & nodes]
   {:type :pipe

(def example-b
  #{(pipe "root" ["x"]
          "result" ["x"] (match (data-map (data-value "a") (bind "a" (cljs-ref number?)) (data-value "b") (bind "b" (cljs-ref number?))) ["a" "b"] (cljs-ref -)
                                      (data-vector (bind "x" any) (data-value "foo")) ["x"] (cljs-ref identity)))})

(def example-c
  #{(pipe "root" ["x"]

(ns aurora.interpreter)

;; todo

;; efficient implementation of stack queries (maybe only compile the watched fn?)
;; efficient implementation of cursors (maybe via side-vars)

;; interpreter

(defrecord Cursor [path value])

(defn run-pipe [program node inputs output stack]
  (let [vars #js {}
        calls #js []
        frame #js {:id (:id node) :vars vars :calls calls}]
