-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathdynamic.sml
More file actions
276 lines (238 loc) · 8.01 KB
/
dynamic.sml
File metadata and controls
276 lines (238 loc) · 8.01 KB
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
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
structure Dynamic = struct
open Std
exception Panic of string
type var = string
structure VarMap = BinarySearchMap struct
type t = var
val compare = String.compare
end
structure Pattern = struct
datatype t
= Wildcard
| Var of var
| Constructor of constr_ident * t option
| Tuple of t list
end
type pattern = Pattern.t
structure Literal = Syntax.Literal
datatype t
= Var of var
| Abs of var * t
| App of t * t
| Record of t Record.t
| Tuple of t list
| Proj of t * label
| Let of var * t * t
| Lit of Literal.t
| List of t list
| ConsList of t * t
| If of t * t * t
| Constructor of constr_ident
| Match of t * branches
| LetRec of (var * t) list * t
withtype branch = pattern * t
and branches = (pattern * t) list
fun expect s (SOME x) = x
| expect s NONE = raise Fail s
structure Sem = struct
datatype t
= Lit of Literal.t
| Fun of t -> t
| Record of t Record.t
| Tuple of t list
| List of t list
| Constructor of constr_ident * t option
| Ref of t ref
datatype u
= Value of t
| Loc of t option ref
fun deref (Loc r) = !r |> expect "deref"
| deref (Value s) = s
val unit = Lit Literal.Unit
fun get_int (Lit (Literal.Int v)) = v
| get_int _ = raise Fail "not int"
fun get_bool (Lit (Literal.Bool v)) = v
| get_bool _ = raise Fail "not bool"
fun get_string (Lit (Literal.String v)) = v
| get_string _ = raise Fail "not string"
fun get_record (Record m) = m
| get_record _ = raise Fail "not record"
fun get_list (List xs) = xs
| get_list _ = raise Fail "not list"
fun get_ref (Ref r) = r
| get_ref _ = raise Fail "not reference"
fun fun2 f = Fun (fn s1 => Fun (fn s2 => f (s1, s2)))
end
structure Env : sig
type t
val initial : t
exception Unbound of var
val insert_value : var -> Sem.t -> t -> t
val lookup : var -> t -> Sem.u
end = struct
type t = Sem.u VarMap.t
fun insert_value v s = VarMap.insert v (Sem.Value s)
exception Unbound of var
fun lookup v env =
case VarMap.lookup v env of
SOME x => x
| NONE => raise Unbound(v)
fun compare_int (s1, s2) =
let
val n1 = Sem.get_int s1
val n2 = Sem.get_int s2
val s =
case Int.compare (n1, n2) of
LESS => "LT"
| EQUAL => "EQ"
| GREATER => "GT"
in
Sem.Constructor(ConstrID.from_string s, NONE)
end
fun compare_string (s1, s2) =
let
val s1 = Sem.get_string s1
val s2 = Sem.get_string s2
val s =
case String.compare (s1, s2) of
LESS => "LT"
| EQUAL => "EQ"
| GREATER => "GT"
in
Sem.Constructor(ConstrID.from_string s, NONE)
end
val initial_modules = VarMap.from_list $
List.map (fn (x, s) => (Label.encode $ Label.module $ ModuleID.from_string x, Sem.Value s))
[ ( "MakeRef"
, Sem.Fun (fn _ => Sem.Record $ Record.from_list $
map (fn (x, y) => (Label.value $ ValID.from_string x, y))
[ ("make", Sem.Fun (fn s1 => Sem.Ref $ ref s1))
, ("get", Sem.Fun (fn s1 => !(Sem.get_ref s1)))
, ("set", Sem.fun2 (fn (s1, s2) => Sem.unit before Sem.get_ref s1 := s2))
])
)
]
val initial = VarMap.union initial_modules $ VarMap.from_list $
List.map (fn (x, s) => (Label.encode $ Label.value $ ValID.from_string x, Sem.Value s))
[ ( "print_endline"
, Sem.Fun (fn s => Sem.Lit Literal.Unit before print (Sem.get_string s ^ "\n"))
)
, ( "show_int"
, Sem.Fun (fn s => Sem.Lit $ Literal.String $ Int.toString $ Sem.get_int s)
)
, ( "concat_string"
, Sem.fun2 (fn (s1, s2) => Sem.Lit $ Literal.String $ Sem.get_string s1 ^ Sem.get_string s2)
)
, ( "+"
, Sem.fun2 (fn (s1, s2) => Sem.Lit $ Literal.Int $ Sem.get_int s1 + Sem.get_int s2)
)
, ( "-"
, Sem.fun2 (fn (s1, s2) => Sem.Lit $ Literal.Int $ Sem.get_int s1 - Sem.get_int s2)
)
, ( "*"
, Sem.fun2 (fn (s1, s2) => Sem.Lit $ Literal.Int $ Sem.get_int s1 * Sem.get_int s2)
)
, ("compare_int", Sem.fun2 compare_int)
, ("compare_string", Sem.fun2 compare_string)
, ("panic", Sem.Fun (fn s => raise Panic(Sem.get_string s)))
]
end
fun zip [] [] = []
| zip (x :: xs) (y :: ys) = (x, y) :: zip xs ys
| zip _ _ = []
infix >>=
fun NONE >>= _ = NONE
| (SOME x) >>= f = f x
fun pattern_match env p s : Env.t option =
case (p, s) of
(Pattern.Wildcard, _) => SOME env
| (Pattern.Var v, _) => SOME $ Env.insert_value v s env
| (Pattern.Constructor(id1, p_opt), Sem.Constructor(id2, s_opt)) =>
if ConstrID.eq (id1, id2)
then
case (p_opt, s_opt) of
(NONE, NONE) => SOME env
| (SOME p, SOME s) => pattern_match env p s
| _ => raise Fail "argument mismatch"
else NONE
| (Pattern.Tuple ps, Sem.Tuple ss) =>
let
val xs = zip ps ss
in
foldl (fn ((p, s), acc) => acc >>= (fn acc' => pattern_match acc' p s)) (SOME env) xs
end
| (Pattern.Constructor(id, p_opt), Sem.List ss) =>
if ConstrID.eq(id, ConstrID.from_string "[]")
then
case ss of
[] => SOME env
| _ => NONE
else if ConstrID.eq(id, ConstrID.from_string "::")
then
case ss of
[] => NONE
| x :: xs => pattern_match env (expect "::" p_opt) $ Sem.Tuple [x, Sem.List xs]
else NONE
| _ => NONE
fun eval env (Var v) = Env.lookup v env |> Sem.deref
| eval env (Abs(v, x)) = Sem.Fun(fn s => eval (Env.insert_value v s env) x)
| eval env (App(x, y)) =
let
val s1 = eval env x
val s2 = eval env y
in
case s1 of
Sem.Fun f => f s2
| Sem.Constructor(id, NONE) => Sem.Constructor(id, SOME s2)
| _ => raise Fail "could not apply"
end
| eval env (Record m) = Sem.Record $ Record.map (eval env) m
| eval env (Tuple xs) = Sem.Tuple $ map (eval env) xs
| eval env (Proj(x, l)) =
let val r = eval env x |> Sem.get_record in
case r |> Record.lookup l of
SOME s => s
| NONE => raise Fail ("projection: " ^ Label.encode l ^ " from " ^ Int.toString (Record.size r))
end
| eval env (Let(v, x, y)) =
let val s1 = eval env x in
eval (Env.insert_value v s1 env) y
end
| eval env (Lit l) = Sem.Lit l
| eval env (List xs) = Sem.List $ List.map (eval env) xs
| eval env (ConsList(x, y)) =
let
val h = eval env x
val t = eval env y |> Sem.get_list
in
Sem.List $ h :: t
end
| eval env (If(x, y, z)) =
let
val s1 = eval env x
in
if Sem.get_bool s1
then eval env y
else eval env z
end
| eval env (Constructor id) = Sem.Constructor(id, NONE)
| eval env (Match(x, bs)) =
let
val s1 = eval env x
fun f [] = raise Fail "no match"
| f ((p, y) :: bs) =
case pattern_match env p s1 of
SOME env' => eval env' y
| NONE => f bs
in
f bs
end
| eval env (LetRec(xs, y)) =
let
val xs = map (fn (v, x) => (v, x, ref NONE)) xs
val env1 = foldl (fn ((v, _, r), acc) => VarMap.insert v (Sem.Loc r) acc) env xs
val () = List.app (fn (_, x, r) => let val s = eval env1 x in r := SOME s end) xs
in
eval env1 y
end
end