Add copyright notices and new function String.chomp
[ocaml.git] / camlp4 / Camlp4 / ErrorHandler.ml
blob231efed90402425445e550757fef6626181c8b21
1 (****************************************************************************)
2 (* *)
3 (* Objective Caml *)
4 (* *)
5 (* INRIA Rocquencourt *)
6 (* *)
7 (* Copyright 2006 Institut National de Recherche en Informatique et *)
8 (* en Automatique. All rights reserved. This file is distributed under *)
9 (* the terms of the GNU Library General Public License, with the special *)
10 (* exception on linking described in LICENSE at the top of the Objective *)
11 (* Caml source tree. *)
12 (* *)
13 (****************************************************************************)
15 (* Authors:
16 * - Daniel de Rauglaudre: initial version
17 * - Nicolas Pouillard: refactoring
19 (* camlp4r *)
21 open Format;
23 module ObjTools = struct
25 value desc obj =
26 if Obj.is_block obj then
27 "tag = " ^ string_of_int (Obj.tag obj)
28 else "int_val = " ^ string_of_int (Obj.obj obj);
30 (*Imported from the extlib*)
31 value rec to_string r =
32 if Obj.is_int r then
33 let i = (Obj.magic r : int)
34 in string_of_int i ^ " | CstTag" ^ string_of_int (i + 1)
35 else (* Block. *)
36 let rec get_fields acc =
37 fun
38 [ 0 -> acc
39 | n -> let n = n-1 in get_fields [Obj.field r n :: acc] n ]
41 let rec is_list r =
42 if Obj.is_int r then
43 r = Obj.repr 0 (* [] *)
44 else
45 let s = Obj.size r and t = Obj.tag r in
46 t = 0 && s = 2 && is_list (Obj.field r 1) (* h :: t *)
48 let rec get_list r =
49 if Obj.is_int r then []
50 else let h = Obj.field r 0 and t = get_list (Obj.field r 1) in [h :: t]
52 let opaque name =
53 (* XXX In future, print the address of value 'r'. Not possible in
54 * pure OCaml at the moment.
56 "<" ^ name ^ ">"
58 let s = Obj.size r and t = Obj.tag r in
59 (* From the tag, determine the type of block. *)
60 match t with
61 [ _ when is_list r ->
62 let fields = get_list r in
63 "[" ^ String.concat "; " (List.map to_string fields) ^ "]"
64 | 0 ->
65 let fields = get_fields [] s in
66 "(" ^ String.concat ", " (List.map to_string fields) ^ ")"
67 | x when x = Obj.lazy_tag ->
68 (* Note that [lazy_tag .. forward_tag] are < no_scan_tag. Not
69 * clear if very large constructed values could have the same
70 * tag. XXX *)
71 opaque "lazy"
72 | x when x = Obj.closure_tag ->
73 opaque "closure"
74 | x when x = Obj.object_tag ->
75 let fields = get_fields [] s in
76 let (_class, id, slots) =
77 match fields with
78 [ [h; h'::t] -> (h, h', t)
79 | _ -> assert False ]
81 (* No information on decoding the class (first field). So just print
82 * out the ID and the slots. *)
83 "Object #" ^ to_string id ^ " (" ^ String.concat ", " (List.map to_string slots) ^ ")"
84 | x when x = Obj.infix_tag ->
85 opaque "infix"
86 | x when x = Obj.forward_tag ->
87 opaque "forward"
88 | x when x < Obj.no_scan_tag ->
89 let fields = get_fields [] s in
90 "Tag" ^ string_of_int t ^
91 " (" ^ String.concat ", " (List.map to_string fields) ^ ")"
92 | x when x = Obj.string_tag ->
93 "\"" ^ String.escaped (Obj.magic r : string) ^ "\""
94 | x when x = Obj.double_tag ->
95 string_of_float (Obj.magic r : float)
96 | x when x = Obj.abstract_tag ->
97 opaque "abstract"
98 | x when x = Obj.custom_tag ->
99 opaque "custom"
100 | x when x = Obj.final_tag ->
101 opaque "final"
102 | _ ->
103 failwith ("ObjTools.to_string: unknown tag (" ^ string_of_int t ^ ")") ];
105 value print ppf x = fprintf ppf "%s" (to_string x);
106 value print_desc ppf x = fprintf ppf "%s" (desc x);
108 end;
110 value default_handler ppf x = do {
111 let x = Obj.repr x;
112 fprintf ppf "Camlp4: Uncaught exception: %s"
113 (Obj.obj (Obj.field (Obj.field x 0) 0) : string);
114 if Obj.size x > 1 then do {
115 pp_print_string ppf " (";
116 for i = 1 to Obj.size x - 1 do
117 if i > 1 then pp_print_string ppf ", " else ();
118 ObjTools.print ppf (Obj.field x i);
119 done;
120 pp_print_char ppf ')'
122 else ();
123 fprintf ppf "@."
126 value handler = ref (fun ppf default_handler exn -> default_handler ppf exn);
128 value register f =
129 let current_handler = handler.val in
130 handler.val :=
131 fun ppf default_handler exn ->
132 try f ppf exn with exn -> current_handler ppf default_handler exn;
134 module Register (Error : Sig.Error) = struct
135 let current_handler = handler.val in
136 handler.val :=
137 fun ppf default_handler ->
138 fun [ Error.E x -> Error.print ppf x
139 | x -> current_handler ppf default_handler x ];
140 end;
143 value gen_print ppf default_handler =
145 [ Out_of_memory -> fprintf ppf "Out of memory"
146 | Assert_failure (file, line, char) ->
147 fprintf ppf "Assertion failed, file %S, line %d, char %d"
148 file line char
149 | Match_failure (file, line, char) ->
150 fprintf ppf "Pattern matching failed, file %S, line %d, char %d"
151 file line char
152 | Failure str -> fprintf ppf "Failure: %S" str
153 | Invalid_argument str -> fprintf ppf "Invalid argument: %S" str
154 | Sys_error str -> fprintf ppf "I/O error: %S" str
155 | Stream.Failure -> fprintf ppf "Parse failure"
156 | Stream.Error str -> fprintf ppf "Parse error: %s" str
157 | x -> handler.val ppf default_handler x ];
159 value print ppf = gen_print ppf default_handler;
161 value try_print ppf = gen_print ppf (fun _ -> raise);
163 value to_string exn =
164 let buf = Buffer.create 128 in
165 let () = bprintf buf "%a" print exn in
166 Buffer.contents buf;
168 value try_to_string exn =
169 let buf = Buffer.create 128 in
170 let () = bprintf buf "%a" try_print exn in
171 Buffer.contents buf;