From eded98d74ea5df01c7131712e568ff08e3cb707b Mon Sep 17 00:00:00 2001 From: Ravi Chandra Padmala Date: Sun, 12 Nov 2023 20:01:12 -0500 Subject: [PATCH] Add content to statements. Change dep type from :Name -> :named. To add content to statemnents, we annotate the AST with the source using instaparse's built-in functionality. --- src/bean/deps.cljs | 2 +- src/bean/grid.cljs | 34 +++++++++++++++++----------------- src/bean/parser.cljs | 8 ++++++-- src/bean/value.cljs | 12 ++++++++++++ test/bean/grid_test.cljs | 4 ++-- test/bean/value_test.cljs | 22 ++++++++++++++++++++++ 6 files changed, 60 insertions(+), 22 deletions(-) create mode 100644 src/bean/value.cljs create mode 100644 test/bean/value_test.cljs diff --git a/src/bean/deps.cljs b/src/bean/deps.cljs index 7c9261d..ecb498c 100644 --- a/src/bean/deps.cljs +++ b/src/bean/deps.cljs @@ -6,7 +6,7 @@ [:cell dep]) (defn ->named-dep [dep] - [:Name dep]) + [:named dep]) (defn- ast->deps [ast] (let [[node-type & [arg :as args]] ast] diff --git a/src/bean/grid.cljs b/src/bean/grid.cljs index 8984567..64e50b4 100644 --- a/src/bean/grid.cljs +++ b/src/bean/grid.cljs @@ -2,21 +2,12 @@ (:require [bean.interpreter :as interpreter] [bean.parser :as parser] [bean.util :as util] + [bean.value :as value] [bean.deps :as deps] [bean.errors :as errors] [clojure.set :as set] [clojure.string])) -(defn- ast->val - ([ast] - {:content "nocontent" - :ast ast})) - -(defn- content->val - ([content] - {:content content - :ast (parser/parse content)})) - (defn- offset [[start-row start-col] [offset-rows offset-cols]] [(+ start-row offset-rows) (+ start-col offset-cols)]) @@ -119,7 +110,7 @@ (spill grid)))) (defn parse-grid [grid] - (util/map-on-matrix content->val grid)) + (util/map-on-matrix value/from-cell grid)) (defn- eval-cell [cell sheet] (if (or (not (:spilled-from cell)) @@ -163,7 +154,7 @@ (eval-address address sheet (util/get-cell grid cell-address) false)) ([address sheet new-content] - (eval-address address sheet (content->val new-content) true)) + (eval-address address sheet (value/from-cell new-content) true)) ([[_ cell-address :as address] {:keys [grid depgraph ui] :as sheet} cell content-changed?] ; todo: if cyclic dependency break with error @@ -177,7 +168,7 @@ (spill-matrix unspilled-grid cell-address) [unspilled-grid #{cell-address}]) updated-addrs (set/union evaled-addrs cleared-addrs)] - + (as-> (-> sheet (assoc :grid grid*) (assoc :depgraph (cond-> depgraph @@ -195,7 +186,7 @@ (-> (interested-spillers updated-addrs grid) (disj address))))))) -(defmethod eval-address :Name +(defmethod eval-address :named ([[_ named :as address] {:keys [bindings] :as sheet}] (if-let [v (bindings named)] (eval-address address sheet v false) @@ -203,7 +194,12 @@ ([address sheet new-content] ;; TODO: This is invalid - (eval-address address sheet (ast->val new-content) true)) + (eval-address address + sheet + (value/from-statement (parser/statement-source (:code sheet) + new-content) + new-content) + true)) ([[_ named :as address] {:keys [bindings] :as sheet} val _content-changed?] (-> (let [existing-val (bindings named) @@ -232,8 +228,12 @@ (let [res (let [code-ast (parser/parse-statement code)] (if-let [parse-error (parser/error code-ast)] (assoc sheet :code-error parse-error) - (-> (reduce (fn [sheet [_ address expr]] - (eval-address address sheet (ast->val expr) false)) + (-> (reduce (fn [sheet [_ [_ named] expr]] + (eval-address [:named named] + sheet + (value/from-statement (parser/statement-source code expr) + expr) + false)) (dissoc sheet :code-error) (rest code-ast)) (assoc :code-ast code-ast))))] diff --git a/src/bean/parser.cljs b/src/bean/parser.cljs index 405a7ad..2e04aa8 100644 --- a/src/bean/parser.cljs +++ b/src/bean/parser.cljs @@ -35,12 +35,16 @@ (def ^:private statement-parser (insta/parser (str statement-grammer "\n" expression-grammer))) -(defn parse-statement [v] - (insta/parse statement-parser v)) +(defn parse-statement [src] + (let [program (insta/parse statement-parser src)] + (insta/add-line-and-column-info-to-metadata src program))) (defn parse [v] (insta/parse parser v)) +(defn statement-source [code statement] + (apply subs code (insta/span statement))) + (defn error [result] (when (insta/get-failure result) (let [{:keys [index reason]} result] diff --git a/src/bean/value.cljs b/src/bean/value.cljs new file mode 100644 index 0000000..c842afb --- /dev/null +++ b/src/bean/value.cljs @@ -0,0 +1,12 @@ +(ns bean.value + (:require [bean.parser :as parser])) + +(defn from-statement + [content ast] + {:content content + :ast ast}) + +(defn from-cell [content] + {:content content + :ast (parser/parse content)}) + diff --git a/test/bean/grid_test.cljs b/test/bean/grid_test.cljs index 26208d1..7eeea8b 100644 --- a/test/bean/grid_test.cljs +++ b/test/bean/grid_test.cljs @@ -297,14 +297,14 @@ (get-in sheet [:bindings "addaone" :value]))))) (testing "Depgraph is updated when a named reference's dependencies change" - (is (= {[:cell [0 1]] #{[:Name "addaone"]}} + (is (= {[:cell [0 1]] #{[:named "addaone"]}} (as-> (new-sheet [["1" "2"]] "addaone:4+A1") sheet (eval-sheet sheet) (eval-code sheet "addaone:4+B1") (get-in sheet [:depgraph]))))) (testing "Depgraph is updated when a named reference's dependents change" - (is (= {[:Name "addaone"] #{[:cell [0 1]]}} + (is (= {[:named "addaone"] #{[:cell [0 1]]}} (as-> (new-sheet [["1" "2"]] "addaone:4") sheet (eval-sheet sheet) (eval-address [:cell [0 1]] sheet "=addaone+20") diff --git a/test/bean/value_test.cljs b/test/bean/value_test.cljs new file mode 100644 index 0000000..9dc54ae --- /dev/null +++ b/test/bean/value_test.cljs @@ -0,0 +1,22 @@ +(ns bean.value-test + (:require [clojure.test :refer [deftest is testing]] + [bean.value :as value])) + +(deftest new-test + (testing "Returns a new value for a statement with given content & ast" + (is (= {:ast [:Expression + [:Expression [:CellRef "A" "8"]] + [:Operation "+"] + [:Expression [:CellRef "B" "9"]]] + :content "A8+B9"} + (value/from-statement "A8+B9" [:Expression + [:Expression [:CellRef "A" "8"]] + [:Operation "+"] + [:Expression [:CellRef "B" "9"]]])))) + (testing "Returns a value that parses given cell contents & uses that ast" + (is (= {:ast [:CellContents [:Expression + [:Expression [:CellRef "A" "8"]] + [:Operation "+"] + [:Expression [:CellRef "B" "9"]]]] + :content "=A8+B9"} + (value/from-cell "=A8+B9"))))) \ No newline at end of file