123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155open!Importtypet=exn[@@deriving_inlinesexp_of]letsexp_of_t=(sexp_of_exn:t->Ppx_sexp_conv_lib.Sexp.t)[@@@end]letexit=Caml.exitexceptionFinallyoft*t[@@deriving_inlinesexp]let()=Ppx_sexp_conv_lib.Conv.Exn_converter.add[%extension_constructorFinally](function|Finally(v0,v1)->letv0=sexp_of_tv0andv1=sexp_of_tv1inPpx_sexp_conv_lib.Sexp.List[Ppx_sexp_conv_lib.Sexp.Atom"exn.ml.Finally";v0;v1]|_->assertfalse);;[@@@end]exceptionReraisedofstring*t[@@deriving_inlinesexp]let()=Ppx_sexp_conv_lib.Conv.Exn_converter.add[%extension_constructorReraised](function|Reraised(v0,v1)->letv0=sexp_of_stringv0andv1=sexp_of_tv1inPpx_sexp_conv_lib.Sexp.List[Ppx_sexp_conv_lib.Sexp.Atom"exn.ml.Reraised";v0;v1]|_->assertfalse);;[@@@end]exceptionSexpofSexp.t(* We install a custom exn-converter rather than use:
{[
exception Sexp of Sexp.t [@@deriving_inline sexp]
(* ... *)
[@@@end]
]}
to eliminate the extra wrapping of [(Sexp ...)]. *)let()=Sexplib.Conv.Exn_converter.add[%extension_constructorSexp](function|Sexpt->t|_->(* Reaching this branch indicates a bug in sexplib. *)assertfalse);;letcreate_ssexp=Sexpsexpletreraiseexcstr=raise(Reraised(str,exc))letreraisefexcformat=Printf.ksprintf(funstr()->reraiseexcstr)formatletto_stringexc=Sexp.to_string_hum~indent:2(sexp_of_exnexc)letto_string_machexc=Sexp.to_string_mach(sexp_of_exnexc)letsexp_of_t=sexp_of_exnletprotectx~fx~(finally:_->unit)=matchfxwith|res->finallyx;res|exceptionexn->raise(matchfinallyxwith|()->exn|exceptionfinal_exn->Finally(exn,final_exn));;letprotect~f~finally=protectx~f()~finallyletdoes_raise(typea)(f:unit->a)=tryignore(f():a);falsewith|_->true;;includePretty_printer.Register_pp(structtypet=exnletppppft=matchsexp_of_exn_opttwith|Somesexp->Sexp.pp_humppfsexp|None->Caml.Format.pp_print_stringppf(Caml.Printexc.to_stringt);;letmodule_name="Base.Exn"end)letprint_with_backtraceexcraw_backtrace=Caml.Format.eprintf"@[<2>Uncaught exception:@\n@\n@[%a@]@]@\n@."ppexc;ifCaml.Printexc.backtrace_status()thenCaml.Printexc.print_raw_backtraceCaml.stderrraw_backtrace;Caml.flushCaml.stderr;;letset_uncaught_exception_handler()=Caml.Printexc.set_uncaught_exception_handlerprint_with_backtrace;;lethandle_uncaught_aux~do_at_exit~exitf=tryf()with|exc->letraw_backtrace=Caml.Printexc.get_raw_backtrace()in(* One reason to run [do_at_exit] handlers before printing out the error message is
that it helps curses applications bring the terminal in a good state, otherwise the
error message might get corrupted. Also, the OCaml top-level uncaught exception
handler does the same. *)ifdo_at_exitthen(tryCaml.do_at_exit()with|_->());(tryprint_with_backtraceexcraw_backtracewith|_->(tryCaml.Printf.eprintf"Exn.handle_uncaught could not print; exiting anyway\n%!"with|_->()));exit1;;lethandle_uncaught_and_exitf=handle_uncaught_auxf~exit~do_at_exit:truelethandle_uncaught~exit:must_exitf=handle_uncaught_auxf~exit:(ifmust_exitthenexitelseignore)~do_at_exit:must_exit;;letreraise_uncaughtstrfunc=tryfunc()with|exn->raise(Reraised(str,exn));;externalclear_backtrace:unit->unit="Base_clear_caml_backtrace_pos"[@@noalloc]letraise_without_backtracee=(* We clear the backtrace to reduce confusion, so that people don't think whatever
is stored corresponds to this raise. *)clear_backtrace();Caml.raise_notracee;;letinitialize_module()=set_uncaught_exception_handler()modulePrivate=structletclear_backtrace=clear_backtraceend