module TopLevelFunctions where

import Prelude hiding (LT, GT, EQ, showList)
import Data.Maybe
import Value
import Operators


type FunEnv = [(String, Function)]
data Function = Function [String] Exp
  deriving Show

data Program = Program FunEnv Exp
  deriving Show

data Exp = Literal   Value
         | Unary     UnaryOp Exp
         | Binary    BinaryOp Exp Exp
         | If        Exp Exp Exp
         | Variable  String
         | Declare   String Exp Exp
         | Call      String [Exp]
  deriving Show
            
evaluate :: Exp -> Env -> FunEnv -> Value
evaluate (Literal v) env funEnv      = v

evaluate (Unary op a) env funEnv     = 
  unary op (evaluate a env funEnv)

evaluate (Binary op a b) env funEnv  = 
  binary op (evaluate a env funEnv) (evaluate b env funEnv)

evaluate (If a b c) env funEnv       = 
  let BoolV test = evaluate a env funEnv in
    if test then evaluate b env funEnv
            else evaluate c env funEnv

evaluate (Variable x) env funEnv     = fromJust (lookup x env)

evaluate (Declare x exp body) env funEnv = evaluate body newEnv funEnv
  where newEnv = (x, evaluate exp env funEnv) : env

evaluate (Call fun args) env funEnv   = evaluate body newEnv funEnv
  where Function xs body = fromJust (lookup fun funEnv)
        newEnv = zip xs [evaluate a env funEnv | a <- args]