| 
					
				 | 
			
			
				@@ -62,8 +62,8 @@ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 (def parse-variables (memoize (fn [expression] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                                 (js->clj (.getVariables mathjs expression))))) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-(def evaluate-expressions (memoize (fn [expression variables] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                                     (.evaluate mathjs expression (clj->js variables))))) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+(def evaluate-expression (memoize (fn [expression variables] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                                    (.evaluate mathjs expression (clj->js variables))))) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 (defn temp3 [[k v]] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   (let [w (name k) 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -90,7 +90,7 @@ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				           parsed (zipmap (keys remaining) evaluated-vars) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				           not-ready (group-by (fn [[ k v ]] (some #(= :not-yet (last %)) v)) parsed) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				           ;TODO: detect circular references 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-          prepared (map (fn [[k v]] [k (evaluate-expressions (remaining k) (apply hash-map (flatten v)))]) (not-ready nil)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          prepared (map (fn [[k v]] [k (evaluate-expression (remaining k) (apply hash-map (flatten v)))]) (not-ready nil)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				           new-evaluated (reduce conj evaluated prepared) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				           still-remaining (apply hash-map (flatten (map #(list (key %) (remaining (key %))) (not-ready true))))] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				       ;remaining ; {:B8 B7 * 2, :C7 D1, :B7 C5 + D6} 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -106,6 +106,73 @@ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				       ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     )) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+(def str->rc (memoize (fn [s] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        (let [c (re-find #"^[A-Z]+" s) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                              r (.parseInt js/window (re-find #"[0-9]+$" s))] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                          {:row r :col c})))) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+(defn find-cell [data c r] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  (some #(if (and (= (:col %) c) (= (:row %) r)) %) data)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+(defn find-val [data c r] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  (let [l (find-cell data c r) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        v (get l :display (get l :value))] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    (println "found?" c r v l (get l :value) (get l :display)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    (cond 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      (nil? v) 0 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      (and (string? v) (= (first v) "=")) :not-yet 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      :else v))) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+(defn copy-display-values' [data display-values] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  (if (empty? display-values) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    data 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    (let [v (first display-values) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          r (:row v) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          c (:col v) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          inserted (map #(if (and (= r (:row %)) (= c (:col %)) (= (first (:value %)) "=")) (assoc % :display (:display v)) %) data)] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      (recur inserted (rest display-values))))) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+(defn copy-display-values [data display-values] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  (let [removed (map #(-> % (dissoc :vars) (dissoc :refs) (dissoc :found) (dissoc :inputs)) display-values)] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    (into data removed))) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+(defn experimental [data] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  (let [remove-old-displays (map #(dissoc % :display) data) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        {has-formula true original-values false} (group-by #(= (first (:value %)) "=") remove-old-displays) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        ;TODO: detect circular references 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        variables (map #(assoc % :vars (parse-variables (subs (:value %) 1))) has-formula) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        first-mapped-cell-keys (map (fn [datum] (assoc datum :refs (map str->rc (:vars datum)))) variables)] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    (loop [values original-values mapped-cell-keys first-mapped-cell-keys] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      (let [search-values (map (fn [datum] (assoc datum :found (map #(find-val (concat values mapped-cell-keys) (:col %) (:row %)) (:refs datum)))) mapped-cell-keys) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            {not-ready true ready nil} (group-by (fn [datum] (some #(= :not-yet %) (:found datum))) search-values) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            prepped-for-eval (map (fn [datum] (assoc datum :inputs (apply hash-map (interleave (:vars datum) (:found datum))))) ready) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            evaluated (map (fn [datum] (assoc datum :display (evaluate-expression (subs (:value datum) 1) (:inputs datum)))) prepped-for-eval) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            updated-values (copy-display-values values evaluated) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            ] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        (println) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        (println) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        (println) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        (println "has-formula" has-formula) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        (println "values" values) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        (println "variables" variables) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        (println "mapped-cell-keys" mapped-cell-keys) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        (println "search-values" search-values) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        (println "not ready to eval" not-ready) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        (println "             nil?" (nil? not-ready)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        (println "ready to eval" ready) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        (println "prepped-for-eval" prepped-for-eval) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        (println "evaluated" evaluated) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        (println "updated-values" updated-values) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        (println "done!") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        (println) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        (println "loop    " values "      " mapped-cell-keys) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        (println "") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        (println "recur   " updated-values "    " not-ready) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        (if (nil? not-ready) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          updated-values 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          (recur updated-values not-ready) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        )) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 ;TODO: figure out how to re-evaluate only when the cell modified affects other cells 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 (defn re-evaluate-data [] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   (let [rt (temp1 @data-atom) 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -164,6 +231,10 @@ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 (defn app [] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   [:div 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				    [:h3 "Microtables"] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+   (do 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     (println "hi again") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     (experimental @data-atom) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     "hi again") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				    [sheet @data-atom]]) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 ;; ------------------------- 
			 |