src/Pure/ML/exn_debugger.ML
changeset 62498 5dfcc9697f29
child 62516 5732f1c31566
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/Pure/ML/exn_debugger.ML	Wed Mar 02 19:43:31 2016 +0100
@@ -0,0 +1,63 @@
+(*  Title:      Pure/ML/exn_debugger.ML
+    Author:     Makarius
+
+Detailed exception trace via ML debugger.
+*)
+
+signature EXN_DEBUGGER =
+sig
+  val capture_exception_trace: (unit -> 'a) -> (string * ML_Debugger.location) list * 'a Exn.result
+end;
+
+structure Exn_Debugger: EXN_DEBUGGER =
+struct
+
+(* thread data *)
+
+local
+  val tag = Universal.tag () : ((string * ML_Debugger.location) * exn) list option Universal.tag;
+in
+
+fun start_trace () = Thread.setLocal (tag, SOME []);
+
+fun update_trace entry exn =
+  (case Thread.getLocal tag of
+    SOME (SOME trace) => Thread.setLocal (tag, SOME ((entry, exn) :: trace))
+  | _ => ());
+
+fun stop_trace () =
+  let
+    val trace = (case Thread.getLocal tag of SOME (SOME trace) => trace | _ => []);
+    val _ = Thread.setLocal (tag, NONE);
+  in trace end;
+
+val _ = ML_Debugger.on_exit_exception (SOME update_trace);
+
+end;
+
+
+(* capture exception trace *)
+
+local
+  fun eq_exn exns =
+    op = (apply2 General.exnName exns) andalso op = (apply2 Exn_Output.position exns);
+in
+
+fun capture_exception_trace e =
+  uninterruptible (fn restore_attributes => fn () =>
+    let
+      val _ = start_trace ();
+      val result = Exn.interruptible_capture (restore_attributes e) ();
+      val trace = stop_trace ();
+      val trace' =
+        (case result of
+          Exn.Res _ => []
+        | Exn.Exn exn =>
+            trace
+            |> map_filter (fn (entry, e) => if eq_exn (exn, e) then SOME entry else NONE)
+            |> rev);
+    in (trace', result) end) ();
+
+end;
+
+end;