diff --git a/src/main/frontend/extensions/calc.cljc b/src/main/frontend/extensions/calc.cljc index 172b9357c..e37791896 100644 --- a/src/main/frontend/extensions/calc.cljc +++ b/src/main/frontend/extensions/calc.cljc @@ -27,37 +27,39 @@ (defn eval* [env ast] (insta/transform - {:number (comp edn/read-string #(str/replace % "," "")) - :scientific edn/read-string - :expr identity - :add + - :sub - - :mul * - :div / - :pow (fn [a b] + {:number (comp edn/read-string #(str/replace % "," "")) + :negnumber (comp edn/read-string #(str/replace % "," "")) + :scientific edn/read-string + :negscientific edn/read-string + :expr identity + :add + + :sub - + :mul * + :div / + :pow (fn [a b] #?(:clj (java.lang.Math/pow a b) :cljs (js/Math.pow a b))) - :log (fn [a] + :log (fn [a] #?(:clj (java.lang.Math/log10 a) :cljs (js/Math.log10 a))) - :ln (fn [a] + :ln (fn [a] #?(:clj (java.lang.Math/log a) :cljs (js/Math.log a))) - :sin (fn [a] + :sin (fn [a] #?(:clj (java.lang.Math/sin a) :cljs (js/Math.sin a))) - :cos (fn [a] + :cos (fn [a] #?(:clj (java.lang.Math/cos a) :cljs (js/Math.cos a))) - :tan (fn [a] + :tan (fn [a] #?(:clj (java.lang.Math/tan a) :cljs (js/Math.tan a))) - :atan (fn [a] + :atan (fn [a] #?(:clj (java.lang.Math/atan a) :cljs (js/Math.atan a))) - :asin (fn [a] + :asin (fn [a] #?(:clj (java.lang.Math/asin a) :cljs (js/Math.asin a))) - :acos (fn [a] + :acos (fn [a] #?(:clj (java.lang.Math/acos a) :cljs (js/Math.acos a))) - :assignment (fn [var val] + :assignment (fn [var val] (swap! env assoc var val) val) - :toassign str/trim - :variable (fn [var] - (let [var (str/trim var)] + :toassign str/trim + :variable (fn [var] + (let [var (str/trim var)] (or (get @env var) (throw (ex-info (util/format "Can't find variable %s" var) diff --git a/src/main/grammar/calc.bnf b/src/main/grammar/calc.bnf index 59f09686e..2958b97c1 100644 --- a/src/main/grammar/calc.bnf +++ b/src/main/grammar/calc.bnf @@ -17,8 +17,10 @@ tan = <#'\s*'> <'tan('> expr <')'> <#'\s*'> atan = <#'\s*'> <'atan('> expr <')'> <#'\s*'> acos = <#'\s*'> <'acos('> expr <')'> <#'\s*'> asin = <#'\s*'> <'asin('> expr <')'> <#'\s*'> - = scientific | number | variable | <#'\s*'> <'('> expr <')'> <#'\s*'> + = negscientific | scientific | negnumber | number | variable | <#'\s*'> <'('> expr <')'> <#'\s*'> +negscientific = #'\s*-[0-9]+\.?[0-9]*(e|E)-?[0-9]+()\s*' scientific = #'\s*[0-9]+\.?[0-9]*(e|E)-?[0-9]+()\s*' +negnumber = #'\s*-\d+(,\d+)*(\.\d*)?\s*' number = #'\s*\d+(,\d+)*(\.\d*)?\s*' variable = #'\s*[a-zA-Z]+(\_+[a-zA-Z]+)*\s*' toassign = #'\s*[a-zA-Z]+(\_+[a-zA-Z]+)*\s*' diff --git a/src/test/frontend/extensions/calc_test.cljc b/src/test/frontend/extensions/calc_test.cljc index b33dde5a3..1ab190d14 100644 --- a/src/test/frontend/extensions/calc_test.cljc +++ b/src/test/frontend/extensions/calc_test.cljc @@ -22,7 +22,12 @@ 98123 "9,8,123" 1123.0 " 112,3.0 " 22.1124131 "2,2.1124131" - 100.01231 " 1,00.01231 "))) + 100.01231 " 1,00.01231 ")) + (testing "even when they are negative" + (are [value expr] (= value (run expr)) + -98123 "-98123" + -1123.0 " -112,3.0 " + -22.1124131 "-2,2.1124131"))) (testing "basic operations work" (are [value expr] (= value (run expr)) 1 "1 + 0" @@ -32,11 +37,15 @@ 1 "(2-1 ) " 211 "100 + 111" 2111 "1,000 + 11,11" + -111 "1,000 + -11,11" 0 "1 + 2 + 3 + 4 + 5 -1-2-3-4-5" 1 "1 * 1" + -1 "1 * -1" 2 "1*2" + -2 "-1*2" 9 " 3 *3" 1 " 2 * 3 / 3 / 2" + -1 " 2 * 3 / 3 / -2" #?(:clj 1/2 :cljs 0.5) " 1 / 2" 0.5 " 1/ 2.0")) @@ -62,6 +71,7 @@ 1.0e1 "1.0e01" 1.23e-10 "123.0e-12" 12.3 "123.0e-1" + -12.3 "-123.0e-1" 12.3 "123.0E-1" 2.0 "1e0 + 1e0")) (testing "scientific functions" @@ -80,9 +90,11 @@ (calc/eval env (calc/parse expr)) (= final-env @env)) {"a" 1} "a = 1" + {"a" -1} "a = -1" {"variable" 1} "variable = 1 + 0 * 2" {"x" 1} "x= 2 * 1 - 1 " {"y" 4} "y =8 / 4 + 2 * 1 - 25 * 0 / 1" + {"y" 4} "y =8 / 4 + 2 * 1 - 25 * 0 / 1" {"zzz" 14.0} "zzz=3 *2 ^ 2 + 1 * 2" {"foo" 74.0} "foo = (((3*2) ^ 2 + 1) * 2)")) (testing "variables can have underscores"