comparison src/rpcify.sml @ 908:ed06e25c70ef

Convert to requiring explicit 'rpc' marker
author Adam Chlipala <adamc@hcoop.net>
date Sat, 22 Aug 2009 12:55:18 -0400
parents a28982de5645
children 2a50da66ffd8
comparison
equal deleted inserted replaced
907:5fe49effbc83 908:ed06e25c70ef
38 structure SS = BinarySetFn(struct 38 structure SS = BinarySetFn(struct
39 type ord_key = string 39 type ord_key = string
40 val compare = String.compare 40 val compare = String.compare
41 end) 41 end)
42 42
43 fun multiLiftExpInExp n e =
44 if n = 0 then
45 e
46 else
47 multiLiftExpInExp (n - 1) (E.liftExpInExp 0 e)
48
49 type state = { 43 type state = {
50 cpsed : int IM.map,
51 cpsed_range : con IM.map,
52 cps_decls : (string * int * con * exp * string) list,
53
54 exported : IS.set, 44 exported : IS.set,
55 export_decls : decl list, 45 export_decls : decl list
56
57 maxName : int
58 } 46 }
59 47
60 fun frob file = 48 fun frob file =
61 let 49 let
62 fun sideish (basis, ssids) e = 50 val rpcBaseIds = foldl (fn ((d, _), rpcIds) =>
63 U.Exp.exists {kind = fn _ => false, 51 case d of
64 con = fn _ => false, 52 DVal (_, n, _, (EFfi ("Basis", "rpc"), _), _) => IS.add (rpcIds, n)
65 exp = fn ENamed n => IS.member (ssids, n) 53 | DVal (_, n, _, (ENamed n', _), _) => if IS.member (rpcIds, n') then
66 | EFfi x => basis x 54 IS.add (rpcIds, n)
67 | EFfiApp (m, x, _) => basis (m, x) 55 else
68 | _ => false} 56 rpcIds
69 (U.Exp.map {kind = fn x => x, 57 | _ => rpcIds)
70 con = fn x => x, 58 IS.empty file
71 exp = fn ERecord _ => ERecord []
72 | x => x} e)
73
74 fun whichIds basis =
75 let
76 fun decl ((d, _), ssids) =
77 let
78 val impure = sideish (basis, ssids)
79 in
80 case d of
81 DVal (_, n, _, e, _) => if impure e then
82 IS.add (ssids, n)
83 else
84 ssids
85 | DValRec xes => if List.exists (fn (_, _, _, e, _) => impure e) xes then
86 foldl (fn ((_, n, _, _, _), ssids) => IS.add (ssids, n))
87 ssids xes
88 else
89 ssids
90 | _ => ssids
91 end
92 in
93 foldl decl IS.empty file
94 end
95
96 val ssids = whichIds Settings.isServerOnly
97 val csids = whichIds Settings.isClientOnly
98
99 fun sideish' (basis, ids) extra =
100 sideish (basis, IM.foldli (fn (id, _, ids) => IS.add (ids, id)) ids extra)
101
102 val serverSide = sideish' (Settings.isServerOnly, ssids)
103 val clientSide = sideish' (Settings.isClientOnly, csids)
104 59
105 val tfuncs = foldl 60 val tfuncs = foldl
106 (fn ((d, _), tfuncs) => 61 (fn ((d, _), tfuncs) =>
107 let 62 let
108 fun doOne ((x, n, t, e, _), tfuncs) = 63 fun doOne ((x, n, t, e, _), tfuncs) =
132 IM.empty file 87 IM.empty file
133 88
134 fun exp (e, st) = 89 fun exp (e, st) =
135 let 90 let
136 fun getApp (e', args) = 91 fun getApp (e', args) =
137 let 92 case e' of
138 val loc = #2 e' 93 ENamed n => SOME (n, args)
139 in 94 | EApp (e1, e2) => getApp (#1 e1, e2 :: args)
140 case #1 e' of 95 | _ => NONE
141 ENamed n => (n, args)
142 | EApp (e1, e2) => getApp (e1, e2 :: args)
143 | _ => (ErrorMsg.errorAt loc "Mixed client/server code doesn't use a named function for server part";
144 (*Print.prefaces "Bad" [("e", CorePrint.p_exp CoreEnv.empty (e, ErrorMsg.dummySpan))];*)
145 (0, []))
146 end
147 96
148 fun newRpc (trans1, trans2, st : state) = 97 fun newRpc (trans : exp, st : state) =
149 let 98 case getApp (#1 trans, []) of
150 val loc = #2 trans1 99 NONE => (ErrorMsg.errorAt (#2 trans)
100 "RPC code doesn't use a named function or transaction";
101 (#1 trans, st))
102 | SOME (n, args) =>
103 case IM.find (tfuncs, n) of
104 NONE => ((*Print.prefaces "BAD" [("e", CorePrint.p_exp CoreEnv.empty (e, loc))];*)
105 raise Fail ("Rpcify: Undetected transaction function " ^ Int.toString n))
106 | SOME (_, _, ran, _) =>
107 let
108 val loc = #2 trans
151 109
152 val (n, args) = getApp (trans1, []) 110 val (exported, export_decls) =
111 if IS.member (#exported st, n) then
112 (#exported st, #export_decls st)
113 else
114 (IS.add (#exported st, n),
115 (DExport (Rpc ReadWrite, n), loc) :: #export_decls st)
153 116
154 val (exported, export_decls) = 117 val st = {exported = exported,
155 if IS.member (#exported st, n) then 118 export_decls = export_decls}
156 (#exported st, #export_decls st)
157 else
158 (IS.add (#exported st, n),
159 (DExport (Rpc ReadWrite, n), loc) :: #export_decls st)
160 119
161 val st = {cpsed = #cpsed st, 120 val k = (ECApp ((EFfi ("Basis", "return"), loc),
162 cpsed_range = #cpsed_range st, 121 (CFfi ("Basis", "transaction"), loc)), loc)
163 cps_decls = #cps_decls st, 122 val k = (ECApp (k, ran), loc)
164 123 val k = (EApp (k, (EFfi ("Basis", "transaction_monad"), loc)), loc)
165 exported = exported, 124 val e' = EServerCall (n, args, k, ran, ran)
166 export_decls = export_decls,
167
168 maxName = #maxName st}
169
170 val ran =
171 case IM.find (tfuncs, n) of
172 NONE => ((*Print.prefaces "BAD" [("e", CorePrint.p_exp CoreEnv.empty (e, loc))];*)
173 raise Fail ("Rpcify: Undetected transaction function " ^ Int.toString n))
174 | SOME (_, _, ran, _) => ran
175
176 val e' = EServerCall (n, args, trans2, ran)
177 in
178 (e', st)
179 end
180
181 fun newCps (t1, t2, trans1, trans2, st) =
182 let
183 val loc = #2 trans1
184
185 val (n, args) = getApp (trans1, [])
186
187 fun makeCall n' =
188 let
189 val e = (ENamed n', loc)
190 val e = (EApp (e, trans2), loc)
191 in 125 in
192 #1 (foldl (fn (arg, e) => (EApp (e, arg), loc)) e args) 126 (e', st)
193 end 127 end
194 in
195 case IM.find (#cpsed_range st, n) of
196 SOME kdom =>
197 (case args of
198 [] => raise Fail "Rpcify: cps'd function lacks first argument"
199 | ke :: args =>
200 let
201 val ke' = (EFfi ("Basis", "bind"), loc)
202 val ke' = (ECApp (ke', (CFfi ("Basis", "transaction"), loc)), loc)
203 val ke' = (ECApp (ke', kdom), loc)
204 val ke' = (ECApp (ke', t2), loc)
205 val ke' = (EApp (ke', (EFfi ("Basis", "transaction_monad"), loc)), loc)
206 val ke' = (EApp (ke', (EApp (E.liftExpInExp 0 ke, (ERel 0, loc)), loc)), loc)
207 val ke' = (EApp (ke', E.liftExpInExp 0 trans2), loc)
208 val ke' = (EAbs ("x", kdom,
209 (CApp ((CFfi ("Basis", "transaction"), loc), t2), loc),
210 ke'), loc)
211
212 val e' = (ENamed n, loc)
213 val e' = (EApp (e', ke'), loc)
214 val e' = foldl (fn (arg, e') => (EApp (e', arg), loc)) e' args
215 val (e', st) = doExp (e', st)
216 in
217 (#1 e', st)
218 end)
219 | NONE =>
220 case IM.find (#cpsed st, n) of
221 SOME n' => (makeCall n', st)
222 | NONE =>
223 let
224 val (name, fargs, ran, e) =
225 case IM.find (tfuncs, n) of
226 NONE => (Print.prefaces "BAD" [("e",
227 CorePrint.p_exp CoreEnv.empty (e, loc))];
228 raise Fail "Rpcify: Undetected transaction function [2]")
229 | SOME x => x
230
231 val n' = #maxName st
232
233 val st = {cpsed = IM.insert (#cpsed st, n, n'),
234 cpsed_range = IM.insert (#cpsed_range st, n', ran),
235 cps_decls = #cps_decls st,
236 exported = #exported st,
237 export_decls = #export_decls st,
238 maxName = n' + 1}
239
240 val unit = (TRecord (CRecord ((KType, loc), []), loc), loc)
241 val body = (EFfi ("Basis", "bind"), loc)
242 val body = (ECApp (body, (CFfi ("Basis", "transaction"), loc)), loc)
243 val body = (ECApp (body, t1), loc)
244 val body = (ECApp (body, unit), loc)
245 val body = (EApp (body, (EFfi ("Basis", "transaction_monad"), loc)), loc)
246 val body = (EApp (body, e), loc)
247 val body = (EApp (body, (ERel (length args), loc)), loc)
248 val bt = (CApp ((CFfi ("Basis", "transaction"), loc), unit), loc)
249 val (body, bt) = foldr (fn ((x, t), (body, bt)) =>
250 ((EAbs (x, t, bt, body), loc),
251 (TFun (t, bt), loc)))
252 (body, bt) fargs
253 val kt = (TFun (ran, (CApp ((CFfi ("Basis", "transaction"), loc),
254 unit),
255 loc)), loc)
256 val body = (EAbs ("k", kt, bt, body), loc)
257 val bt = (TFun (kt, bt), loc)
258
259 val (body, st) = doExp (body, st)
260
261 val vi = (name ^ "_cps",
262 n',
263 bt,
264 body,
265 "")
266
267 val st = {cpsed = #cpsed st,
268 cpsed_range = #cpsed_range st,
269 cps_decls = vi :: #cps_decls st,
270 exported = #exported st,
271 export_decls = #export_decls st,
272 maxName = #maxName st}
273 in
274 (makeCall n', st)
275 end
276 end
277
278 fun dummyK loc =
279 let
280 val unit = (TRecord (CRecord ((KType, loc), []), loc), loc)
281
282 val k = (EFfi ("Basis", "return"), loc)
283 val k = (ECApp (k, (CFfi ("Basis", "transaction"), loc)), loc)
284 val k = (ECApp (k, unit), loc)
285 val k = (EApp (k, (EFfi ("Basis", "transaction_monad"), loc)), loc)
286 val k = (EApp (k, (ERecord [], loc)), loc)
287 in
288 (EAbs ("_", unit, unit, k), loc)
289 end
290 in 128 in
291 case e of 129 case e of
292 EApp ( 130 EApp ((ECApp ((EFfi ("Basis", "rpc"), _), ran), _), trans) => newRpc (trans, st)
293 (EApp 131 | EApp ((ECApp ((ENamed n, _), ran), _), trans) =>
294 ((EApp ((ECApp ((ECApp ((ECApp ((EFfi ("Basis", "bind"), loc), _), _), t1), _), t2), _), 132 if IS.member (rpcBaseIds, n) then
295 (EFfi ("Basis", "transaction_monad"), _)), _), 133 newRpc (trans, st)
296 (ECase (ed, pes, {disc, ...}), _)), _), 134 else
297 trans2) => 135 (e, st)
298 let
299 val e' = (EFfi ("Basis", "bind"), loc)
300 val e' = (ECApp (e', (CFfi ("Basis", "transaction"), loc)), loc)
301 val e' = (ECApp (e', t1), loc)
302 val e' = (ECApp (e', t2), loc)
303 val e' = (EApp (e', (EFfi ("Basis", "transaction_monad"), loc)), loc)
304
305 val (pes, st) = ListUtil.foldlMap (fn ((p, e), st) =>
306 let
307 val e' = (EApp (e', e), loc)
308 val e' = (EApp (e',
309 multiLiftExpInExp (E.patBindsN p)
310 trans2), loc)
311 val (e', st) = doExp (e', st)
312 in
313 ((p, e'), st)
314 end) st pes
315 in
316 (ECase (ed, pes, {disc = disc,
317 result = (CApp ((CFfi ("Basis", "transaction"), loc), t2), loc)}),
318 st)
319 end
320
321 | EApp (
322 (EApp
323 ((EApp ((ECApp ((ECApp ((ECApp ((EFfi ("Basis", "bind"), loc), _), _), t1), _), t2), _),
324 (EFfi ("Basis", "transaction_monad"), _)), _),
325 (EServerCall (n, es, ke, t), _)), _),
326 trans2) =>
327 let
328 val e' = (EFfi ("Basis", "bind"), loc)
329 val e' = (ECApp (e', (CFfi ("Basis", "transaction"), loc)), loc)
330 val e' = (ECApp (e', t), loc)
331 val e' = (ECApp (e', t2), loc)
332 val e' = (EApp (e', (EFfi ("Basis", "transaction_monad"), loc)), loc)
333 val e' = (EApp (e', (EApp (E.liftExpInExp 0 ke, (ERel 0, loc)), loc)), loc)
334 val e' = (EApp (e', E.liftExpInExp 0 trans2), loc)
335 val e' = (EAbs ("x", t, t2, e'), loc)
336 val e' = (EServerCall (n, es, e', t), loc)
337 val (e', st) = doExp (e', st)
338 in
339 (#1 e', st)
340 end
341
342 | EApp (
343 (EApp
344 ((EApp ((ECApp ((ECApp ((ECApp ((EFfi ("Basis", "bind"), loc), _), _), _), _), t3), _),
345 (EFfi ("Basis", "transaction_monad"), _)), _),
346 (EApp ((EApp
347 ((EApp ((ECApp ((ECApp ((ECApp ((EFfi ("Basis", "bind"), _), _), _), t1), _), t2), _),
348 (EFfi ("Basis", "transaction_monad"), _)), _),
349 trans1), _), trans2), _)), _),
350 trans3) =>
351 let
352 val e'' = (EFfi ("Basis", "bind"), loc)
353 val e'' = (ECApp (e'', (CFfi ("Basis", "transaction"), loc)), loc)
354 val e'' = (ECApp (e'', t2), loc)
355 val e'' = (ECApp (e'', t3), loc)
356 val e'' = (EApp (e'', (EFfi ("Basis", "transaction_monad"), loc)), loc)
357 val e'' = (EApp (e'', (EApp (E.liftExpInExp 0 trans2, (ERel 0, loc)), loc)), loc)
358 val e'' = (EApp (e'', E.liftExpInExp 0 trans3), loc)
359 val e'' = (EAbs ("x", t1, (CApp ((CFfi ("Basis", "transaction"), loc), t3), loc), e''), loc)
360
361 val e' = (EFfi ("Basis", "bind"), loc)
362 val e' = (ECApp (e', (CFfi ("Basis", "transaction"), loc)), loc)
363 val e' = (ECApp (e', t1), loc)
364 val e' = (ECApp (e', t3), loc)
365 val e' = (EApp (e', (EFfi ("Basis", "transaction_monad"), loc)), loc)
366 val e' = (EApp (e', trans1), loc)
367 val e' = (EApp (e', e''), loc)
368 val (e', st) = doExp (e', st)
369 in
370 (#1 e', st)
371 end
372
373 | EApp (
374 (EApp
375 ((EApp ((ECApp ((ECApp ((ECApp ((EFfi ("Basis", "bind"), _), _), _), _), _), _), _),
376 (EFfi ("Basis", "transaction_monad"), _)), _),
377 _), loc),
378 (EAbs (_, _, _, (EWrite _, _)), _)) => (e, st)
379
380 | EApp (
381 (EApp
382 ((EApp ((ECApp ((ECApp ((ECApp ((EFfi ("Basis", "bind"), _), _), _), t1), _), t2), _),
383 (EFfi ("Basis", "transaction_monad"), _)), _),
384 trans1), loc),
385 trans2) =>
386 (case (serverSide (#cpsed_range st) trans1, clientSide (#cpsed_range st) trans1,
387 serverSide (#cpsed_range st) trans2, clientSide (#cpsed_range st) trans2) of
388 (true, false, _, true) => newRpc (trans1, trans2, st)
389 | (_, true, true, false) =>
390 (case #1 trans2 of
391 EAbs (x, dom, ran, trans2) =>
392 let
393 val (trans2, st) = newRpc (trans2, dummyK loc, st)
394 val trans2 = (EAbs (x, dom, ran, (trans2, loc)), loc)
395
396 val e = (EFfi ("Basis", "bind"), loc)
397 val e = (ECApp (e, (CFfi ("Basis", "transaction"), loc)), loc)
398 val e = (ECApp (e, t1), loc)
399 val e = (ECApp (e, t2), loc)
400 val e = (EApp (e, (EFfi ("Basis", "transaction_monad"), loc)), loc)
401 val e = (EApp (e, trans1), loc)
402 val e = EApp (e, trans2)
403 in
404 (e, st)
405 end
406 | _ => (e, st))
407 | (true, true, _, _) => newCps (t1, t2, trans1, trans2, st)
408
409 | _ => (e, st))
410
411 | ERecord xes =>
412 let
413 val loc = case xes of
414 [] => ErrorMsg.dummySpan
415 | (_, (_, loc), _) :: _ => loc
416
417 fun candidate (x, e) =
418 String.isPrefix "On" x
419 andalso serverSide (#cpsed_range st) e
420 andalso not (clientSide (#cpsed_range st) e)
421 in
422 if List.exists (fn ((CName x, _), e, _) => candidate (x, e)
423 | _ => false) xes then
424 let
425 val (xes, st) = ListUtil.foldlMap
426 (fn (y as (nm as (CName x, _), e, t), st) =>
427 if candidate (x, e) then
428 let
429 val (e, st) = newRpc (e, dummyK loc, st)
430 in
431 ((nm, (e, loc), t), st)
432 end
433 else
434 (y, st)
435 | y => y)
436 st xes
437 in
438 (ERecord xes, st)
439 end
440 else
441 (e, st)
442 end
443 136
444 | _ => (e, st) 137 | _ => (e, st)
445 end 138 end
446 139
447 and doExp (e, st) = U.Exp.foldMap {kind = fn x => x, 140 and doExp (e, st) = U.Exp.foldMap {kind = fn x => x,
454 con = fn x => x, 147 con = fn x => x,
455 exp = exp, 148 exp = exp,
456 decl = fn x => x} 149 decl = fn x => x}
457 st d 150 st d
458 in 151 in
459 (List.revAppend (case #cps_decls st of 152 (#export_decls st @ [d],
460 [] => [d] 153 {exported = #exported st,
461 | ds => 154 export_decls = []})
462 case d of
463 (DValRec vis, loc) => [(DValRec (ds @ vis), loc)]
464 | (_, loc) => [d, (DValRec ds, loc)],
465 #export_decls st),
466 {cpsed = #cpsed st,
467 cpsed_range = #cpsed_range st,
468 cps_decls = [],
469
470 exported = #exported st,
471 export_decls = [],
472
473 maxName = #maxName st})
474 end 155 end
475 156
476 val (file, _) = ListUtil.foldlMapConcat decl 157 val (file, _) = ListUtil.foldlMapConcat decl
477 {cpsed = IM.empty, 158 {exported = IS.empty,
478 cpsed_range = IM.empty, 159 export_decls = []}
479 cps_decls = [],
480
481 exported = IS.empty,
482 export_decls = [],
483
484 maxName = U.File.maxName file + 1}
485 file 160 file
486 in 161 in
487 file 162 file
488 end 163 end
489 164