|
@@ -6,8 +6,6 @@
|
|
|
; https://clojureverse.org/t/guide-on-how-to-use-import-npm-modules-packages-in-clojurescript/2298
|
|
|
; https://shadow-cljs.github.io/docs/UsersGuide.html#npm
|
|
|
|
|
|
-(defn highest [dir data] (apply max (map dir data)))
|
|
|
-
|
|
|
|
|
|
(defn highest-col
|
|
|
"Return the highest column (letter) for which there is a non-empty cell"
|
|
@@ -76,13 +74,6 @@
|
|
|
(dissoc :display)
|
|
|
(dissoc :error))))
|
|
|
|
|
|
-(defn add-parsed-variables-to-specific-datum
|
|
|
- "Parse variables from the value of a datum and add in :vars and :refs (for swap! data-atom).
|
|
|
- If the value does not contain a fomula, remove any :vars and :refs that may have been there."
|
|
|
- [c r data] (map #(if (and (= (:col %) c) (= (:row %) r))
|
|
|
- (add-parsed-variables %)
|
|
|
- %) data))
|
|
|
-
|
|
|
; the references in the data are a set of disconnected, doubly-linked trees
|
|
|
;TODO: rather than denotify all, then re-notify all, maybe use a diff? maybe on small scales it's not worth it?
|
|
|
(defn denotify-references
|
|
@@ -197,32 +188,12 @@
|
|
|
:calc-error)))))
|
|
|
|
|
|
;TODO: deal with lowercase cell references
|
|
|
-(defn find-cell [data c r]
|
|
|
- (some #(if (and (= (:col %) c) (= (:row %) r)) %) data))
|
|
|
-(defn find-ref [data cell-ref]
|
|
|
- (some (fn [{:keys [row col] :as datum}] (if (and (= row (:row cell-ref)) (= col (:col cell-ref))) datum)) data))
|
|
|
-(defn copy-display-values [data display-values]
|
|
|
- (let [original (map #(dissoc % :dirty) data)
|
|
|
- removed (map #(-> % (dissoc :found) (dissoc :inputs) (dissoc :dirty)) display-values)]
|
|
|
- (into original removed)))
|
|
|
|
|
|
;TODO: memoize dynamically? probably not worth memoizing directly, and could take up too much memory over time
|
|
|
; https://stackoverflow.com/a/13123571/8172807
|
|
|
(defn find-cycle
|
|
|
- ([data datum] (find-cycle data datum #{}))
|
|
|
- ([data datum ances]
|
|
|
- (let [cur {:row (:row datum) :col (:col datum)}
|
|
|
- this-and-above (conj ances cur)
|
|
|
- refs (:refs datum)
|
|
|
- found (not (empty? (clojure.set/intersection this-and-above (set refs))))]
|
|
|
- (if found
|
|
|
- :cycle-error
|
|
|
- (some (fn [cell]
|
|
|
- (find-cycle data (find-ref data cell) this-and-above)) refs)))))
|
|
|
-
|
|
|
-(defn alt-find-cycle
|
|
|
"Accepts the data and a datum, and peforms a depth-first search to find reference cycles, following back-references."
|
|
|
- ([data c r] (alt-find-cycle data c r #{}))
|
|
|
+ ([data c r] (find-cycle data c r #{}))
|
|
|
([data c r ancest]
|
|
|
(let [datum (get-in data [c r])
|
|
|
current {:col c :row r}
|
|
@@ -231,7 +202,7 @@
|
|
|
found-repeat (not (empty? (clojure.set/intersection this-and-above (set inbound))))]
|
|
|
(if found-repeat
|
|
|
:cycle-error
|
|
|
- (some #(alt-find-cycle data (:col %) (:row %) this-and-above) inbound)))))
|
|
|
+ (some #(find-cycle data (:col %) (:row %) this-and-above) inbound)))))
|
|
|
|
|
|
|
|
|
(defn gather-variables-and-evaluate-cell
|
|
@@ -278,7 +249,7 @@
|
|
|
(defn evaluate-from-cell
|
|
|
"Evaluate the final value of a cell, and recursively re-evaluate all the cells that reference it."
|
|
|
[data c r]
|
|
|
- (let [cycles? (alt-find-cycle data c r)
|
|
|
+ (let [cycles? (find-cycle data c r)
|
|
|
new-data (if cycles?
|
|
|
(-> data ; if there are cycles, mark :cycle-error and remove :dirty (rathan than evaluate) - still need to recurse up the tree to mark dependents with :cycle-error
|
|
|
(update-in [c r] dissoc :dirty)
|
|
@@ -323,58 +294,4 @@
|
|
|
(recur evaluated (rest queue))))
|
|
|
(recur data (rest queue)))))))
|
|
|
|
|
|
-(evaluate-all (walk-modify-data (:alt-table-data microtables-frontend.db/default-db) (fn [c r datum] (if (= (first (:value datum)) "=") (assoc datum :dirty true) datum))))
|
|
|
-
|
|
|
-#_(defn alt-re-evaluate
|
|
|
- "Evaluate the values of cells that contain formulae, following reference chains if applicable."
|
|
|
- [data]
|
|
|
- (let [non-empty-cells (flatten (map (fn [[c v]] (map (fn [[r _]] {:col c :row r}) v)) data))
|
|
|
- {has-formula true original-values false} (group-by #(= (first (get-in data [(:col %) (:row %) :value])) "=") non-empty-cells)
|
|
|
- found-cycles (map #(let [found (alt-find-cycle data (:col %) (:row %))]
|
|
|
- (if found (assoc % :error found) %)) has-formula)]
|
|
|
- non-empty-cells))
|
|
|
-
|
|
|
-
|
|
|
-(defn find-val [data c r]
|
|
|
- (let [l (find-cell data c r)
|
|
|
- v (get l :display (get l :value))
|
|
|
- formula? (and (string? v) (= (first v) "="))]
|
|
|
- (cond
|
|
|
- (nil? v) 0
|
|
|
- ;(contains? l :error) :ref-error
|
|
|
- formula? :not-yet
|
|
|
- :else v)))
|
|
|
-
|
|
|
-(defn re-evaluate [data]
|
|
|
- (println "re-evaluating" data)
|
|
|
- (let [{has-formula true original-values false} (group-by #(= (first (:value %)) "=") data)
|
|
|
- found-cycles (map #(let [found (find-cycle data %)] (if found (assoc % :error found) %)) has-formula)
|
|
|
- {eligible true ineligible false} (group-by #(not (contains? % :error)) found-cycles)]
|
|
|
- ;
|
|
|
- (loop [values (into original-values ineligible)
|
|
|
- mapped-cell-keys eligible]
|
|
|
- (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]
|
|
|
- (let [hash-map-of-vars-to-vals (apply hash-map (interleave (:vars datum) (:found datum)))]
|
|
|
- (assoc datum :inputs hash-map-of-vars-to-vals)))
|
|
|
- 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 "EVALUATED" evaluated)
|
|
|
- (if (nil? not-ready)
|
|
|
- updated-values
|
|
|
- (recur updated-values not-ready))))))
|
|
|
|