|
@@ -66,6 +66,12 @@
|
|
|
(memoize (fn [expression]
|
|
|
(clojure.string/replace expression #"\(\s*[A-Z]+[0-9]+\s*:\s*[A-Z]+[0-9]+\s*\)" parse-range))))
|
|
|
|
|
|
+(defn formula?
|
|
|
+ "Determines if a value is a fomula. If it is, it returns it (without the leading equals sign. If not, it returns nil."
|
|
|
+ [value]
|
|
|
+ (if (= (first value) "=")
|
|
|
+ (subs value 1)
|
|
|
+ nil))
|
|
|
|
|
|
(def parse-variables (memoize (fn [expression]
|
|
|
(as-> (js->clj (.parse mathjs (replace-ranges-in-expression expression))) $
|
|
@@ -83,16 +89,17 @@
|
|
|
(defn add-references
|
|
|
"Parses the expression in the value of a datum, and adds refs as necessary"
|
|
|
[datum]
|
|
|
- (if (= (first (:value datum)) "=")
|
|
|
- (let [vars (parse-variables (subs (:value datum) 1))
|
|
|
- refs (map str->rc vars)]
|
|
|
+ (let [formula (formula? (:value datum))]
|
|
|
+ (if formula
|
|
|
+ (let [vars (parse-variables formula)
|
|
|
+ refs (map str->rc vars)]
|
|
|
+ (-> datum
|
|
|
+ (assoc :refs refs)
|
|
|
+ (dissoc :error)))
|
|
|
(-> datum
|
|
|
- (assoc :refs refs)
|
|
|
- (dissoc :error)))
|
|
|
- (-> datum
|
|
|
- (dissoc :refs)
|
|
|
- (dissoc :display)
|
|
|
- (dissoc :error))))
|
|
|
+ (dissoc :refs)
|
|
|
+ (dissoc :display)
|
|
|
+ (dissoc :error)))))
|
|
|
|
|
|
; 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?
|
|
@@ -150,7 +157,7 @@
|
|
|
"Assuming all references have been added, insert all back references."
|
|
|
[data]
|
|
|
(loop [data data
|
|
|
- formulas (walk-get-refs data #(= (first (:value %3)) "="))]
|
|
|
+ formulas (walk-get-refs data formula?)]
|
|
|
(if (empty? formulas)
|
|
|
data
|
|
|
(let [origin (first formulas)
|
|
@@ -253,9 +260,9 @@
|
|
|
(let [datum (dissoc (dissoc (get-in data [c r]) :dirty) :display) ; get rid of the dirty flag right away (it must be included with the returned data to have effect)
|
|
|
refs (:refs datum)
|
|
|
value (:value datum)
|
|
|
- formula? (= (first value) "=")
|
|
|
+ formula (formula? value)
|
|
|
resolved-refs (map #(merge % (get-in data [(:col %) (:row %)])) refs)
|
|
|
- evaluated-refs (map #(if (= (first (:value %)) "=") (:display %) (:value %)) resolved-refs)
|
|
|
+ evaluated-refs (map #(if (formula? (:value %)) (:display %) (:value %)) resolved-refs)
|
|
|
invalid-refs (some nil? resolved-refs)
|
|
|
dirty-refs (some :dirty resolved-refs)
|
|
|
error-refs (some #(= (:display %) :error) resolved-refs)
|
|
@@ -263,7 +270,7 @@
|
|
|
cycle-refs (some #(= (:display %) :cycle-error) resolved-refs)
|
|
|
disqualified? (or invalid-refs dirty-refs error-refs)]
|
|
|
(cond
|
|
|
- (false? formula?) (assoc-in data [c r] datum) ; if it's not a formula, then return as is (with the dirty flag removed)
|
|
|
+ formula (assoc-in data [c r] datum) ; if it's not a formula, then return as is (with the dirty flag removed)
|
|
|
cycle-refs (-> data ; if one of its references has a reference cycle, then this one is "poisoned" as well
|
|
|
(assoc-in [c r] datum)
|
|
|
(assoc-in [c r :display] :cycle-error))
|