-
Notifications
You must be signed in to change notification settings - Fork 1
/
Eval.hs
executable file
·57 lines (48 loc) · 2.32 KB
/
Eval.hs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
{-# LANGUAGE FlexibleContexts #-}
module Eval ( eval
, updateSymbolInParent
) where
import Types
import Data.Map as Map
import Control.Monad.State (get, modify, MonadState)
import Control.Monad.Error (throwError)
eval :: Expr -> Result
eval (Integer n) = return (Integer n)
eval (Fn f args) = return (Fn f args)
eval (Special f args) = return (Special f args)
eval (Symbol s) = do get >>= lookupSymbol
where lookupSymbol (Env symTable parentEnv) =
if s `member` symTable == True
then return (symTable ! s)
else case parentEnv of
Nothing -> throwError ("Symbol " ++ s ++ " is unbound.")
(Just parent) -> lookupSymbol parent
eval (QuotedList x) = return (List x)
eval (List (x:xs)) = eval x >>= apply
where apply (Special f expectedArgs) = apply' expectedArgs xs f
apply (Fn f expectedArgs) = do args <- mapM eval xs
apply' expectedArgs args f
apply _ = throwError "invalid function call"
apply' :: FuncSig -> [Expr] -> Result -> Result
apply' expectedArgs args f = do modify pushEnv
applyArgsToEnv expectedArgs args
result <- f
modify popEnv
return result
-- env funcs
applyArgsToEnv :: FuncSig -> [Expr] -> IOResult
applyArgsToEnv ("...":_) args = do updateSymbol "..." (List args)
applyArgsToEnv (earg:expectedArgs) (arg:args) = do updateSymbol earg arg
applyArgsToEnv expectedArgs args
applyArgsToEnv [] _ = return ()
applyArgsToEnv _ _ = throwError "Wrong arity"
updateSymbol :: MonadState Env m => String -> Expr -> m ()
updateSymbol s evalE = modify (\(Env symTable parentEnv) -> (Env (Map.insert s evalE symTable)) parentEnv)
updateSymbolInParent :: MonadState Env m => String -> Expr -> m ()
updateSymbolInParent s evalE = modify (\(Env symTable parentEnv) -> (Env symTable (updatedEnv parentEnv)))
where updatedEnv (Just (Env symTable env)) = (Just (Env (Map.insert s evalE symTable) env))
pushEnv :: Env -> Env
pushEnv env = Env empty (Just env)
popEnv :: Env -> Env
popEnv env@(Env _ Nothing) = env
popEnv (Env _ (Just parentEnv)) = parentEnv