-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathdata.ml
351 lines (293 loc) · 11.1 KB
/
data.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
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
type state_id =
{ state_id : int }
type route_id =
{ route_id : int }
type ('a, 'b) union =
| Inl of 'a
| Inr of 'b
type coq_info =
{ version : string
; release_date : string }
let compare_version (m1, n1) (m2, n2) =
match Int.compare m1 m2 with
| 0 -> Int.compare n1 n2
| n -> n
type location_offset =
{ start : int
; stop : int }
type pretty_block =
{ content : string
; highlighter : string }
type pretty_expr = pretty_block list
type goal =
{ goal_id : string
; goal_hyp : pretty_expr list
; goal_ccl : pretty_expr }
type goals =
{ fg : goal list
; bg : (goal list * goal list) list
; shelved : goal list
; given_up : goal list }
type data =
| D_Unit
| D_Bool of bool
| D_Int of int
| D_String of string
| D_State_Id of int
| D_Route_Id of int
| D_Coq_Info of coq_info
| D_Location of location_offset
| D_Pretty of pretty_expr
| D_Goal of goal
| D_Goals of goals
| D_Option of data option
| D_Union of (data, data) union
| D_Pair of data * data
| D_List of data list
type _ data_type =
| T_Unit : unit data_type
| T_Bool : bool data_type
| T_Int : int data_type
| T_String : string data_type
| T_State_Id : state_id data_type
| T_Route_Id : route_id data_type
| T_Coq_Info : coq_info data_type
| T_Location : location_offset data_type
| T_Pretty : pretty_expr data_type
| T_Goal : goal data_type
| T_Goals : goals data_type
| T_Option : 'a data_type -> 'a option data_type
| T_List : 'a data_type -> 'a list data_type
| T_Union : 'a data_type * 'b data_type -> ('a, 'b) union data_type
| T_Pair : 'a data_type * 'b data_type -> ('a * 'b) data_type
let rec extract_data : 'a. 'a data_type -> data -> 'a
= fun (type a) (ty : a data_type) data : a ->
match ty, data with
| T_Unit , D_Unit -> ()
| T_Bool , D_Bool b -> b
| T_Int , D_Int i -> i
| T_String , D_String s -> s
| T_State_Id, D_State_Id id -> { state_id = id }
| T_Route_Id, D_Route_Id id -> { route_id = id }
| T_Coq_Info, D_Coq_Info i -> i
| T_Location, D_Location l -> l
| T_Pretty , D_Pretty pe -> pe
| T_Goal , D_Goal g -> g
| T_Goals , D_Goals gs -> gs
| T_Option ty', D_Option opt ->
Option.map (extract_data ty') opt
| T_List ty', D_List lst ->
List.map (extract_data ty') lst
| T_Union(ty', _), D_Union(Inl value') ->
Inl(extract_data ty' value')
| T_Union(_, ty'), D_Union(Inr value') ->
Inr(extract_data ty' value')
| T_Pair(ty1, ty2), D_Pair(v1, v2) ->
( extract_data ty1 v1, extract_data ty2 v2 )
| _ ->
failwith "extract_data"
(*
let rec pack_data : 'a. 'a data_type -> 'a -> data
= fun (type a) (ty : a data_type) (value : a) ->
match ty, value with
| T_Unit , () -> D_Unit
| T_Bool , b -> D_Bool b
| T_Int , i -> D_Int i
| T_String , s -> D_String s
| T_State_Id, id -> D_State_Id id.state_id
| T_Route_Id, id -> D_Route_Id id.route_id
| T_Pretty , pe -> D_Pretty pe
| T_Goal , g -> D_Goal g
| T_Goals , gs -> D_Goals gs
| T_Option ty', opt -> D_Option(Option.map (pack_data ty') opt)
| T_List ty', lst -> D_List(List.map (pack_data ty') lst)
| T_Union(ty', _), Inl value' -> D_Union(Inl(pack_data ty' value'))
| T_Union(_, ty'), Inr value' -> D_Union(Inr(pack_data ty' value'))
| T_Pair(ty1, ty2), (v1, v2) ->
D_Pair(pack_data ty1 v1, pack_data ty2 v2)
*)
let rec xml_of_data data =
let open Xml in
match data with
| D_Unit ->
{ tag = "unit"; attrs = []; body = [] }
| D_Bool b ->
{ tag = "bool"; body = []
; attrs = ["val", if b then "true" else "false"] }
| D_Int i ->
{ tag = "int"; attrs = []
; body = [Xml_Str(string_of_int i)] }
| D_String s ->
{ tag = "string"; attrs = []
; body = [Xml_Str s] }
| D_State_Id id ->
{ tag = "state_id"; body = []
; attrs = ["val", string_of_int id] }
| D_Route_Id id ->
{ tag = "route_id"; body = []
; attrs = ["val", string_of_int id] }
| D_Coq_Info _ | D_Location _ | D_Pretty _ | D_Goal _ | D_Goals _ ->
(* there is no need to serialize these in this plugin *)
failwith "xml_of_data"
| D_Option None ->
{ tag = "option"; attrs = ["val", "none"]
; body = [] }
| D_Option(Some data') ->
{ tag = "option"; attrs = ["val", "some"]
; body = [Xml_Elem(xml_of_data data')] }
| D_Union(Inl data') ->
{ tag = "union"; attrs = ["val", "in_l"]
; body = [Xml_Elem(xml_of_data data')] }
| D_Union(Inr data') ->
{ tag = "union"; attrs = ["val", "in_r"]
; body = [Xml_Elem(xml_of_data data')] }
| D_Pair(fst, snd) ->
{ tag = "pair"; attrs = []
; body = [Xml_Elem(xml_of_data fst); Xml_Elem(xml_of_data snd)] }
| D_List lst ->
{ tag = "list"; attrs = []
; body = List.map (fun d -> Xml_Elem(xml_of_data d)) lst }
let pretty_expr_of_xml xml =
let open Xml in
match xml.tag, xml.attrs, xml.body with
| "_", [], [Xml_Elem { tag = "pp"; attrs = []; body }] ->
let rec content_to_blocks outer_tag xml_content =
match xml_content with
| Xml_Str content ->
[{ content; highlighter = outer_tag }]
| Xml_Elem { tag; body } ->
List.concat_map (content_to_blocks tag) body
in
List.concat_map (content_to_blocks "") body
| _ ->
failwith "pretty_expr_of_xml"
let rec data_of_xml xml =
let open Xml in
match xml.tag, xml.attrs, xml.body with
| "unit", [], [] ->
D_Unit
| "bool", ["val", "true"], [] ->
D_Bool true
| "bool", ["val", "false"], [] ->
D_Bool false
| "int", [], [Xml_Str i] ->
D_Int(int_of_string i)
| "string", [], [Xml_Str s] ->
D_String s
| "string", [], [] ->
D_String ""
| ("state_id" | "edit_id"), ["val", id], [] ->
D_State_Id(int_of_string id)
| "route_id", ["val", id], [] ->
D_Route_Id(int_of_string id)
| "coq_info", [], [Xml_Elem ver; _; Xml_Elem date; _] ->
D_Coq_Info {
version = extract_data T_String (data_of_xml ver);
release_date = extract_data T_String (data_of_xml date)
}
| "loc", ["start", start; "stop", stop], [] ->
D_Location { start = int_of_string start
; stop = int_of_string stop }
| "richpp", [], [Xml_Elem pp] ->
D_Pretty(pretty_expr_of_xml pp)
| "goal", [], [Xml_Elem id; Xml_Elem hyp; Xml_Elem ccl]
(* From Coq 8.14, there's a [string option] field for user-defined goal name.
See [https://github.com/coq/coq/pull/14523] *)
| "goal", [], [Xml_Elem id; Xml_Elem hyp; Xml_Elem ccl; _] ->
D_Goal {
goal_id = extract_data T_String (data_of_xml id);
goal_hyp = extract_data (T_List T_Pretty) (data_of_xml hyp);
goal_ccl = extract_data T_Pretty (data_of_xml ccl)
}
| "goals", []
, [Xml_Elem fg; Xml_Elem bg; Xml_Elem shelved; Xml_Elem given_up] ->
D_Goals {
fg = extract_data (T_List T_Goal) (data_of_xml fg);
bg = data_of_xml bg |> extract_data @@
T_List(T_Pair(T_List T_Goal, T_List T_Goal));
shelved = extract_data (T_List T_Goal) (data_of_xml shelved);
given_up = extract_data (T_List T_Goal) (data_of_xml given_up)
}
| "option", ["val", "none"], [] ->
D_Option None
| "option", ["val", "some"], [Xml_Elem data'] ->
D_Option(Some(data_of_xml data'))
| "union", ["val", "in_l"], [Xml_Elem data'] ->
D_Union(Inl(data_of_xml data'))
| "union", ["val", "in_r"], [Xml_Elem data'] ->
D_Union(Inr(data_of_xml data'))
| "pair", [], [Xml_Elem fst; Xml_Elem snd] ->
D_Pair(data_of_xml fst, data_of_xml snd)
| "list", [], contents ->
D_List(contents |> List.map @@ function
| Xml_Elem elem -> data_of_xml elem
| _ -> failwith "data_of_xml")
| tag, _, _ ->
failwith ("data_of_xml: " ^ tag)
type value =
| Good of data
| Fail of location_offset option * state_id * pretty_expr
type feedback_content =
| Message of string * location_offset option * pretty_expr
| Processed
type feedback =
{ fb_route_id : route_id
; fb_state_id : state_id
; fb_content : feedback_content }
type coq_reply =
| Value of value
| Feedback of feedback
| Unknown
let reply_of_xml xml =
let open Xml in
match xml.tag, xml.attrs, xml.body with
| "value", ["val", "good"], [Xml_Elem elem] ->
Value(Good(data_of_xml elem))
| "value", ["val", "fail"], [Xml_Elem sid; Xml_Elem err_msg] ->
let state_id = extract_data T_State_Id (data_of_xml sid) in
let err_msg = extract_data T_Pretty (data_of_xml err_msg) in
Value(Fail(None, state_id, err_msg))
| "value", ["val", "fail"; "loc_s", loc_s; "loc_e", loc_e]
, [Xml_Elem sid; Xml_Elem err_msg] ->
let state_id = extract_data T_State_Id (data_of_xml sid) in
let err_msg = extract_data T_Pretty (data_of_xml err_msg) in
let start = int_of_string loc_s in
let stop = int_of_string loc_e in
Value(Fail(Some { start; stop }, state_id, err_msg))
| "feedback", ["object", "state"; "route", route]
, [ Xml_Elem sid
; Xml_Elem { tag = "feedback_content"
; attrs = ["val", feedback_type]
; body } ] ->
let route_id = { route_id = int_of_string route } in
let state_id = extract_data T_State_Id (data_of_xml sid) in
begin match feedback_type, body with
| "message"
, [ Xml_Elem { tag = "message"; attrs = []
; body =
[ Xml_Elem { tag = "message_level"
; attrs = ["val", level]
; body = [] }
; Xml_Elem loc
; Xml_Elem msg_content ]
} ] ->
Feedback {
fb_route_id = route_id;
fb_state_id = state_id;
fb_content = Message(
level,
extract_data (T_Option T_Location) (data_of_xml loc),
extract_data T_Pretty (data_of_xml msg_content)
)
}
| "processed", [] ->
Feedback {
fb_route_id = route_id;
fb_state_id = state_id;
fb_content = Processed
}
| _ ->
Unknown
end
| _ ->
Unknown