-
Notifications
You must be signed in to change notification settings - Fork 0
/
Eval.hs
245 lines (182 loc) · 5.54 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
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
module Eval where
import Control.Monad.Except
import Control.Applicative
import Text.Printf
import Data.Map as Map
import Data.IORef
import Syntax
data Value
= VInt Integer
| VBool Bool
| VChar Char
| VRef (IORef Value)
| VCons String [Value]
| VClosure String Expr (IORef Env)
| VPrim Int [Value] ([Value] -> IO Value)
instance Show Value where
show (VInt x) = show x
show (VBool x) = show x
show (VChar x) = show x
show (VRef _) = "<<ref>>"
show (VCons name values) = printf "(%s %s)" name (unwords $ fmap show values)
show (VClosure x body env) = "<<closure>>"
show (VPrim n argv f) = "<<prim>>"
instance Eq Value where
(VInt x) == (VInt y) = x==y
(VBool x) == (VBool y) = x==y
(VChar x) == (VChar y) = x==y
(VRef x) == (VRef y) = x==y
(VCons n0 es0) == (VCons n1 es1) = n0==n1 && es0==es1
type Env = Map String Value
eval :: IORef Env -> Expr -> IO Value
eval _ (Lit x) =
return $ case x of
(LInt x) -> VInt x
(LBool x) -> VBool x
(LChar x) -> VChar x
eval menv (Var x) = do
env <- readIORef menv
case Map.lookup x env of
Just v -> return v
Nothing -> fail $ printf "Variable not in scope: %s" (show x)
eval menv (DeRef x) = do
ref <- eval menv x
case ref of
VRef r -> readIORef r
_ -> fail $ printf "dereference a unknown value: %s" ++ (show x)
eval menv (Cond cond tr fl) = do
vc <- eval menv cond
case vc of
VBool True -> eval menv tr
VBool False -> eval menv fl
_ -> fail $ printf "Condition is not Bool Type: %s" (show vc)
eval menv (Block es) = do
rs <- traverse (eval menv) es
return $ last rs
eval menv (Case expr ps) = do
value <- eval menv expr
res <- runExceptT $ evalPatterns menv ps value
case res of
Left err -> fail err
Right ret -> return ret
eval menv (App func arg) = do
v <- eval menv func
argv <- eval menv arg
case v of
(VClosure x body mclos) -> do
clos <- readIORef mclos
menv' <- newIORef $ Map.insert x argv clos
eval menv' body
(VPrim 1 args f) ->
f (reverse $ argv:args)
(VPrim n args f) ->
return $ VPrim (n-1) (argv:args) f
(VCons ctor elems) -> do
return $ VCons ctor (elems++[argv])
_ -> fail $ printf "%s is not a function" (show v)
eval menv (Lambda x body) = do
return $ VClosure x body menv
eval menv (Let decls) = do
evalDecls menv decls
return $ VCons "Tuple" []
-----------------------------------------
evalDecl :: IORef Env -> Decl -> IO ()
evalDecl menv (Val pat expr) = do
value <- eval menv expr
res <- runExceptT $ match menv pat value
case res of
Left err -> fail err
Right () -> return ()
evalDecl menv (Func name params body) = do
let body' = Prelude.foldr Lambda body params
clos <- eval menv body'
env <- readIORef menv
writeIORef menv (Map.insert name clos env)
evalDecl menv (TypeCtor _ _ ctors) = do
let f (name, _) = Map.insert name (VCons name [])
env <- readIORef menv
let env' = Prelude.foldr f env ctors
writeIORef menv env'
evalDecl menv (TypeAlias _ _ _) = do
return ()
evalDecl menv (Proto _ _) = do
return ()
evalDecls :: IORef Env -> [Decl] -> IO ()
evalDecls menv decls = do
traverse (evalDecl menv) decls
return ()
evalModule :: Module -> IO Env
evalModule (Module decls) = do
menv <- newIORef initEnv
evalDecls menv decls
readIORef menv
-----------------------
match :: IORef Env -> Pattern -> Value -> ExceptT String IO ()
match menv PWild _ = return ()
match menv (PLit xx) yy = do
case (xx,yy) of
(LInt x, VInt y) -> guard $ x==y
(LBool x, VBool y) -> guard $ x==y
(LChar x, VChar y) -> guard $ x==y
_ -> fail $ printf "Dismatch Type: %s & %s" (show xx) (show yy)
match menv (PCons "Ref" [pat]) (VRef ref) = do
v <- lift $ readIORef ref
match menv pat v
match menv (PCons "Ref" pats) (VRef ref) = do
fail $ printf "Ref can not have multiple value: Ref %s" (unwords $ fmap show pats)
match menv (PCons pctor ps) (VCons vctor vs) = do
if pctor == vctor
then matchs menv ps vs
else throwError "Dismatch Ctor"
match menv (PVar capture name mpat) value = do
case mpat of
Nothing -> return ()
(Just pat) -> match menv pat value
env' <- lift $ readIORef menv
if capture
then case Map.lookup name env' of
Nothing -> throwError ("Variable not in scope: " ++ (show (name,env')))
Just v ->
if v==value
then return ()
else throwError "Can not match capture variable"
else lift $ writeIORef menv $ Map.insert name value env'
matchs menv [] [] = return ()
matchs menv _ [] = fail "Dismatch Ctor"
matchs menv [] _ = fail "Dismatch Ctor"
matchs menv (p:ps) (v:vs) = do
match menv p v
matchs menv ps vs
evalPatterns :: IORef Env -> Cases -> Value -> ExceptT String IO Value
evalPatterns menv [] _ = throwError "Can not match any pattern"
evalPatterns menv ((pat,body):ps) value = do
env <- lift $ readIORef menv
let f = do
menv' <- lift $ newIORef env
match menv' pat value
lift $ eval menv' body
f <|> evalPatterns menv ps value
------------------------------------
add [VInt a, VInt b] = return $ VInt (a+b)
sub [VInt a, VInt b] = return $ VInt (a-b)
mul [VInt a, VInt b] = return $ VInt (a*b)
eq [a, b] = return $ VBool (a==b)
newRef [x] = do
r <- newIORef x
return $ VRef r
write [VRef p, x] = do
writeIORef p x
return $ VBool True
print0 [a] = do
print a
return $ VBool True
binop sym f = (sym, VPrim 2 [] f)
initEnv = fromList [
binop "+" add,
binop "-" sub,
binop "*" mul,
binop "==" eq,
binop "<-" write,
("print", VPrim 1 [] print0),
("Ref", VPrim 1 [] newRef)
]