/
host2spec.ml
371 lines (341 loc) · 15.3 KB
/
host2spec.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
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
(****************************************************************************)
(* RelationExtraction - Extraction of inductive relations for Coq *)
(* *)
(* This program is free software: you can redistribute it and/or modify *)
(* it under the terms of the GNU General Public License as published by *)
(* the Free Software Foundation, either version 3 of the License, or *)
(* (at your option) any later version. *)
(* *)
(* This program is distributed in the hope that it will be useful, *)
(* but WITHOUT ANY WARRANTY; without even the implied warranty of *)
(* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *)
(* GNU General Public License for more details. *)
(* *)
(* You should have received a copy of the GNU General Public License *)
(* along with this program. If not, see <http://www.gnu.org/licenses/>. *)
(* *)
(* Copyright 2011 CNAM-ENSIIE *)
(* Catherine Dubois <dubois@ensiie.fr> *)
(* David Delahaye <david.delahaye@cnam.fr> *)
(* Pierre-Nicolas Tollitte <tollitte@ensiie.fr> *)
(****************************************************************************)
open Util
open Pp
open Declarations
open Term
open Names
open Libnames
open Nametab
open Inductive
open Pred
open Host_stuff
open Coq_stuff
(* TODO:
- correct types annotations for (=) arguments.
currently they are typed as "refl_eq".
*)
(* Adds the global reference of an inductive into the exract env. *)
let add_indgref_to_env env id ind_gref =
if List.mem_assoc id env.extr_henv.ind_grefs then env
else let ind_grefs' = (id, ind_gref)::env.extr_henv.ind_grefs in
{env with extr_henv = {env.extr_henv with ind_grefs = ind_grefs'}}
(* Adds the global reference of an inductive into the exract env. *)
let add_cstr_to_env env id cstr =
if List.mem_assoc id env.extr_henv.cstrs then env
else let cstrs' = (id, cstr)::env.extr_henv.cstrs in
{env with extr_henv = {env.extr_henv with cstrs = cstrs'}}
(* Gets the identifier of a binder *)
let get_name = function
| (Name id, _) -> id
| _ -> anomalylabstrm "RelationExtraction"
(str "Cannot find the name of a binder")
(* Finds a list of the constructors of an inductive type. *)
let find_it_constrs constr =
let ind, i = destConstruct constr in
let _,idc = Inductive.lookup_mind_specif (Global.env ()) ind in
List.map (fun cstr_id ->
ident_of_string (string_of_id cstr_id)
) (Array.to_list idc.mind_consnames)
(* Gets type of one inductive body. *)
let get_prod_type_from_oib oib =
match oib.mind_arity with
| Monomorphic a -> a.mind_user_arity
| _ -> errorlabstrm "RelationExtraction" (str "Non monomorphic arity")
(* TODO: make compatibility with mutual inductives (see the <Rel _> case) *)
(* Finds type of a constructor. For each argument of this constructor:
- the list of constructors of the argument type.
- the argument type itself. *)
let find_types_of_constr constr = match kind_of_term constr with
| Construct (ind, i) ->
let mib, oib = Inductive.lookup_mind_specif (Global.env ()) ind in
let (n, _) = decompose_prod oib.mind_user_lc.(i-1) in
List.map (fun (_, c) -> match kind_of_term c with
| Ind ind ->
let _, oib = Inductive.lookup_mind_specif (Global.env ()) ind in
CTSum (List.map (fun cstr_id ->
(ident_of_string (string_of_id cstr_id))
) (Array.to_list oib.mind_consnames)), Some c
| Rel _ -> let ty = mkInd ind in
let _, oib = Inductive.lookup_mind_specif (Global.env ()) ind in
CTSum (List.map (fun cstr_id ->
(ident_of_string (string_of_id cstr_id))
) (Array.to_list oib.mind_consnames)), Some ty
| _ -> CTNone, Some c
) (List.rev n)
| _ -> anomalylabstrm "RelationExtraction" (str "Constructor type not found")
(* TODO: make compatibility with mutual inductives (see the <Rel _> case) *)
(* Finds type of an inductive arguments. For each argument:
- the list of constructors of the argument type.
- the argument type itself. *)
let find_types_of_ind ind =
let _, oib = Inductive.lookup_mind_specif (Global.env ()) ind in
let (n, _) = decompose_prod (get_prod_type_from_oib oib) in
List.map (fun (_, c) -> match kind_of_term c with
| Ind ind ->
let _, oib = Inductive.lookup_mind_specif (Global.env ()) ind in
CTSum (List.map (fun cstr_id ->
(ident_of_string (string_of_id cstr_id))
) (Array.to_list oib.mind_consnames)), Some c
| Rel _ -> let ty = mkInd ind in
let _, oib = Inductive.lookup_mind_specif (Global.env ()) ind in
CTSum (List.map (fun cstr_id ->
(ident_of_string (string_of_id cstr_id))
) (Array.to_list oib.mind_consnames)), Some ty
| _ -> CTNone, Some c
) (List.rev n)
let rec filter2 p l1 l2 = match l1, l2 with
| a::tl1, b::tl2 -> if p a b then let l1, l2 = filter2 p tl1 tl2 in
a::l1, b::l2
else filter2 p tl1 tl2
| _ -> l1, l2
let rec filter3 p l1 l2 l3 = match l1, l2, l3 with
| a::tl1, b::tl2, c::tl3 -> if p a then let l2, l3 = filter3 p tl1 tl2 tl3 in
b::l2, c::l3
else filter3 p tl1 tl2 tl3
| _ -> l2, l3
let rec map_filter f l = match l with
| [] -> []
| a::tl -> let b, a' = f a in if b then
a'::(map_filter f tl)
else map_filter f tl
(* Filters implicit arguments of Coq constr arguments.
h and args must come from a constr of the form App(h, args).
When typs is not known, the function can be called with h args args. *)
let filter_impargs_cstr h args typs =
let imp = match Impargs.implicits_of_global (global_of_constr h) with
| (_,a)::_ -> a
| _ -> [] in
let filter = fun a -> not (Impargs.is_status_implicit a) in
let rec terms_filter term typ = match kind_of_term term with
| Ind _ -> false
| App (h, _) -> terms_filter h typ
| _ -> true in
let args = Array.to_list args in
let no_imp_args, no_imp_typ =
if List.length args <> List.length imp then args, typs
else filter3 filter imp args typs in
let nargs, ntyps = filter2 terms_filter no_imp_args no_imp_typ in
(Array.of_list nargs, ntyps)
(* Parses a simple Coq term. *)
let rec build_untyped_term (env, id_spec) prod term =
match kind_of_term term with
| Const c -> let i = ident_of_string (string_of_con c) in
let env = add_cstr_to_env env i term in
MLTConst i, env
| Rel i -> let n =
ident_of_string (string_of_id (get_name (List.nth prod (i-1)))) in
MLTVar n, env
| App (h, args) when isConstruct h ->
let typs = find_types_of_constr h in
let args, typs = filter_impargs_cstr h args typs in
let _, i = destConstruct h in
let it_constrs = find_it_constrs h in
let constr = List.nth it_constrs (i-1) in
let args, env = List.fold_right2 (fun t a (args, env) ->
let a, env = build_term (env, id_spec) prod (Some t) a in
a::args, env) typs (Array.to_list args) ([], env) in
let env = add_cstr_to_env env constr h in
MLTConstr (constr, args), env
| Construct _ ->
let _, i = destConstruct term in
let it_constrs = find_it_constrs term in
let constr = List.nth it_constrs (i-1) in
let env = add_cstr_to_env env constr term in
MLTConstr (constr, []), env
| App (h, args) ->
let args, _ = filter_impargs_cstr h args (Array.to_list args) in
let c = destConst h in
let n = con_label c in
let s = ident_of_string (string_of_label n) in
let args, inf = List.fold_right (fun a (args, env) ->
let a, env = build_term (env, id_spec) prod None a in
a::args, env) (Array.to_list args) ([], env) in
let env = add_cstr_to_env env s h in
MLTFun (s, args, None), env
| _ -> anomalylabstrm "RelationExtraction" (str "Unknown Coq construction")
and build_term (env, id_spec) prod typ term =
let (t, env) = build_untyped_term (env, id_spec) prod term in
match typ with
| None -> fake_type env t, env
| Some typ -> (t, typ), env
(* Mode Skip filter *)
let rec filter_mode_skip mode args = match (mode, args) with
| (MSkip::tl_mode, a::tl_args) -> filter_mode_skip tl_mode tl_args
| (_::tl_mode, a::tl_args) -> a::(filter_mode_skip tl_mode tl_args)
| _ -> []
(* Parses the conclusion of a predicate's constructor (or property). *)
let build_concl (env, id_spec) named_prod term = match kind_of_term term with
| App (_, args) -> let mode = List.hd (extr_get_modes env id_spec) in
let ind_ref = List.assoc id_spec env.extr_henv.ind_refs in
let ind = destInd (constr_of_global (global ind_ref)) in
let typs = find_types_of_ind ind in
let args = filter_mode_skip mode (Array.to_list args) in
let typs = filter_mode_skip mode typs in
let args, env = List.fold_right2 (fun a t (args, env) ->
let a, env = build_term (env, id_spec) named_prod (Some t) a in
a::args, env
) args typs ([], env) in
fake_type env (MLTFun (id_spec, args, Some mode)), env
| _ -> anomalylabstrm "RelationExtraction"
(str "Cannot find a constructor's conclusion")
(* Tests if a constr is \/ *)
let isOr constr =
if isInd constr then
let ind = destInd constr in
let _,oid = Inductive.lookup_mind_specif (Global.env ()) ind in
(string_of_id oid.mind_typename = "or")
else false
(* Tests if a constr is /\ *)
let isAnd constr =
if isInd constr then
let ind = destInd constr in
let _,oid = Inductive.lookup_mind_specif (Global.env ()) ind in
(string_of_id oid.mind_typename = "and")
else false
(* Tests if a constr is not *)
let isNot constr =
if isConst constr then
let c = destConst constr in
let str = string_of_con c in
let str' = try let i = String.rindex str '#' in
String.sub str (i+1) (String.length str - i - 1)
with Not_found | Invalid_argument _ -> str in
str' = "not"
else false
(* Parses a premisse of a predicate's constructor (or property). *)
let rec build_premisse (env, id_spec) named_prod term =
let build_predicate ind args =
let _, oib = Inductive.lookup_mind_specif (Global.env ()) ind in
let ind_gref = locate (qualid_of_ident oib.mind_typename) in
let id = ident_of_string (string_of_id oib.mind_typename) in
let modes = begin match extr_get_modes env id with
| [] -> [make_mode ind_gref None]
| modes -> modes end in
let typs = find_types_of_ind ind in
let pred_terms, env = List.fold_right (fun mode (pred_terms, env) ->
let args = filter_mode_skip mode (Array.to_list args) in
let typs = filter_mode_skip mode typs in
let args, env = List.fold_right2 (fun a t (args, env) ->
let a, env = build_term (env, id_spec) named_prod (Some t) a in
a::args, env
) args typs ([], env) in
(PMTerm (fake_type env (MLTFun (id, args, Some mode))))::pred_terms, env
) modes ([], env) in
let env = add_indgref_to_env env id ind_gref in
begin match pred_terms with
| [] -> anomalylabstrm "RelationExtraction" (str "Bad premisse form")
| [pred_term] -> pred_term, env
| _ -> PMChoice pred_terms, env
end in
begin match kind_of_term term with
| App (h, [|arg|]) when isNot h ->
let pm, env = build_premisse (env, id_spec) named_prod arg in
(PMNot pm, env)
| App (h, args) when isOr h ->
let pms, env = build_premisse_list (env, id_spec)
named_prod (Array.to_list args) in
(PMOr pms, env)
| App (h, args) when isAnd h ->
let pms, env = build_premisse_list (env, id_spec)
named_prod (Array.to_list args) in
(PMAnd pms, env)
| App (h, _) when isConst h -> let t, env = build_term (env, id_spec)
named_prod None term in
PMTerm t, env
| App (h, args) when isInd h -> let ind = destInd h in
build_predicate ind args
| App (h, args) when isRel h -> let i = destRel h in
let ind_ref = List.assoc id_spec env.extr_henv.ind_refs in
let ind = destInd (constr_of_global (global ind_ref)) in
let mib, oib = Inductive.lookup_mind_specif (Global.env ()) ind in
let ind_binds = List.rev (Array.to_list mib.mind_packets) in
let i = i - List.length named_prod - 1 in
let good_oib = List.nth ind_binds i in
let ind_gref = global (Ident (dummy_loc, good_oib.mind_typename)) in
let ind = destInd (constr_of_global ind_gref) in
build_predicate ind args
| _ -> anomalylabstrm "RelationExtraction" (str "Bad premisse form")
end
and build_premisse_list (env, id_spec) named_prod terms =
List.fold_right (fun term (prems, env) ->
let p, env = build_premisse (env, id_spec) named_prod term in
p::prems, env
) terms ([], env)
let build_prem (env, id_spec) named_prod cstr = match kind_of_term cstr with
| App (_, args) ->
let t, env = build_premisse (env, id_spec) named_prod cstr in
begin match t with
| PMTerm (MLTFun (_, [], _),_) ->
([], env) (* fix for the fake list() premisse *)
| _ -> ([t], env)
end
| _ -> ([], env)
(* Parses the whole set of premisses of a predicate's constructor
(or property). *)
let rec build_prems (env, id_spec) named_prod cstr_list = match cstr_list with
| [] -> [], env
| cstr::tail -> if isProd cstr then
anomalylabstrm "RelationExtraction" (str "Too many products in a premisse")
else
let p, env = build_prem (env, id_spec) (List.tl named_prod) cstr in
let p2, env = build_prems (env, id_spec) (List.tl named_prod) tail in
(p@p2, env)
(* Parses a predicate's constructor (or property). *)
let build_prop (env, id_spec) prop_name prop_type =
let named_prod, concl = decompose_prod prop_type in
let concl, env = build_concl (env, id_spec) named_prod concl in
let named_prems = List.filter (fun (x, _) -> x = Anonymous) named_prod in
let prems = List.map snd named_prems in
let prems, env = build_prems (env, id_spec) named_prod prems in
let vars = map_filter (fun (x, _) -> match x with
| Name id -> true, ident_of_string (string_of_id id)
| Anonymous -> false, ident_of_string "") named_prod in
{
prop_name = Some prop_name;
prop_vars = vars;
prop_prems = prems;
prop_concl = concl
}, env
(* Parses one predicate's specification. *)
let find_one_spec env (id_spec, _) =
let idr = List.assoc id_spec env.extr_henv.ind_refs in
let ind = destInd (constr_of_global (global idr)) in
let _, oib = Inductive.lookup_mind_specif (Global.env ()) ind in
let props, env = List.fold_right2 (fun prop_name cstr (pl, env) ->
let prop_name = ident_of_string (string_of_id prop_name) in
let p, env = build_prop (env, id_spec) prop_name cstr in
p::pl, env
)
(Array.to_list oib.mind_consnames)
(Array.to_list oib.mind_user_lc) ([], env) in
let args_types = find_types_of_ind ind in
(id_spec, {
spec_name = id_spec;
spec_args_types = args_types;
spec_props = props;
}), env
let find_specifications env =
let specs, env = List.fold_right (fun e (specs, env) ->
let s, env = find_one_spec env e in
s::specs, env) env.extr_extractions ([], env) in
{ env with extr_specs = specs }