Import Debian changes 20180207-1
[hcoop/debian/mlton.git] / mlton / xml / implement-exceptions.fun
CommitLineData
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
9functor ImplementExceptions (S: XML_TRANSFORM_STRUCTS): XML_TRANSFORM =
10struct
11
12open S
13datatype z = datatype Dec.t
14datatype z = datatype PrimExp.t
15structure Dexp = DirectExp
16
17fun 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
531end