packages feed

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