Skip to content

Instantly share code, notes, and snippets.

@nhusher
Last active April 26, 2018 15:07
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save nhusher/223096ffd27b58872568fa6178d820bd to your computer and use it in GitHub Desktop.
Save nhusher/223096ffd27b58872568fa6178d820bd to your computer and use it in GitHub Desktop.
(ns calc.core
(:require
[instaparse.core :as insta]
[clojure.pprint :refer [pprint]]))
; Define a parser:
(def parser
(insta/parser
"
<expr> = sum-expr
<sum-expr> = prod-expr | add | subtract
<prod-expr> = unary-expr | multiply | divide
<unary-expr> = apply | number | paren
add = sum-expr ws* <'+'> ws* sum-expr
subtract = sum-expr ws* <'-'> ws* sum-expr
multiply = prod-expr ws* <'*'> ws* prod-expr
divide = prod-expr ws* <'/'> ws* prod-expr
apply = #'\\w?[\\w\\d]+' ws* <'('> argument+ <')'>
<paren> = <'('> ws* expr ws* <')'>
<number> = negative | float | integer
<argument> = expr <','?> ws*
negative = <'-'> (float | integer)
float = #'\\d+\\.\\d+'
integer = #'\\d+'
<ws> = <#'\\s+'>
"))
(defmulti evaluate (fn [[action]] action))
(defmethod evaluate :multiply [[_ a b]] (* (evaluate a) (evaluate b)))
(defmethod evaluate :divide [[_ a b]] (/ (evaluate a) (evaluate b)))
(defmethod evaluate :add [[_ a b]] (+ (evaluate a) (evaluate b)))
(defmethod evaluate :subtract [[_ a b]] (- (evaluate a) (evaluate b)))
(defmethod evaluate :negative [[_ a]] (* (evaluate a) -1))
(defmethod evaluate :integer [[_ a]] (read-string a))
(defmethod evaluate :float [[_ a]] (read-string a)) ;todo: handle precision
(def functions
{ "sqrt" #(Math/sqrt %)
"floor" #(Math/floor %)
"ceil" #(Math/ceil %)
"pow" #(Math/pow %1 %2)})
; Apply a known function to the provided arguments:
(defmethod evaluate :apply [[_ f & args]]
(apply (get functions f) (map evaluate args)))
(defn -main [& args]
(println "Evaluating" (apply str args))
(pprint (evaluate (first (parser (apply str args))))))
(ns calc.core
(:require
[instaparse.core :as insta]
[clojure.pprint :refer [pprint]]))
; Define a parser:
(def parser
(insta/parser
"
<expr> = sum-expr
<sum-expr> = prod-expr | add | subtract
<prod-expr> = unary-expr | multiply | divide
<unary-expr> = number | paren
add = sum-expr ws* <'+'> ws* sum-expr
subtract = sum-expr ws* <'-'> ws* sum-expr
multiply = prod-expr ws* <'*'> ws* prod-expr
divide = prod-expr ws* <'/'> ws* prod-expr
<paren> = <'('> ws* expr ws* <')'>
<number> = negative | float | integer
negative = <'-'> (float | integer)
float = #'\\d+\\.\\d+'
integer = #'\\d+'
<ws> = <#'\\s+'>
"))
(defmulti evaluate (fn [[action]] action))
(defmethod evaluate :multiply [[_ a b]] (* (evaluate a) (evaluate b)))
(defmethod evaluate :divide [[_ a b]] (/ (evaluate a) (evaluate b)))
(defmethod evaluate :add [[_ a b]] (+ (evaluate a) (evaluate b)))
(defmethod evaluate :subtract [[_ a b]] (- (evaluate a) (evaluate b)))
(defmethod evaluate :negative [[_ a]] (* (evaluate a) -1))
(defmethod evaluate :integer [[_ a]] (read-string a))
(defmethod evaluate :float [[_ a]] (read-string a))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment