package dolmen_loop
Source file report.ml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302(* This file is free software, part of dolmen. See file "LICENSE" for more information *) (* Types *) (* ************************************************************************* *) type _ kind = | Error : { id : int; } -> [> `Error ] kind | Warning : { id : int; } -> [> `Warning ] kind type ('kind, 'param) aux = { (* report identification *) kind : 'kind kind; code : Code.t; (* cli interaction *) mnemonic : string; (* short message printing *) message : Format.formatter -> 'param -> unit; mutable hints : ('param -> (Format.formatter -> unit) option) list; (* long documentation *) name : string; doc : Format.formatter -> unit; } type any = Any : (_, _) aux -> any type 'a error = ([ `Error ], 'a) aux type 'a warning = ([ `Warning ], 'a) aux type any_error = Any_err : _ error -> any_error type any_warning = Any_warn : _ warning -> any_warning (* Common functions *) (* ************************************************************************* *) let code report = report.code let name report = report.name let mnemonic report = report.mnemonic let print_doc fmt report = Format.fprintf fmt "%t" report.doc let print fmt (report, param) = report.message fmt param let print_hints fmt (report, param) = List.iter (fun hint -> match hint param with | None -> () | Some pp -> Format.fprintf fmt "@\n@[<hov 2>Hint: %t@]" pp ) report.hints (* Creation and fetching *) (* ************************************************************************* *) let locked = ref false let error_count = ref 0 let warning_count = ref 0 let mnemonics_table = Hashtbl.create 113 let no_doc fmt = Format.fprintf fmt "No documentation yet" let mk_aux ~kind ~code ~mnemonic ~message ?(hints=[]) ~name ?(doc=no_doc) () = assert (not !locked && not (Hashtbl.mem mnemonics_table mnemonic)); let res = { code; kind; mnemonic; message; hints; name; doc; } in Hashtbl.add mnemonics_table mnemonic (Any res); res let mk_error ?(code=Code.bug) ~mnemonic ~message ?hints ~name ?doc () : _ error = let id = incr error_count; !error_count in mk_aux ~kind:(Error { id; }) ~code ~mnemonic ~message ?hints ~name ?doc () let mk_warning ?(code=Code.bug) ~mnemonic ~message ?hints ~name ?doc () : _ warning = let id = !warning_count in incr warning_count; mk_aux ~kind:(Warning { id; }) ~code ~mnemonic ~message ?hints ~name ?doc () let add_hint t hint = let new_hint _ = Some (hint) in t.hints <- new_hint :: t.hints (* Warnings interface *) (* ************************************************************************* *) module Warning = struct type 'a t = 'a warning let mk = mk_warning let code = code let name = name let mnemonic = mnemonic let print = print let print_doc = print_doc let print_hints = print_hints module Status = struct type t = | Disabled | Enabled | Fatal let print fmt = function | Disabled -> Format.fprintf fmt "disabled" | Enabled -> Format.fprintf fmt "enabled" | Fatal -> Format.fprintf fmt "fatal" let to_string t = Format.asprintf "%a" print t let merge s s' = match s, s' with | Disabled, Disabled -> Disabled | _, Fatal | Fatal, _ -> Fatal | _, _ -> Enabled end end (* Error interface *) (* ************************************************************************* *) module Error = struct type 'a t = 'a error let mk = mk_error let code = code let name = name let mnemonic = mnemonic let print = print let print_doc = print_doc let print_hints = print_hints let user_interrupt : _ t = mk ~code:Code.limit ~mnemonic:"user-interrupt" ~message:(fun fmt () -> Format.fprintf fmt "User Interrupt") ~name:"User Interrupt" () let timeout : _ t = mk ~code:Code.limit ~mnemonic:"timeout" ~message:(fun fmt () -> Format.fprintf fmt "Time limit reached") ~name:"Timeout" () let spaceout : _ t = mk ~code:Code.limit ~mnemonic:"spaceout" ~message:(fun fmt () -> Format.fprintf fmt "Memory limit reached") ~name:"Out of space" () let internal_error = mk ~code:Code.bug ~mnemonic:"internal-error" ~message:(fun fmt t -> Format.fprintf fmt "@[<v>%t@ Please report upstream, ^^@]" t) ~name:"Internal Error" () let uncaught_exn = mk ~code:Code.bug ~mnemonic:"uncaught-exn" ~message:(fun fmt (exn, bt) -> Format.fprintf fmt "Uncaught exception:@\n%s%a%s" (Printexc.to_string exn) (if Printexc.backtrace_status () then Format.pp_print_newline else (fun _ _ -> ())) () (if Printexc.backtrace_status () then Printexc.raw_backtrace_to_string bt else "")) ~name:"Uncaught exception" () end (* Reports *) (* ************************************************************************* *) module T = struct type all = [ `All ] type err = [ `Error of any_error ] type warn = [ `Warning of any_warning ] type t = [ all | err | warn ] let name = function | `All -> "All warnings" | `Error Any_err e -> name e | `Warning Any_warn w -> name w let mnemonic = function | `All -> "all" | `Error Any_err e -> mnemonic e | `Warning Any_warn w -> mnemonic w let kind = function | `All -> "group" | `Error _ -> "error" | `Warning _ -> "warning" let category = function | `All -> "General" | `Error Any_err e -> Code.category (code e) | `Warning Any_warn w -> Code.category (code w) let doc = function | `Error Any_err e -> e.doc | `Warning Any_warn w -> w.doc | `All -> Format.dprintf "%a" Format.pp_print_text "The group of all warnings. Its main use is when specifying \ a set of warnings to enable/disable/make fatal when using the \ '-w' option of Dolmen." let find_mnemonic = function | "all" -> Some `All | mnemonic -> begin match Hashtbl.find_opt mnemonics_table mnemonic with | Some (Any ({ kind = Warning _; _ } as w)) -> Some (`Warning (Any_warn w)) | Some (Any ({ kind = Error _; _ } as e)) -> Some (`Error (Any_err e)) | None -> None end let list () = Hashtbl.fold (fun _ any acc -> let elt = match any with | Any ({ kind = Warning _; _ } as w) -> `Warning (Any_warn w) | Any ({ kind = Error _; _ } as e) -> `Error (Any_err e) in elt :: acc ) mnemonics_table [`All] end (* Configuration *) (* ************************************************************************* *) module Conf = struct type t = { warnings : Warning.Status.t array; } let mk ~default = locked := true; { warnings = Array.make !warning_count default; } let _copy t = { warnings = Array.copy t.warnings; } let _get conf i = conf.warnings.(i) let _set_inplace conf i status = conf.warnings.(i) <- status let _update_inplace conf i status = _set_inplace conf i (Warning.Status.merge status (_get conf i)) let status conf (warning : _ warning) = let (Warning { id; }) = warning.kind in _get conf id let update f param conf = function | `All -> for i = 0 to Array.length conf.warnings - 1 do f conf i param done; conf | `Warning (Any_warn { kind = Warning { id; }; _}) -> let conf = _copy conf in f conf id param; conf let fatal conf w = update _update_inplace Fatal conf w let enable conf w = update _update_inplace Enabled conf w let disable conf w = update _set_inplace Disabled conf w let set_enabled conf w = update _set_inplace Enabled conf w end