package coq-lsp

  1. Overview
  2. Docs
Language Server Protocol native server for Coq

Install

dune-project
 Dependency

Authors

Maintainers

Sources

coq-lsp-0.2.4.9.0.tbz
sha256=b6bf58331589b0bc750c01cc96a607322cf20260e61bd74f64998e04a9b909d3
sha512=b74f88117a180b089f99dc2d0cd867bdeb7aef071fa487334cdd2961ac61b9ba592e7f58c509dd6920ca2708dcc64992944009d4dce504bb5d0e28bb7d963c07

doc/src/coq-lsp.coq/protect.ml.html

Source file protect.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
(*************************************************************************)
(* 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                   *)
(*************************************************************************)

module Error = struct
  type 'l t =
    | User of 'l Message.Payload.t
    | Anomaly of 'l Message.Payload.t

  let map ~f = function
    | User e -> User (f e)
    | Anomaly e -> Anomaly (f e)
end

module R = struct
  type ('a, 'l) t =
    | Completed of ('a, 'l Error.t) result
    | Interrupted (* signal sent, eval didn't complete *)

  let error msg =
    let payload = Message.Payload.make msg in
    Completed (Error (Error.User payload))

  let map ~f = function
    | Completed (Result.Ok r) -> Completed (Result.Ok (f r))
    | Completed (Result.Error r) -> Completed (Result.Error r)
    | Interrupted -> Interrupted

  let map_error ~f = function
    | Completed (Error e) -> Completed (Error (Error.map ~f e))
    | Completed (Ok r) -> Completed (Ok r)
    | 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 *)
  let map_loc ~f =
    let f = Message.Payload.map ~f in
    map_error ~f
end

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 *)
let eval_exn ~token ~f x =
  match Limits.limit ~token ~f x with
  | Ok res -> R.Completed (Ok res)
  | Error _ ->
    Vernacstate.Interp.invalidate_cache ();
    R.Interrupted
  | exception exn ->
    let e, info = Exninfo.capture exn in
    let range = Loc.(get_loc info) in
    let msg = CErrors.iprint (e, info) in
    let quickFix =
      match Quickfix.from_exception exn with
      | Ok [] | Error _ -> None
      | Ok qf -> Some (List.map qf_of_coq qf)
    in
    let payload = Message.Payload.make ?range ?quickFix msg in
    Vernacstate.Interp.invalidate_cache ();
    if CErrors.is_anomaly e then R.Completed (Error (Anomaly payload))
    else R.Completed (Error (User payload))

let _bind_exn ~f x =
  match x with
  | R.Interrupted -> R.Interrupted
  | R.Completed (Error e) -> R.Completed (Error e)
  | R.Completed (Ok r) -> f r

let fb_queue : Loc.t Message.t list ref = ref []

module E = struct
  type ('a, 'l) t =
    { r : ('a, 'l) R.t
    ; feedback : 'l Message.t list
    }

  let eval ~token ~f x =
    let r = eval_exn ~token ~f x in
    let feedback = List.rev !fb_queue in
    let () = fb_queue := [] in
    { r; feedback }

  let map ~f { r; feedback } = { r = R.map ~f r; feedback }

  let map_loc ~f { r; feedback } =
    { r = R.map_loc ~f r; feedback = List.map (Message.map ~f) feedback }

  let bind ~f { r; feedback } =
    match r with
    | R.Interrupted -> { r = R.Interrupted; feedback }
    | R.Completed (Error e) -> { r = R.Completed (Error e); feedback }
    | R.Completed (Ok r) ->
      let { r; feedback = fb2 } = f r in
      { r; feedback = feedback @ fb2 }

  let ok v = { r = Completed (Ok v); feedback = [] }
  let error err = { r = R.error err; feedback = [] }

  module O = struct
    let ( let+ ) x f = map ~f x
    let ( let* ) x f = bind ~f x
  end
end

(* Eval with reified exceptions and feedback *)
let eval ~token ~f x = E.eval ~token ~f x