Просмотр исходного кода

Revised format directives and mixed number format

Also changed output of non-decimal numbers to use base prefixes.
Martin Scott 3 лет назад
Родитель
Сommit
1d0fa763a5

+ 18 - 10
src/main/frontend/extensions/calc.cljc

@@ -88,24 +88,24 @@
     :toassign   str/trim
     :comment    (constantly nil)
     :digits     int
-    :mode-fix   (fn format [places]
+    :format-fix (fn format [places]
                   (swap! env assoc :mode "fix" :places places)
                   (get @env "last"))
-    :mode-sci   (fn format [places]
+    :format-sci (fn format [places]
                   (swap! env assoc :mode "sci" :places places)
                   (get @env "last"))
-    :mode-frac  (fn format [max-denominator]
+    :format-frac (fn format [max-denominator]
                   (swap! env dissoc :mode :improper)
                   (swap! env assoc :mode "frac" :max-denominator max-denominator)
                   (get @env "last"))
-    :mode-frac-i (fn format [max-denominator]
+    :format-impf (fn format [max-denominator]
                   (swap! env assoc :mode "frac" :max-denominator max-denominator :improper true)
                   (get @env "last"))
-    :mode-norm  (fn format [precision]
+    :format-norm (fn format [precision]
                   (swap! env dissoc :mode :places)
                   (swap! env assoc :precision precision)
                   (get @env "last"))
-    :mode-base  (fn base [b]
+    :base       (fn base [b]
                   (swap! env assoc :base (str/lower-case b))
                   (get @env "last"))
     :variable   (fn resolve [var]
@@ -150,11 +150,19 @@
   (and (< (.-e num) digits)
        (.isInteger (.shiftedBy num (+ tolerance digits)))))
 
+(defn format-base [val base]
+  (let [sign (.-s val)
+       display-val (if (neg-int? sign) (.abs val) val)]
+    (str
+      (when (neg-int? sign) "-")
+      (case base 2 "0b" 8 "0o" 16 "0x")
+      (.toString display-val base))))
+
 (defn format-fraction [numerator denominator improper]
   (let [whole (.dividedToIntegerBy numerator denominator)]
     (if (or improper (.isZero whole))
       (str numerator "/" denominator )
-      (str whole "_"
+      (str whole " "
            (.abs (.modulo numerator denominator)) "/" denominator))))
 
 (defn format-normal [env val]
@@ -171,11 +179,11 @@
           places (get @env :places)]
       (cond
         (= base "hex")
-          (.toString val 16)
+          (format-base val 16)
         (= base "oct")
-          (.toString val 8)
+          (format-base val 8)
         (= base "bin")
-          (.toString val 2)
+          (format-base val 2)
 
         (= mode "fix")
           (if (can-fix? val places)

+ 14 - 13
src/main/grammar/calc.bnf

@@ -1,4 +1,4 @@
-<start> = assignment | expr | comment | mode
+<start> = assignment | expr | comment | directive
 expr = add-sub [comment]
 comment = <#'\s*(#.*$)?'>
 <add-sub> = pow-term | mul-div | add | sub | variable
@@ -32,20 +32,21 @@ number = decimal-number | hexadecimal-number | octal-number | binary-number
 <hexadecimal-number> = #'\s*0x([0-9a-fA-F]+(,[0-9a-fA-F]+)*(\.[0-9a-fA-F]*)?|[0-9a-fA-F]*\.[0-9a-fA-F]+)\s*'
 <octal-number> = #'\s*0o([0-7]+(,[0-7]+)*(\.[0-7]*)?|[0-7]*\.[0-7]+)\s*'
 <binary-number> = #'\s*0b([01]+(,[01]+)*(\.[01]*)?|[01]*\.[01]+)\s*'
-mixed-number = <#'\s*'> digits <'_'> digits <#'[/_]'> digits <#'\s*'>
+mixed-number = <#'\s*'> digits <#'\s+'> digits <'/'> digits <#'\s*'>
 percent = number <'%'> <#'\s*'>
 variable = #'\s*_*[a-zA-Z]+[_a-zA-Z0-9]*\s*'
 toassign = #'\s*_*[a-zA-Z]+[_a-zA-Z0-9]*\s*'
 assignment = toassign <#'\s*'> <'='> <#'\s*'> expr
-<mode> = <#'\s*\:'> ( mode-fix | mode-sci | mode-norm | mode-frac | mode-frac-i | mode-base ) <#'\s*'> [comment]
-mode-fix = <#'(?i)fix(ed)?\s*'> digits
-mode-sci = <#'(?i)sci(entific)?\s*'> [digits]
-mode-norm = <#'(?i)norm(al)?\s*'> [digits]
-mode-frac = <#'(?i)frac(tions?)?\s*'> [digits]
-mode-frac-i = <#'(?i)frac(tions?)?-i(mp(roper)?)?\s*'> [digits]
-mode-base = mode-hex | mode-dec | mode-oct | mode-bin
-<mode-hex> = #'(?i)hex' <#'(?i)(adecimal)?'>
-<mode-dec> = #'(?i)dec' <#'(?i)(imal)?'>
-<mode-oct> = #'(?i)oct' <#'(?i)(al)?'>
-<mode-bin> = #'(?i)bin' <#'(?i)(ary)?'>
+<directive> = <#'\s*\:'> (format | base) <#'\s*'> [comment]
+<format> = <#'(format|fmt)\s+'> ( format-fix | format-sci | format-norm | format-frac | format-impf )
+format-fix = <#'(?i)fix(ed)?\s*'> digits
+format-sci = <#'(?i)sci(entific)?\s*'> [digits]
+format-norm = <#'(?i)norm(al)?\s*'> [digits]
+format-frac = <#'(?i)frac(tions?)?\s*'> [digits]
+format-impf = <#'(?i)imp(roper)?\s*'> [digits]
+base = base-hex | base-dec | base-oct | base-bin
+<base-hex> = #'(?i)hex' <#'(?i)(adecimal)?'>
+<base-dec> = #'(?i)dec' <#'(?i)(imal)?'>
+<base-oct> = #'(?i)oct' <#'(?i)(al)?'>
+<base-bin> = #'(?i)bin' <#'(?i)(ary)?'>
 digits = #'\d+'

+ 41 - 40
src/test/frontend/extensions/calc_test.cljc

@@ -199,54 +199,54 @@
 (deftest formatting
   (testing "display normal"
     (are [values exprs] (= values (calc/eval-lines (str/join "\n" exprs)))
-      [nil "1000000"]     [":norm" "1e6" ]
-      [nil "1000000"]     [":norm 7" "1e6"]
-      [nil "1e+6"]        [":norm 6" "1e6"]
-      [nil "3.14"]        [":norm 3" "PI"]
-      [nil "3"]           [":norm 1" "E"]
-      [nil "0.000123"]    [":norm 5" "0.000123"]
-      [nil "1.23e-4"]     [":norm 4" "0.000123"]
-      [nil "123400000"]   [":normal 9" "1.234e8"]
-      [nil "1.234e+8"]    [":normal 8" "1.234e8"]))
+      [nil "1000000"]     [":format norm" "1e6" ]
+      [nil "1000000"]     [":format norm 7" "1e6"]
+      [nil "1e+6"]        [":format norm 6" "1e6"]
+      [nil "3.14"]        [":format norm 3" "PI"]
+      [nil "3"]           [":format norm 1" "E"]
+      [nil "0.000123"]    [":format norm 5" "0.000123"]
+      [nil "1.23e-4"]     [":format norm 4" "0.000123"]
+      [nil "123400000"]   [":format normal 9" "1.234e8"]
+      [nil "1.234e+8"]    [":format normal 8" "1.234e8"]))
   (testing "display fixed"
     (are [values exprs] (= values (calc/eval-lines (str/join "\n" exprs)))
-      [nil "0.123450"]    [":fix 6" "0.12345"]
-      [nil "0.1235"]      [":fix 4" "0.12345"]
-      [nil "2.7183"]      [":fixed 4" "E"]
-      [nil "0.001"]       [":fix 3" "0.0005"]
-      [nil "4.000e-4"]    [":fix 3" "0.0004"]
-      [nil "1.00e+21"]    [":fixed 2" "1e21+0.1"]))
+      [nil "0.123450"]    [":format fix 6" "0.12345"]
+      [nil "0.1235"]      [":format fix 4" "0.12345"]
+      [nil "2.7183"]      [":format fixed 4" "E"]
+      [nil "0.001"]       [":format fix 3" "0.0005"]
+      [nil "4.000e-4"]    [":format fix 3" "0.0004"]
+      [nil "1.00e+21"]    [":format fixed 2" "1e21+0.1"]))
   (testing "display scientific"
     (are [values exprs] (= values (calc/eval-lines (str/join "\n" exprs)))
-      [nil "1e+6"]        [":sci" "1e6"]
-      [nil "3.142e+0"]    [":sci 3" "PI"]
-      [nil "3.14e+2"]     [":scientific" "3.14*10^2"])))
+      [nil "1e+6"]        [":format sci" "1e6"]
+      [nil "3.142e+0"]    [":format sci 3" "PI"]
+      [nil "3.14e+2"]     [":format scientific" "3.14*10^2"])))
 
 (deftest fractions
   (testing "mixed numbers"
     (are [value expr] (= value (run expr))
-      0          "0_0_1"
-      1          "0_1/1"
-      1          "1_0/1"
-      2.5        "2_1/2"
-      2.5        "2_1_2"
-      -4.28      "-4_7/25"
-      2.00101    "2_101/100000"
-      -99.2      "-99_8_40"))
+      0          "0 0/1"
+      1          "0 1/1"
+      1          "1 0/1"
+      2.5        "2 1/2"
+      2.5        "2 1/2"
+      -4.28      "-4 7/25"
+      2.00101    "2 101/100000"
+      -99.2      "-99 8/40"))
   (testing "display fractions"
     (are [values exprs] (= values (calc/eval-lines (str/join "\n" exprs)))
-      [nil "4_3/8"]           [":frac" "4.375"]
-      [nil "-7_1/4"]          [":fraction" "-7.25"]
-      [nil "2"]               [":fractions" "19/20 + 1_1/20"]
-      [nil "-2"]              [":frac" "19/17 - 3_2/17"]
-      [nil "3.14157"]         [":frac" "3.14157"]
-      [nil "3_14157/100000"]  [":frac 100000" "3.14157"]))
+      [nil "4 3/8"]           [":format frac" "4.375"]
+      [nil "-7 1/4"]          [":format fraction" "-7.25"]
+      [nil "2"]               [":format fractions" "19/20 + 1 1/20"]
+      [nil "-2"]              [":format frac" "19/17 - 3 2/17"]
+      [nil "3.14157"]         [":format frac" "3.14157"]
+      [nil "3 14157/100000"]  [":format frac 100000" "3.14157"]))
   (testing "display improper fractions"
     (are [values exprs] (= values (calc/eval-lines (str/join "\n" exprs)))
-      [nil "35/8"]            [":frac-i" "4.375"]
-      [nil "-29/4"]           [":frac-imp" "-7.25"]
-      [nil "3.14157"]         [":fractions-improper" "3.14157" ]
-      [nil "314157/100000"]   [":frac-i 100000" "3.14157"])))
+      [nil "35/8"]            [":format improper" "4.375"]
+      [nil "-29/4"]           [":format imp" "-7.25"]
+      [nil "3.14157"]         [":format improper" "3.14157" ]
+      [nil "314157/100000"]   [":format imp 100000" "3.14157"])))
 
 (deftest base-conversion
   (testing "mixed base input"
@@ -258,10 +258,11 @@
       32.0      "0b100 * 0b1000"))
   (testing "mixed base output"
     (are [values exprs] (= values (calc/eval-lines (str/join "\n" exprs)))
-      ["12345" "3039"]          ["12345" ":hex"]
-      ["12345" "30071"]         ["12345" ":oct"]
-      ["12345" "11000000111001"]["12345" ":bin"]
-      [nil "100000000"]         [":bin" "0b10000 * 0b10000"])))
+      ["12345" "0x3039"]          ["12345" ":hex"]
+      ["12345" "0o30071"]         ["12345" ":oct"]
+      ["12345" "0b11000000111001"]["12345" ":bin"]
+      [nil "0b100000000"]         [":bin" "0b10000 * 0b10000"]
+      [nil "-0xff"]               [":hex" "-255"])))
 
 (deftest comments
   (testing "comments are ignored"