Commit | Line | Data |
---|---|---|
7f918cf1 CE |
1 | (* Copyright (C) 1999-2008 Henry Cejtin, Matthew Fluet, Suresh |
2 | * Jagannathan, and Stephen Weeks. | |
3 | * Copyright (C) 1997-2000 NEC Research Institute. | |
4 | * | |
5 | * MLton is released under a BSD-style license. | |
6 | * See the file MLton-LICENSE for details. | |
7 | *) | |
8 | ||
9 | functor ImplementExceptions (S: XML_TRANSFORM_STRUCTS): XML_TRANSFORM = | |
10 | struct | |
11 | ||
12 | open S | |
13 | datatype z = datatype Dec.t | |
14 | datatype z = datatype PrimExp.t | |
15 | structure Dexp = DirectExp | |
16 | ||
17 | fun transform (Program.T {datatypes, body, ...}): Program.t = | |
18 | let | |
19 | (* topLevelHandler holds the ref cell containing the function of | |
20 | * type exn -> unit that should be called on unhandled exceptions. | |
21 | *) | |
22 | val topLevelHandlerType = Type.arrow (Type.exn, Type.unit) | |
23 | val topLevelHandlerVar = Var.newNoname () | |
24 | val extraType = | |
25 | Exn.withEscape | |
26 | (fn escape => | |
27 | let | |
28 | val _ = | |
29 | Exp.foreachPrimExp | |
30 | (body, fn (_, _, e) => | |
31 | case e of | |
32 | PrimApp {prim, targs, ...} => | |
33 | (case Prim.name prim of | |
34 | Prim.Name.Exn_extra => | |
35 | escape (Vector.first targs) | |
36 | | Prim.Name.Exn_setExtendExtra => | |
37 | escape (Vector.first targs) | |
38 | | _ => ()) | |
39 | | _ => ()) | |
40 | in | |
41 | Type.unit | |
42 | end) | |
43 | val dfltExtraVar = Var.newNoname () | |
44 | val dfltExtraExp = | |
45 | if Type.isUnit extraType | |
46 | then Dexp.unit () | |
47 | else let | |
48 | val extraTycon = Type.tycon extraType | |
49 | val extraCon = | |
50 | Exn.withEscape | |
51 | (fn escape => | |
52 | let | |
53 | val _ = | |
54 | Vector.foreach | |
55 | (datatypes, fn {cons, tycon, ...} => | |
56 | if Tycon.equals (tycon, extraTycon) | |
57 | then Vector.foreach | |
58 | (cons, fn {arg, con, ...} => | |
59 | case arg of | |
60 | NONE => escape con | |
61 | | _ => ()) | |
62 | else ()) | |
63 | in | |
64 | Error.bug "ImplementExceptions: can't find extraCon" | |
65 | end) | |
66 | in | |
67 | Dexp.conApp {arg = NONE, | |
68 | con = extraCon, | |
69 | targs = Vector.new0 (), | |
70 | ty = extraType} | |
71 | end | |
72 | val extendExtraType = Type.arrow (extraType, extraType) | |
73 | val extendExtraVar = Var.newNoname () | |
74 | val exnNameVar = Var.newString "exnName" | |
75 | (* sumType is the type of the datatype with all of the exn constructors. *) | |
76 | val {extraDatatypes, | |
77 | injectSum, | |
78 | projectExtra, | |
79 | projectSum, | |
80 | raisee, | |
81 | sumTycon, | |
82 | sumType | |
83 | } = | |
84 | if not (!Control.exnHistory) | |
85 | then {extraDatatypes = Vector.new0 (), | |
86 | injectSum = fn e => e, | |
87 | projectExtra = fn _ => Dexp.monoVar (dfltExtraVar, extraType), | |
88 | projectSum = fn x => Dexp.monoVar (x, Type.exn), | |
89 | raisee = (fn {exn, extend, ty, var} => | |
90 | [MonoVal {var = var, ty = ty, | |
91 | exp = Raise {exn = exn, | |
92 | extend = extend}}]), | |
93 | sumTycon = Tycon.exn, | |
94 | sumType = Type.exn} | |
95 | else | |
96 | let | |
97 | val sumTycon = Tycon.newNoname () | |
98 | val sumType = Type.con (sumTycon, Vector.new0 ()) | |
99 | local | |
100 | open Type | |
101 | in | |
102 | val exnCon = Con.newNoname () | |
103 | val exnConArgType = tuple (Vector.new2 (extraType, sumType)) | |
104 | end | |
105 | fun makeExn {exn, extra} = | |
106 | let | |
107 | open Dexp | |
108 | in | |
109 | conApp | |
110 | {con = exnCon, | |
111 | targs = Vector.new0 (), | |
112 | ty = Type.exn, | |
113 | arg = SOME (tuple {exps = Vector.new2 (extra, exn), | |
114 | ty = exnConArgType})} | |
115 | end | |
116 | fun injectSum (exn: Dexp.t): Dexp.t = | |
117 | makeExn {exn = exn, | |
118 | extra = Dexp.monoVar (dfltExtraVar, extraType)} | |
119 | fun extractExtra x = | |
120 | Dexp.select {tuple = x, offset = 0, ty = extraType} | |
121 | fun extractSum x = | |
122 | Dexp.select {tuple = x, offset = 1, ty = sumType} | |
123 | fun extract (exn: Var.t, ty, f: Dexp.t -> Dexp.t): Dexp.t = | |
124 | let | |
125 | open Dexp | |
126 | val tuple = Var.newNoname () | |
127 | in | |
128 | casee | |
129 | {test = monoVar (exn, Type.exn), | |
130 | default = NONE, | |
131 | ty = ty, | |
132 | cases = | |
133 | Cases.Con (Vector.new1 | |
134 | (Pat.T {con = exnCon, | |
135 | targs = Vector.new0 (), | |
136 | arg = SOME (tuple, exnConArgType)}, | |
137 | f (monoVar (tuple, exnConArgType))))} | |
138 | end | |
139 | fun projectExtra (x: Var.t) = | |
140 | extract (x, extraType, extractExtra) | |
141 | fun projectSum (x: Var.t) = | |
142 | extract (x, sumType, extractSum) | |
143 | fun raisee {exn: VarExp.t, | |
144 | extend: bool, | |
145 | ty: Type.t, | |
146 | var = x : Var.t}: Dec.t list = | |
147 | let | |
148 | open Dexp | |
149 | val exp = | |
150 | if not extend | |
151 | then raisee {exn = varExp (exn, Type.exn), | |
152 | extend = false, ty = ty} | |
153 | else | |
154 | extract | |
155 | (VarExp.var exn, ty, fn tup => | |
156 | raisee | |
157 | {exn = makeExn | |
158 | {exn = extractSum tup, | |
159 | extra = | |
160 | app | |
161 | {func = deref (monoVar | |
162 | (extendExtraVar, | |
163 | Type.reff extendExtraType)), | |
164 | arg = extractExtra tup, | |
165 | ty = extraType}}, | |
166 | extend = false, | |
167 | ty = ty}) | |
168 | in | |
169 | vall {exp = exp, var = x} | |
170 | end | |
171 | val extraDatatypes = | |
172 | Vector.new1 {tycon = Tycon.exn, | |
173 | tyvars = Vector.new0 (), | |
174 | cons = Vector.new1 {con = exnCon, | |
175 | arg = SOME exnConArgType}} | |
176 | in | |
177 | {extraDatatypes = extraDatatypes, | |
178 | injectSum = injectSum, | |
179 | projectExtra = projectExtra, | |
180 | projectSum = projectSum, | |
181 | raisee = raisee, | |
182 | sumTycon = sumTycon, | |
183 | sumType = sumType} | |
184 | end | |
185 | val {get = exconInfo: Con.t -> {refVar: Var.t, | |
186 | make: VarExp.t option -> Dexp.t} option, | |
187 | set = setExconInfo, destroy} = | |
188 | Property.destGetSetOnce (Con.plist, Property.initConst NONE) | |
189 | val setExconInfo = | |
190 | Trace.trace2 | |
191 | ("ImplementExceptions.setExconInfo", | |
192 | Con.layout, Layout.ignore, Unit.layout) | |
193 | setExconInfo | |
194 | val exconInfo = | |
195 | Trace.trace | |
196 | ("ImplementExceptions.exconInfo", | |
197 | Con.layout, Layout.ignore) | |
198 | exconInfo | |
199 | fun isExcon c = | |
200 | case exconInfo c of | |
201 | NONE => false | |
202 | | SOME _ => true | |
203 | val exnValCons: {con: Con.t, arg: Type.t} list ref = ref [] | |
204 | val overflow = ref NONE | |
205 | val traceLoopDec = | |
206 | Trace.trace | |
207 | ("ImplementExceptions.loopDec", Dec.layout, List.layout Dec.layout) | |
208 | fun loop (e: Exp.t): Exp.t = | |
209 | let | |
210 | val {decs, result} = Exp.dest e | |
211 | val decs = List.concatRev (List.fold (decs, [], fn (d, ds) => | |
212 | loopDec d :: ds)) | |
213 | in | |
214 | Exp.make {decs = decs, | |
215 | result = result} | |
216 | end | |
217 | and loopDec arg: Dec.t list = | |
218 | traceLoopDec | |
219 | (fn (dec: Dec.t) => | |
220 | case dec of | |
221 | MonoVal b => loopMonoVal b | |
222 | | Fun {decs, ...} => | |
223 | [Fun {tyvars = Vector.new0 (), | |
224 | decs = Vector.map (decs, fn {var, ty, lambda} => | |
225 | {var = var, | |
226 | ty = ty, | |
227 | lambda = loopLambda lambda})}] | |
228 | | Exception {con, arg} => | |
229 | let | |
230 | open Dexp | |
231 | val r = Var.newString "exnRef" | |
232 | val uniq = monoVar (r, Type.unitRef) | |
233 | fun conApp arg = | |
234 | injectSum (Dexp.conApp {con = con, | |
235 | targs = Vector.new0 (), | |
236 | ty = sumType, | |
237 | arg = SOME arg}) | |
238 | val (arg, decs, make) = | |
239 | case arg of | |
240 | NONE => | |
241 | (* If the exception is not value carrying, then go | |
242 | * ahead and make it now. | |
243 | *) | |
244 | let | |
245 | val exn = Var.newNoname () | |
246 | val _ = | |
247 | if Con.equals (con, Con.overflow) | |
248 | then overflow := SOME exn | |
249 | else () | |
250 | in (Type.unitRef, | |
251 | Dexp.vall {var = exn, exp = conApp uniq}, | |
252 | fn NONE => monoVar (exn, Type.exn) | |
253 | | _ => Error.bug "ImplementExceptions: nullary excon applied to arg") | |
254 | end | |
255 | | SOME t => | |
256 | let | |
257 | val tupleType = | |
258 | Type.tuple (Vector.new2 (Type.unitRef, t)) | |
259 | in (tupleType, | |
260 | [], | |
261 | fn SOME x => (conApp o tuple) | |
262 | {exps = Vector.new2 | |
263 | (uniq, varExp (x, t)), | |
264 | ty = tupleType} | |
265 | | _ => Error.bug "ImplmentExceptions: unary excon not applied to arg") | |
266 | end | |
267 | in setExconInfo (con, SOME {refVar = r, make = make}) | |
268 | ; List.push (exnValCons, {con = con, arg = arg}) | |
269 | ; vall {var = r, exp = reff (unit ())} @ decs | |
270 | end | |
271 | | _ => Error.bug "ImplementExceptions: saw unexpected dec") arg | |
272 | and loopMonoVal {var, ty, exp} : Dec.t list = | |
273 | let | |
274 | fun primExp e = [MonoVal {var = var, ty = ty, exp = e}] | |
275 | fun keep () = primExp exp | |
276 | fun makeExp e = Dexp.vall {var = var, exp = e} | |
277 | in | |
278 | case exp of | |
279 | Case {test, cases, default} => | |
280 | let | |
281 | fun normal () = | |
282 | primExp (Case {cases = Cases.map (cases, loop), | |
283 | default = (Option.map | |
284 | (default, fn (e, r) => | |
285 | (loop e, r))), | |
286 | test = test}) | |
287 | in | |
288 | case cases of | |
289 | Cases.Con cases => | |
290 | if Vector.isEmpty cases | |
291 | then normal () | |
292 | else | |
293 | let | |
294 | val (Pat.T {con, ...}, _) = | |
295 | Vector.first cases | |
296 | in | |
297 | if not (isExcon con) | |
298 | then normal () | |
299 | else (* convert to an exception match *) | |
300 | let | |
301 | open Dexp | |
302 | val defaultVar = Var.newString "default" | |
303 | fun callDefault () = | |
304 | app {func = (monoVar | |
305 | (defaultVar, | |
306 | Type.arrow | |
307 | (Type.unit, ty))), | |
308 | arg = unit (), | |
309 | ty = ty} | |
310 | val unit = Var.newString "unit" | |
311 | val (body, region) = | |
312 | case default of | |
313 | NONE => | |
314 | Error.bug "ImplementExceptions: no default for exception case" | |
315 | | SOME (e, r) => | |
316 | (fromExp (loop e, ty), r) | |
317 | val decs = | |
318 | vall | |
319 | {var = defaultVar, | |
320 | exp = lambda {arg = unit, | |
321 | argType = Type.unit, | |
322 | body = body, | |
323 | bodyType = ty, | |
324 | mayInline = true}} | |
325 | in | |
326 | makeExp | |
327 | (lett | |
328 | {decs = decs, | |
329 | body = | |
330 | casee | |
331 | {test = projectSum (VarExp.var test), | |
332 | ty = ty, | |
333 | default = SOME (callDefault (), | |
334 | region), | |
335 | cases = | |
336 | Cases.Con | |
337 | (Vector.map | |
338 | (cases, fn (Pat.T {con, arg, ...}, e) => | |
339 | let | |
340 | val refVar = Var.newNoname () | |
341 | val body = | |
342 | iff {test = | |
343 | equal | |
344 | (monoVar | |
345 | (refVar, Type.unitRef), | |
346 | monoVar | |
347 | (#refVar (valOf (exconInfo con)), | |
348 | Type.unitRef)), | |
349 | ty = ty, | |
350 | thenn = (fromExp | |
351 | (loop e, ty)), | |
352 | elsee = callDefault ()} | |
353 | fun make (arg, body) = | |
354 | (Pat.T | |
355 | {con = con, | |
356 | targs = Vector.new0 (), | |
357 | arg = SOME arg}, | |
358 | body) | |
359 | in case arg of | |
360 | NONE => make ((refVar, Type.unitRef), body) | |
361 | | SOME (x, t) => | |
362 | let | |
363 | val tuple = | |
364 | (Var.newNoname (), | |
365 | Type.tuple (Vector.new2 | |
366 | (Type.unitRef, t))) | |
367 | in | |
368 | make (tuple, | |
369 | detupleBind | |
370 | {tuple = monoVar tuple, | |
371 | components = | |
372 | Vector.new2 (refVar, x), | |
373 | body = body}) | |
374 | end | |
375 | end))}}) | |
376 | end | |
377 | end | |
378 | | _ => normal () | |
379 | end | |
380 | | ConApp {con, arg, ...} => | |
381 | (case exconInfo con of | |
382 | NONE => keep () | |
383 | | SOME {make, ...} => makeExp (make arg)) | |
384 | | Handle {try, catch = (catch, ty), handler} => | |
385 | primExp (Handle {try = loop try, | |
386 | catch = (catch, ty), | |
387 | handler = loop handler}) | |
388 | | Lambda l => primExp (Lambda (loopLambda l)) | |
389 | | PrimApp {args, prim, ...} => | |
390 | let | |
391 | datatype z = datatype Prim.Name.t | |
392 | fun deref (var, ty) = | |
393 | primExp | |
394 | (PrimApp {prim = Prim.deref, | |
395 | targs = Vector.new1 ty, | |
396 | args = Vector.new1 (VarExp.mono var)}) | |
397 | fun assign (var, ty) = | |
398 | primExp | |
399 | (PrimApp {prim = Prim.assign, | |
400 | targs = Vector.new1 ty, | |
401 | args = Vector.new2 (VarExp.mono var, | |
402 | Vector.first args)}) | |
403 | in | |
404 | case Prim.name prim of | |
405 | Exn_extra => | |
406 | (makeExp o projectExtra) | |
407 | (VarExp.var (Vector.first args)) | |
408 | | Exn_name => | |
409 | (primExp o App) | |
410 | {func = VarExp.mono exnNameVar, | |
411 | arg = Vector.first args} | |
412 | | Exn_setExtendExtra => | |
413 | assign (extendExtraVar, | |
414 | extendExtraType) | |
415 | | TopLevel_getHandler => | |
416 | deref (topLevelHandlerVar, | |
417 | topLevelHandlerType) | |
418 | | TopLevel_setHandler => | |
419 | assign (topLevelHandlerVar, | |
420 | topLevelHandlerType) | |
421 | | _ => primExp exp | |
422 | end | |
423 | | Raise {exn, extend} => | |
424 | raisee {exn = exn, extend = extend, ty = ty, var = var} | |
425 | | _ => keep () | |
426 | end | |
427 | and loopLambda l = | |
428 | let | |
429 | val {arg, argType, body, mayInline} = Lambda.dest l | |
430 | in | |
431 | Lambda.make {arg = arg, | |
432 | argType = argType, | |
433 | body = loop body, | |
434 | mayInline = mayInline} | |
435 | end | |
436 | val body = Dexp.fromExp (loop body, Type.unit) | |
437 | val exnValCons = Vector.fromList (!exnValCons) | |
438 | val datatypes = | |
439 | Vector.concat | |
440 | [Vector.new1 | |
441 | {tycon = sumTycon, | |
442 | tyvars = Vector.new0 (), | |
443 | cons = Vector.map (exnValCons, fn {con, arg} => | |
444 | {con = con, arg = SOME arg})}, | |
445 | extraDatatypes, | |
446 | datatypes] | |
447 | val body = | |
448 | Dexp.let1 | |
449 | {body = body, | |
450 | exp = let | |
451 | val exn = Var.newNoname () | |
452 | in | |
453 | Dexp.lambda | |
454 | {arg = exn, | |
455 | argType = Type.exn, | |
456 | body = (Dexp.casee | |
457 | {test = projectSum exn, | |
458 | cases = | |
459 | Cases.Con | |
460 | (Vector.map | |
461 | (exnValCons, fn {con, arg} => | |
462 | (Pat.T {con = con, | |
463 | targs = Vector.new0 (), | |
464 | arg = SOME (Var.newNoname (), arg)}, | |
465 | Dexp.const (Const.string (Con.originalName con))))), | |
466 | default = NONE, | |
467 | ty = Type.string}), | |
468 | bodyType = Type.string, | |
469 | mayInline = true} | |
470 | end, | |
471 | var = exnNameVar} | |
472 | val body = | |
473 | Dexp.let1 | |
474 | {body = body, | |
475 | exp = (Dexp.reff | |
476 | (Dexp.lambda | |
477 | {arg = Var.newNoname (), | |
478 | argType = extraType, | |
479 | body = (Dexp.sequence o Vector.new2) | |
480 | (Dexp.bug "extendExtra unimplemented", | |
481 | Dexp.monoVar (dfltExtraVar, extraType)), | |
482 | bodyType = extraType, | |
483 | mayInline = true})), | |
484 | var = extendExtraVar} | |
485 | val body = | |
486 | Dexp.let1 | |
487 | {body = body, | |
488 | exp = dfltExtraExp, | |
489 | var = dfltExtraVar} | |
490 | val body = | |
491 | let | |
492 | val x = (Var.newNoname (), Type.exn) | |
493 | in | |
494 | Dexp.handlee | |
495 | {try = body, | |
496 | ty = Type.unit, | |
497 | catch = x, | |
498 | handler = Dexp.app {func = (Dexp.deref | |
499 | (Dexp.monoVar | |
500 | (topLevelHandlerVar, | |
501 | Type.reff topLevelHandlerType))), | |
502 | arg = Dexp.monoVar x, | |
503 | ty = Type.unit}} | |
504 | end | |
505 | val body = | |
506 | Dexp.let1 | |
507 | {var = topLevelHandlerVar, | |
508 | exp = Dexp.reff (Dexp.lambda | |
509 | {arg = Var.newNoname (), | |
510 | argType = Type.exn, | |
511 | body = Dexp.bug "toplevel handler not installed", | |
512 | bodyType = Type.unit, | |
513 | mayInline = true}), | |
514 | body = body} | |
515 | val body = | |
516 | Dexp.handlee | |
517 | {try = body, | |
518 | ty = Type.unit, | |
519 | catch = (Var.newNoname (), Type.exn), | |
520 | handler = Dexp.bug "toplevel handler not installed"} | |
521 | val body = Dexp.toExp body | |
522 | val program = | |
523 | Program.T {datatypes = datatypes, | |
524 | body = body, | |
525 | overflow = !overflow} | |
526 | val _ = destroy () | |
527 | in | |
528 | program | |
529 | end | |
530 | ||
531 | end |