module IncorrectFunctions where

import Prelude hiding (LT, GT, EQ)
import Data.Maybe
import Base
import Operators
import FunctionalEnvironment

data Value = IntV  Int
           | BoolV Bool
           | Function String Exp  -- new
  deriving (Eq, Show)

data Exp = Literal   Value
         | Unary     UnaryOp Exp
         | Binary    BinaryOp Exp Exp
         | If        Exp Exp Exp
         | Variable  String
         | Declare   String Exp Exp
         | Call      Exp Exp         -- changed
  deriving (Eq, Show)

type Env = String -> Maybe Value

-- most of this is the same as IntBool
evaluate :: Exp -> Env -> Value
evaluate (Literal v) env      = v
evaluate (Unary op a) env     = unary op (evaluate a env)
evaluate (Binary op a b) env  = binary op (evaluate a env) (evaluate b env)
evaluate (If a b c) env = 
  let BoolV test = evaluate a env in
    if test then evaluate b env
            else evaluate c env
evaluate (Declare x exp body) env = evaluate body newEnv
  where newEnv = bindF x (evaluate exp env) env
evaluate (Variable x) env     =
  case env x of
    Nothing -> error ("Variable " ++ x ++ " undefined")
    Just v  -> v
evaluate (Call fun arg) env = evaluate body newEnv
  where Function x body = evaluate fun env
        newEnv = bindF x (evaluate arg env) env

emptyEnv = \x->Nothing

-- Same as IntBool

unary Not (BoolV b) = BoolV (not b)
unary Neg (IntV i)  = IntV (-i)

binary Add (IntV a)  (IntV b)  = IntV (a + b)
binary Sub (IntV a)  (IntV b)  = IntV (a - b)
binary Mul (IntV a)  (IntV b)  = IntV (a * b)
binary Div (IntV a)  (IntV b)  = IntV (a `div` b)
binary And (BoolV a) (BoolV b) = BoolV (a && b)
binary Or  (BoolV a) (BoolV b) = BoolV (a || b)
binary LT  (IntV a)  (IntV b)  = BoolV (a < b)
binary LE  (IntV a)  (IntV b)  = BoolV (a <= b)
binary GE  (IntV a)  (IntV b)  = BoolV (a >= b)
binary GT  (IntV a)  (IntV b)  = BoolV (a > b)
binary EQ  a         b         = BoolV (a == b)