module Eval (eval,getPrec) where
import BasicNumber
import BasicNumberApprox
import Ast
import Env
-- eval takes an expression and environment, tries to reduce the expression,
-- and returns the reduced expression.
eval :: BasicExp -> Env -> BasicExp
eval (EVar evar) env = eval (lookupEnv evar env) env
eval (Func name args) env = case args of
[] -> Func name []
[arg] -> eval_func_1 name arg env
[arg1,arg2] -> eval_func_2 name arg1 arg2 env
args -> eval_func_n name args env
eval bexp env = bexp
-- get precision from the environment
getPrec :: Env -> Integer
getPrec env = prec
where
prec = read (show bprec)
bprec = case pexpr of
(Numb n) -> -n
_ -> -10
pexpr1 = lookupEnv "$prec" env
pexpr = eval pexpr1 env
-- evaluate functions with 1 argument.
eval_func_1 :: String -> BasicExp -> Env -> BasicExp
eval_func_1 name arg env =
if isBuiltin1 name then
(getBuiltin1 name) narg (getPrec env)
else Func name [narg]
where
narg = eval arg env
-- evaluate functions with 2 arguments.
eval_func_2 :: String -> BasicExp -> BasicExp -> Env -> BasicExp
eval_func_2 name arg1 arg2 env =
if isBuiltin2 name then
(getBuiltin2 name narg1 narg2) narg1 narg2 (getPrec env)
else Func name [narg1,narg2]
where
narg1 = eval arg1 env
narg2 = eval arg2 env
-- evaluate functions with n(n>2) arguments.
eval_func_n :: String -> [BasicExp] -> Env -> BasicExp
eval_func_n name args env = Func name nargs
where
nargs = map eval_element args
eval_element elem = eval elem env
-- test if a function is builtin of arity 1
isBuiltin1 :: String -> Bool
isBuiltin1 "sqrt" = True
isBuiltin1 "real" = True
isBuiltin1 "rat" = True
isBuiltin1 "neg" = True
isBuiltin1 _ = False
-- get a builtin function with 1 argument
getBuiltin1 :: String -> (BasicExp -> Integer -> BasicExp)
getBuiltin1 "sqrt" = aBnf2Bef1 "sqrt" sqrt1 where
sqrt1 :: BasicNumber -> Integer -> BasicNumber
sqrt1 n _ = sqrt n
getBuiltin1 "real" = aBnf2Bef1 "real" makeReal1 where
makeReal1 :: BasicNumber -> Integer -> BasicNumber
makeReal1 n _ = makeReal n
getBuiltin1 "rat" = aBnf2Bef1 "rat" rtoRational
getBuiltin1 "neg" = aBnf2Bef1 "neg" negation where
negation :: BasicNumber -> Integer -> BasicNumber
negation x _ = 0-x
-- convert arithmetic functions on numbers to those on expressions
aBnf2Bef1 :: String -> (BasicNumber -> Integer -> BasicNumber) ->
(BasicExp -> Integer -> BasicExp)
aBnf2Bef1 name fun arg prec =
case arg of
(Numb n) -> Numb (fun n prec)
_ -> (Func name [arg])
-- test if a function is builtin of arity 2
isBuiltin2 :: String -> Bool
isBuiltin2 "add" = True
isBuiltin2 "sub" = True
isBuiltin2 "mul" = True
isBuiltin2 "div" = True
isBuiltin2 "equ" = True
isBuiltin2 "ne" = True
isBuiltin2 "gte" = True
isBuiltin2 "lte" = True
isBuiltin2 "lt" = True
isBuiltin2 "gt" = True
isBuiltin2 _ = False
-- get a builtin function with 2 arguments
getBuiltin2 :: String -> BasicExp -> BasicExp ->
(BasicExp -> BasicExp -> Integer -> BasicExp)
getBuiltin2 "add" _ _ = aBnf2Bef "add" (+)
getBuiltin2 "sub" _ _ = aBnf2Bef "sub" (-)
getBuiltin2 "mul" _ _ = aBnf2Bef "mul" (*)
getBuiltin2 "div" _ _ = aBnf2Bef "div" (/)
getBuiltin2 "equ" _ _ = bBnf2Bef "equ" equ
getBuiltin2 "ne" _ _ = bBnf2Bef "ne" ne
getBuiltin2 "lt" _ _ = bBnf2Bef "lt" lt
getBuiltin2 "gt" _ _ = bBnf2Bef "gt" gt
getBuiltin2 "gte" _ _ = bBnf2Bef "gte" gte
getBuiltin2 "lte" _ _ = bBnf2Bef "lte" lte
-- convert Haskell boolean to basic expression
bool2bexp :: Bool -> BasicExp
bool2bexp True = Numb 1
bool2bexp False = Numb 0
-- convert boolean functions on numbers to those on expressions
bBnf2Bef :: String -> (BasicNumber -> BasicNumber -> Integer -> Bool)
-> BasicExp -> BasicExp -> Integer -> BasicExp
bBnf2Bef name fun e1 e2 prec =
case (e1,e2) of
((Numb n1),(Numb n2)) -> bool2bexp (fun n1 n2 prec)
_ -> (Func name [e1,e2])
-- convert arithmetic functions on numbers to those on expressions
aBnf2Bef :: String -> (BasicNumber -> BasicNumber -> BasicNumber) ->
(BasicExp -> BasicExp -> Integer -> BasicExp)
aBnf2Bef name fun arg1 arg2 _ =
case (arg1,arg2) of
((Numb n1),(Numb n2)) -> Numb (fun n1 n2)
_ -> (Func name [arg1, arg2])
|