Browse code

Add tools for evaluating roll expressions

Joseph Weston authored on 24/10/2022 00:06:02
Showing 2 changed files
... ...
@@ -10,6 +10,8 @@
10 10
   [day8.re-frame/tracing "0.6.2"]
11 11
   [garden "1.3.10"]
12 12
   [net.dhleong/spade "1.1.0"]
13
+  [org.babashka/sci "0.5.34"]
14
+  [org.clojure/core.match "1.0.0"]
13 15
 
14 16
   [day8/shadow-git-inject "0.0.5"]
15 17
   [binaryage/devtools "1.0.3"]
... ...
@@ -1,8 +1,11 @@
1 1
 (ns dmr.events
2 2
   (:require
3
-   [cljs.reader :refer [read-string]]
4
-   [clojure.string :refer [lower-case split join starts-with?]]
3
+   [clojure.edn :as edn]
4
+   [clojure.core.match :refer-macros [match]]
5
+   [clojure.walk :refer [postwalk]]
6
+   [clojure.string :refer [lower-case split join starts-with? replace]]
5 7
    [re-frame.core :as re-frame]
8
+   [sci.core :as sci]
6 9
    [dmr.db :as db]
7 10
    [day8.re-frame.tracing :refer-macros [fn-traced]]))
8 11
 
... ...
@@ -77,6 +80,30 @@
77 80
                            (roll-dice (edn/read-string ndice) (edn/read-string nsides))))]
78 81
     (replace s dice-regex evaluated-roll)))
79 82
 
83
+(defn infixify [expr]
84
+  (match [expr]
85
+    [([x] :seq)] (infixify x)
86
+    [([x op & rest] :seq)] (list op (infixify x) (infixify rest))
87
+    [x :guard number?] x
88
+    :else (throw (js/Error. (str "Expected number, but got '" (pr-str expr) "'")))))
89
+
90
+
91
+(defn evaluate-roll-expression [s]
92
+  (let [string-expr (evaluate-rolls s)
93
+        result (as-> string-expr x
94
+                 (str "(" x ")")  ;So that 'read-string' reads everything
95
+                 (edn/read-string x)
96
+                 (postwalk #(if (vector? %) (reduce + %) %) x)
97
+                 (infixify x)
98
+                 (pr-str x)
99
+                 (sci/eval-string x))]
100
+     {:roll-expression string-expr :result result}))
101
+
102
+(defn safely-evaluate-roll-expression [s]
103
+  (try
104
+    (evaluate-roll-expression s)
105
+    (catch js/Error e {:err (.-message e)})))
106
+
80 107
 (defn execute [db cmdline]
81 108
  (let [append-history #(update-in db [:cmdline :history] conj {:input cmdline :output %})
82 109
        entities (db :entities)