[MLton-commit] r4375

Matthew Fluet MLton@mlton.org
Sat, 4 Mar 2006 10:39:11 -0800


Report exception history for debugging
----------------------------------------------------------------------

A   mlton/branches/on-20050822-x86_64-branch/basis-library.refactor/test/exn.sml

----------------------------------------------------------------------

Added: mlton/branches/on-20050822-x86_64-branch/basis-library.refactor/test/exn.sml
===================================================================
--- mlton/branches/on-20050822-x86_64-branch/basis-library.refactor/test/exn.sml	2006-03-04 18:30:37 UTC (rev 4374)
+++ mlton/branches/on-20050822-x86_64-branch/basis-library.refactor/test/exn.sml	2006-03-04 18:39:11 UTC (rev 4375)
@@ -0,0 +1,160 @@
+structure COld =
+   struct
+      open Int
+         
+      fun makeLength (sub, term) p =
+         let
+            fun loop i =
+               if term (sub (p, i))
+                  then i
+               else loop (i +? 1)
+         in loop 0
+         end
+
+      fun toArrayOfLength (s: 'a,
+                           sub: 'a * int -> 'b,
+                           n: int) : 'b array =
+         let
+            val a = Primitive.Array.arrayUnsafe n
+            fun loop i =
+               if i >= n
+                  then ()
+               else (Array.update (a, i, sub (s, i))
+                     ; loop (i + 1))
+         in loop 0;
+            a
+         end
+
+      structure CS =
+         struct
+            type t = Primitive.MLton.Pointer.t
+
+            fun sub (cs, i) =
+               Primitive.Char8.fromWord8Unsafe (Primitive.MLton.Pointer.getWord8 (cs, i))
+
+            fun update (cs, i, c) =
+               Primitive.MLton.Pointer.setWord8 (cs, i, Primitive.Char8.toWord8Unsafe c)
+
+            fun toCharArrayOfLength (cs, n) = toArrayOfLength (cs, sub, n)
+
+            fun toStringOfLength cs =
+               String.fromArray (CharArray.fromPoly (toCharArrayOfLength cs))
+
+            val length = makeLength (sub, fn #"\000" => true | _ => false)
+
+            fun toString cs = toStringOfLength (cs, length cs)
+         end
+      
+   end
+
+structure MLtonCallStack =
+   struct
+      open Primitive.MLton.CallStack
+
+      val gcState = Primitive.MLton.GCState.gcState
+      structure Pointer = Primitive.MLton.Pointer
+         
+      val current: unit -> t =
+         fn () =>
+         if not keep
+            then T (Array.array (0, 0w0))
+         else
+            let
+               val a = Array.array (Word32.toInt (numStackFrames gcState), 0w0)
+               val () = callStack (gcState, a)
+            in
+               T a
+            end
+
+      val toStrings: t -> string list =
+         fn T a =>
+         if not keep
+            then []
+         else
+            let
+               val skip = Array.length a - 2
+            in
+               Array.foldri
+               (fn (i, frameIndex, ac) =>
+                if i >= skip
+                   then ac
+                else
+                   let
+                      val p = frameIndexSourceSeq (gcState, frameIndex)
+                      val max = Pointer.getInt32 (p, 0)
+                      fun loop (j, ac) =
+                         if j > max
+                            then ac
+                         else loop (j + 1,
+                                    COld.CS.toString (sourceName
+                                                      (gcState, Pointer.getWord32 (p, j)))
+                                    :: ac)
+                   in
+                      loop (1, ac)
+                   end)
+               [] a
+            end
+   end
+
+structure MLtonExn =
+   struct
+      open Primitive.MLton.Exn
+
+      type t = exn
+         
+      val addExnMessager = General.addExnMessager
+
+      val history: t -> string list =
+         if keepHistory then
+            (setInitExtra (NONE: extra)
+             ; setExtendExtra (fn e =>
+                               case e of
+                                  NONE => SOME (MLtonCallStack.current ())
+                                | SOME _ => e)
+             ; (fn e =>
+                case extra e of
+                   NONE => []
+                 | SOME cs =>
+                      let
+                         (* Gets rid of the anonymous function passed to
+                          * setExtendExtra above.
+                          *)
+                         fun loop xs =
+                            case xs of
+                               [] => []
+                             | x :: xs =>
+                                  if String.isPrefix "MLtonExn.fn " x then
+                                     xs
+                                  else
+                                     loop xs
+                      in
+                         loop (MLtonCallStack.toStrings cs)
+                      end))
+         else fn _ => []
+
+      local
+         val message = PrimitiveFFI.Stdio.print
+      in
+         fun 'a topLevelHandler (exn: exn): 'a =
+            (message (concat ["unhandled exception: ", exnMessage exn, "\n"])
+             ; (case history exn of
+                   [] => ()
+                 | l =>
+                      (message "with history:\n"
+                       ; (List.app (fn s => message (concat ["\t", s, "\n"]))
+                          l)))
+             ; Primitive.MLton.bug (Primitive.NullString8.fromString 
+                                    "unhandled exception in Basis Library\000")
+             ; raise Fail "bug")
+            handle _ => (message "Toplevel handler raised exception.\n"
+                         ; Primitive.MLton.bug (Primitive.NullString8.fromString 
+                                                "unhandled exception in Basis Library\000")
+                         (* The following raise is unreachable, but must be there
+                          * so that the expression is of type 'a.
+                          *)
+                         ; raise Fail "bug")
+      end
+   end
+
+val _ = 
+   Primitive.TopLevel.setHandler MLtonExn.topLevelHandler