123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132letshow_backend_exceptions=reftruetypewith_bt=exn*Printexc.raw_backtracetypeerr=..typecontext={steps:stringlist;}exceptionIooferr*contextexceptionMultipleof(exn*Printexc.raw_backtrace)list(* Note: the last exception in list is the first one reported *)typeerr+=Multiple_ioof(err*context*Printexc.raw_backtrace)listexceptionCancelledofexnletcreateerr=Io(err,{steps=[]})letempty_backtrace=Printexc.get_callstack0letadd_contextexfmt=fmt|>Fmt.kstr@@funmsg->matchexwith|Io(code,t)->Io(code,{steps=msg::t.steps})|ex->exletreraise_with_contextexbtfmt=fmt|>Fmt.kstr@@funmsg->matchexwith|Io(code,t)->letcontext={steps=msg::t.steps}inPrintexc.raise_with_backtrace(Io(code,context))bt|_->Printexc.raise_with_backtraceexbtleterr_printers:(Format.formatter->err->bool)listref=ref[]letregister_ppfn=err_printers:=fn::!err_printersletbreakf_=Format.pp_print_custom_breakf~fits:(",",1,"")~breaks:(",",2,"")letpp_errfx=letrecaux=function|[]->Fmt.stringf"?"|pp::pps->ifnot(ppfx)thenauxppsinaux!err_printersletpp_with_contextf(code,context)=Fmt.pff"%a%a"pp_errcodeFmt.(list~sep:nop(break++string))(List.revcontext.steps)letpp_with_btf(code,context,bt)=matchString.trim(Printexc.raw_backtrace_to_stringbt)with|""->Fmt.pff"- @[<hov>%a@]"pp_with_context(code,context)|bt->Fmt.pff"- @[<v>%a@,%a@]"pp_with_context(code,context)Fmt.linesbtletppf=function|Io(code,t)->Fmt.pff"Eio.Io %a%a"pp_errcodeFmt.(list~sep:nop(break++string))(List.revt.steps)|ex->Fmt.stringf(Printexc.to_stringex)letpp_multiplefexns=letpp_with_btf(ex,bt)=matchString.trim(Printexc.raw_backtrace_to_stringbt)with|""->Fmt.pff"- @[<v>%a@]"ppex|bt->Fmt.pff"- @[<v>%a@,%a@]"ppexFmt.linesbtinFmt.pff"@[<v>Multiple exceptions:@,%a@]"(Fmt.(list~sep:cut)pp_with_bt)(List.revexns)let()=Printexc.register_printer@@function|Io_asex->Some(Fmt.str"@[<v>%a@]"ppex)|Multipleexns->Some(Fmt.str"%a"pp_multipleexns)|Cancelledex->Some("Cancelled: "^Printexc.to_stringex)|_->Noneletcombinee1e2=iffste1==fste2thene1elsematche1,e2with|(Cancelled_,_),e|e,(Cancelled_,_)->e(* Don't need to report a cancelled exception if we have something better *)|(Io(c1,t1),bt1),(Io(c2,t2),bt2)->create(Multiple_io[(c1,t1,bt1);(c2,t2,bt2)]),empty_backtrace|(Multipleexs,bt1),e2->Multiple(e2::exs),bt1|e1,e2->Multiple[e2;e1],empty_backtracemoduleBackend=structtypet=..letshow=reftrueletprinters:(Format.formatter->t->bool)listref=ref[]letregister_ppfn=printers:=fn::!printersletppfx=if!showthen(letrecaux=function|[]->Fmt.stringf"?"|pp::pps->ifnot(ppfx)thenauxppsinaux!printers)elseFmt.stringf"_"endtypeerr+=XofBackend.tlet()=register_pp(funf->function|Multiple_ioerrs->Fmt.pff"Multiple_io@\n%a"(Fmt.(list~sep:cut)pp_with_bt)errs;true|Xex->Backend.ppfex;true|_->false)