calculator-0.1.2.2: src/Calculator/Evaluator.hs
module Calculator.Evaluator (eval) where
import Calculator.Parser (parseExpr)
import Calculator.Primitives
import Control.Applicative ((<$>), (<*))
import Data.Function (on)
import Text.ParserCombinators.Parsec (ParseError, eof, parse)
evaluate :: Expr -> Expr
evaluate e@(Constant _) = e
evaluate e@(InvalidError _) = e
evaluate (UnOp (UnaryOp op) e) = Constant . op . fromConst $ evaluate e
evaluate (BinOp (expr, rest)) = process expr rest
evaluate (Function "" e) = evaluate e
evaluate (Function f e) =
let func = lookup f dispatch :: Maybe (Number -> Number)
val = fromConst $ evaluate e
in case func of
Nothing -> InvalidError $ "Unknown function " ++ show f
Just g -> Constant $ g val
evaluate _ = InvalidError evalFaliure
process :: Expr -> [(Operator, Expr)] -> Expr
process expr rest = evaluate $ foldl evalPart expr rest
evalPart :: Expr -> (Operator, Expr) -> Expr
evalPart e1 ((BinaryOp op), e2) =
let val1 = evaluate e1
val2 = evaluate e2
in if isConst val1 && isConst val2
then Constant $ (op `on` fromConst) val1 val2
else case (val1, val2) of
(e@(InvalidError _), _) -> e
(_, e@(InvalidError _)) -> e
(_, _) -> InvalidError evalFaliure
evalPart _ _ = InvalidError evalFaliure
eval :: String -> Either ParseError Expr
eval s = evaluate <$> parse (parseExpr <* eof) s s