123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118(*************************************************************************)(* Copyright 2015-2019 MINES ParisTech -- Dual License LGPL 2.1+ / GPL3+ *)(* Copyright 2019-2024 Inria -- Dual License LGPL 2.1+ / GPL3+ *)(* Copyright 2024-2025 Emilio J. Gallego Arias -- LGPL 2.1+ / GPL3+ *)(* Copyright 2025 CNRS -- LGPL 2.1+ / GPL3+ *)(* Written by: Emilio J. Gallego Arias & coq-lsp contributors *)(*************************************************************************)(* Rocq Language Server Protocol: Rocq Effect Handling *)(*************************************************************************)moduleError=structtype'lt=|Userof'lMessage.Payload.t|Anomalyof'lMessage.Payload.tletmap~f=function|Usere->User(fe)|Anomalye->Anomaly(fe)endmoduleR=structtype('a,'l)t=|Completedof('a,'lError.t)result|Interrupted(* signal sent, eval didn't complete *)leterrormsg=letpayload=Message.Payload.makemsginCompleted(Error(Error.Userpayload))letmap~f=function|Completed(Result.Okr)->Completed(Result.Ok(fr))|Completed(Result.Errorr)->Completed(Result.Errorr)|Interrupted->Interruptedletmap_error~f=function|Completed(Errore)->Completed(Error(Error.map~fe))|Completed(Okr)->Completed(Okr)|Interrupted->Interrupted(* Similar to Message.map, but missing the priority field, this is due to Coq
having to sources of feedback, an async one, and the exn sync one.
Ultimately both carry the same [payload].
See coq/coq#5479 for some information about this, among some other relevant
issues. AFAICT, the STM tried to use a full async error reporting however
due to problems the more "legacy" exn is the actuall error mechanism in
use *)letmap_loc~f=letf=Message.Payload.map~finmap_error~fend(* let qf_of_coq qf = let range = Quickfix.loc qf in let newText = Quickfix.pp
qf |> Pp.string_of_ppcmds in { Lang.Qf.range; newText } *)(* Eval and reify exceptions *)leteval_exn~token~fx=matchLimits.limit~token~fxwith|Okres->R.Completed(Okres)|Error_->Vernacstate.Interp.invalidate_cache();R.Interrupted|exceptionexn->lete,info=Exninfo.captureexninletrange=Loc.(get_locinfo)inletmsg=CErrors.iprint(e,info)inletquickFix=Nonein(* match Quickfix.from_exception exn with | Ok [] | Error _ -> None | Ok qf
-> Some (List.map qf_of_coq qf) in *)letpayload=Message.Payload.make?range?quickFixmsginVernacstate.Interp.invalidate_cache();ifCErrors.is_anomalyethenR.Completed(Error(Anomalypayload))elseR.Completed(Error(Userpayload))let_bind_exn~fx=matchxwith|R.Interrupted->R.Interrupted|R.Completed(Errore)->R.Completed(Errore)|R.Completed(Okr)->frletfb_queue:Loc.tMessage.tlistref=ref[]moduleE=structtype('a,'l)t={r:('a,'l)R.t;feedback:'lMessage.tlist}leteval~token~fx=letr=eval_exn~token~fxinletfeedback=List.rev!fb_queueinlet()=fb_queue:=[]in{r;feedback}letmap~f{r;feedback}={r=R.map~fr;feedback}letmap_loc~f{r;feedback}={r=R.map_loc~fr;feedback=List.map(Message.map~f)feedback}letbind~f{r;feedback}=matchrwith|R.Interrupted->{r=R.Interrupted;feedback}|R.Completed(Errore)->{r=R.Completed(Errore);feedback}|R.Completed(Okr)->let{r;feedback=fb2}=frin{r;feedback=feedback@fb2}letokv={r=Completed(Okv);feedback=[]}leterrorerr={r=R.errorerr;feedback=[]}moduleO=structlet(let+)xf=map~fxlet(let*)xf=bind~fxendend(* Eval with reified exceptions and feedback *)leteval~token~fx=E.eval~token~fx