aboutsummaryrefslogtreecommitdiffhomepage
path: root/contrib/extraction/mlimport.ml
blob: 12e39d044134fd2fcb061ebac372b9b253ed2176 (plain)
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
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488

(*i $Id$ i*)

open Pp
open Names
open Term
open Libobject
open Declare
open Summary

(* TODO : move this function to another file, like more_util. *)

let list0n = 
  let rec gen acc = function
      -1 -> acc
    | n  -> gen (n::acc) (n-1)
  in 
  gen []

(* get a fresh name if necessary *)
let rec next_global_ident id =
  if not (is_global id) then id else next_global_ident (lift_ident id)

(*s Importing ML objects, and linking axioms to terms. *)

(* A table to keep the ML imports. *)

let ml_import_tab = ref (Gmap.empty : (global_reference, identifier) Gmap.t)

let ml_inductives = ref ([] : section_path list)

let add_ml_inductive_import sp =
  if not (List.mem sp !ml_inductives) then
    ml_inductives := sp :: !ml_inductives

let add_ml_import imp id =
  ml_import_tab := Gmap.add imp id !ml_import_tab;
  match imp with
    | IndRef (sp,_) -> add_ml_inductive_import sp
    | _ -> ()

let find_ml_import imp = Gmap.find imp !ml_import_tab

let is_ml_import op =
  try let _ = find_ml_import op in true with Not_found -> false

let sp_is_ml_import sp =
     (is_ml_import (ConstRef sp))
  or (is_ml_import (IndRef (sp,0)))
  or (is_ml_import (ConstructRef ((sp,0),1)))

let sp_prod = path_of_string "#Datatypes#prod.fw"

let sp_is_ml_import_or_prod sp =
  (sp = sp_prod) or (sp_is_ml_import sp)

let inMLImport,outMLImport =
  declare_object ("MLIMPORT",
     { load_function = (fun _ -> ());
       open_function = (fun (_,(imp,id)) -> add_ml_import imp id);
       cache_function = (fun (_,(imp,id)) -> add_ml_import imp id);
       export_function = (fun x -> Some x) })

(* A table to keep the extractions to ML objects *)

let ml_extract_tab = ref (Gmap.empty : (global_reference, identifier) Gmap.t)

let add_ml_extract op id =
  ml_extract_tab := Gmap.add op id !ml_extract_tab;
  match op with 
    | IndRef (sp,_) -> add_ml_inductive_import sp
    | _ -> ()

let find_ml_extract gr = Gmap.find gr !ml_extract_tab

let is_ml_extract op = 
  try let _ = find_ml_extract op in true with Not_found -> false

let sp_is_ml_extract sp =
     (is_ml_extract (ConstRef sp))
  or (is_ml_extract (IndRef (sp,0)))
  or (is_ml_extract (ConstructRef ((sp,0),1)))

let inMLExtract,outMLExtract =
  declare_object ("MLEXTRACT",
     { load_function = (fun _ -> ());
       open_function = (fun (_,(op,id)) -> add_ml_extract op id);
       cache_function = (fun (_,(op,id)) -> add_ml_extract op id);
       export_function = (fun x -> Some x) })

let is_import_or_extract sp = sp_is_ml_import sp or sp_is_ml_extract sp

(* Those two tables are rolled-back *)

let freeze () =
  (!ml_import_tab, !ml_inductives, !ml_extract_tab)

let unfreeze (ft,stk,et) =
  ml_import_tab := ft;
  ml_inductives := stk;
  ml_extract_tab := et

let _ = declare_summary "MLIMPORT-TABLE"
  { freeze_function   = freeze ;
    unfreeze_function = unfreeze ;
    init_function     = (fun () -> ml_import_tab := Gmap.empty;
      	       	       	       	   ml_inductives := [];
				   ml_extract_tab := Gmap.empty);
    survive_section = false }

(**************************************************************************)
(*                      ML Import file__name : type.                      *)
(**************************************************************************)

(***** constants__make_parameter_body *****)
let make_fw_parameter_body (hyps,jt) =
  match level_of_type jt with
    (Prop Pos) | (Type _) ->
      {cONSTKIND = FW;
       cONSTHYPS=hyps;
       cONSTBODY=None;
       cONSTEVAL = None;
       cONSTOPAQUE = true;
       cONSTTYPE= jt;
       cONSTIMPARGS = NO_IMPL }
  | _ -> errorlabstrm "make_fw_parameter_body" 
         [< Printer.fprtype jt ; 'sTR " is not an informative term." >]


(***** constants__infexecute_parameter *****)
let fw_infexecute_parameter fhyps name t =
  let sp = Lib.make_path OBJ name in
  let (u,j) = fexecute_type_with_univ empty_evd fhyps sp t in
  let ids = auto_save_variables() in
  let fhyps' = thin_to_level fhyps (body_of_type j) in
    (u,[FW,make_fw_parameter_body (fhyps',j)])


(***** declare__machine_parameter *****)
let fw_machine_parameter fhyps (name,cty) =
  let (u',cmap) = fw_infexecute_parameter fhyps name cty in
    add_named_object (name,OBJ) (inConstant(cmap,NeverDischarge,u'))


(***** command__parameter_def_var *****)
let fw_parameter id com =
  let tcci = fconstr_of_com empty_evd (initial_fsign()) com in
  let tfw = fwify tcci in
  let _,fhyps = initial_assumptions() in
  fw_machine_parameter fhyps (id,tfw)


let ml_import id' id com =
  fw_parameter id com ;
  let sp = Lib.make_path FW id in
  add_anonymous_object (inMLImport (Const sp, id')) ;
  mSGNL [< 'sTR(string_of_id id) ; 'sTR" imported." >]


let id_of_varg = function
    VARG_IDENTIFIER id -> id
  | VARG_STRING s -> (try id_of_string s with _ -> id_of_string (" "^s))
  | _ -> invalid_arg "id_of_varg"

(*** TODO: remove overwriting ***)
let _ = overwriting_vinterp_add("ML_IMPORT", function
   [id'; VARG_IDENTIFIER id; VARG_COMMAND com] -> 
     (fun () -> ml_import (id_of_varg id') id com)
 | _ -> anomaly "ML_IMPORT called with bad arguments.")



(**************************************************************************)
(*                         Link ident := Fw-term.                         *)
(**************************************************************************)

let not_an_axiom id =
  errorlabstrm "ml_import__fw_link"
  [< 'sTR(string_of_id id) ; 'sTR" is not an FW axiom." >]


let not_have_type env cb' cb =
  let c = match cb'.cONSTBODY with
      Some {contents=COOKED x} -> x
    | _ -> anomaly "ml_import__not_have_type: should be a constant" in
    errorlabstrm "Ml_import.not_convertible"
  [< pENV [< 'sTR"In environment " >] env ; 'fNL ;
     'sTR"The term: " ; pFTERMINENV(env,c) ; 'sPC ; 
     'sTR"does not have type" ; 'sPC ; pFTYPEINENV(env,cb.cONSTTYPE) ;
     'sTR"." ; 'fNL ;
     'sTR"Actually, it has type" ; 'sPC ; pFTYPEINENV(env,cb'.cONSTTYPE) >]


let fw_infexecute_constant fhyps id c =
  let sp = Lib.make_path OBJ id in
  let (u,j) = fexecute_with_univ empty_evd fhyps sp c in
  let ids = auto_save_variables() in
  let fhyps' = thin_to_level fhyps j._KIND in
    (u,[FW, make_constant_body FW false (fhyps',j)])


let fw_link id com =

  (*** First we check that id corresponds to an informative axiom. ***)
  let sp = fwsp_of_id id in
  let osp = objsp_of sp in
  let (cmap,s,u) = match Lib.leaf_object_tag osp with
                     "CONSTANT" -> outConstant (Lib.map_leaf osp)
		   | _ -> not_an_axiom id in
  let cb = try Listmap.map cmap FW
           with Not_found -> not_an_axiom id in
  if cb.cONSTBODY <> None then not_an_axiom id ;

  (*** Then we execute the term com. ***)
  let (hyps,fhyps) = initial_assumptions() in
  let tcci = fconstr_of_com empty_evd hyps com in
  let tfw = fwify tcci in
  let (u',cmap') = fw_infexecute_constant fhyps id tfw in
  let cb' = Listmap.map cmap' FW in

  (*** We check that the type of com is convertible with cb.CONSTTYPE ***)
  if (not (conv empty_evd 
	     (body_of_type cb.cONSTTYPE) 
	     (body_of_type cb'.cONSTTYPE))) then
    not_have_type (gLOB fhyps) cb' cb ;

  (*** At last, we transform the original axiom into a constant. ***)
(**lib__remap (osp,lib__LEAF (inConstant(listmap__remap cmap FW cb',s,u))); **)
  cb.cONSTBODY <- cb'.cONSTBODY ;
  cb.cONSTOPAQUE <- false ;

  let c = match cb'.cONSTBODY with
      Some {contents=COOKED x} -> x
    | _ -> anomaly "ml_import__fw_link: should be a constant" in
  mSGNL (hOV 0 [< 'sTR"Constant " ; print_id id ; 'sTR" linked to" ; 'sPC ;
		  pFTERM c >])


(*** TODO: remove overwriting ***)
let _ = overwriting_vinterp_add("LINK", function
   [VARG_IDENTIFIER id; VARG_COMMAND com] -> (fun () -> fw_link id com)
 | _ -> anomaly "ML_IMPORT called with bad arguments.")



(**************************************************************************)
(*       ML Inductive name [ c1 ... cn ] == <Inductive Definition>.       *)
(**************************************************************************)
(*                     ML Inductive name1 [ c1,1 ... c1,n1 ]              *)
(*                                  ...                                   *)
(*                    	       	    namek [ ck,1 ... ck,nk ]              *)
(*                     == <Mutual Inductive Definition>.                  *)
(**************************************************************************)

(***** declare__machine_minductive *****)
let fw_machine_minductive fhyps nparams mispecvec finite = 
  if Array.length mispecvec = 0 then anomaly "fw_machine_minductive" 
  else 
   let mindidvec = 
     Array.map (fun  (indid,_,_,_,_) -> indid) mispecvec
   and arlcvec = 
     Array.map (fun  (_,_,indarity,indconstructors,_) ->
      	       	       	 (indarity,indconstructors)) mispecvec
   and namesvec = 
     Array.map (fun  (indid,indstamp,_,_,consnames) -> 
      	       	       	 (indstamp,indid,consnames)) mispecvec in

  let sp = Lib.make_path OBJ mindidvec.(0) in
  let (u',mimap) = with_universes 
      (execute_minductive fhyps nparams namesvec finite)
                               (sp,initial_universes,arlcvec) in

  (***  declare_minductive (mindidvec,mimap,u')  ***)
  add_named_object (mindidvec.(0),OBJ) (inMutualInductive (mimap,u'))
  (***  do_vect declare_eliminations mindidvec  ***)


(***** trad__fconstruct *****)
let fw_fconstruct sigma fsign com =
  let c = fconstr_of_com sigma fsign com in
  Mach.fexecute_type sigma fsign c


(***** command__build_mutual *****)
let fw_build_mutual lparams lnamearconstrs finite =

  let lrecnames = List.map (fun (x,_,_)->x)  lnamearconstrs
  and nparams = List.length lparams
  and sign0 = initial_fsign() in

  let (ind_sign,arityl) = List.fold_left 
    (fun (sign,arl) (recname,arityc,_) -> 
      let arity = fw_fconstruct empty_evd sign0 (mkProdCit lparams arityc) in
      (add_sign (recname,arity) sign, (arity::arl)))
      (sign0,[]) lnamearconstrs in

  let mispecvec = Array.of_list 
    (List.map2 (fun ar (name,_,lname_constr) -> 
    let consconstrl = List.map 
     (fun (_,constr) -> 
      	let c = fconstr_of_com empty_evd ind_sign 
		  (mkProdCit lparams constr)
      	in fwify c) lname_constr in
    (name,Anonymous,ar,
        put_DLAMSV_subst (List.rev lrecnames) (Array.of_list consconstrl),
              Array.of_list (List.map fst lname_constr)))
    (List.rev arityl) lnamearconstrs) in

  let _,fhyps = initial_assumptions() in
  fw_machine_minductive fhyps nparams mispecvec finite


let not_same_number_types () =
  errorlabstrm "ml_import__ml_import_inductive"
  [< 'sTR"Not the same number of types." >]

let not_same_number_constructors (id,id') =
  errorlabstrm "ml_import__ml_import_inductive"
    (hOV 0
       [< 'sTR"The ML type" ; 'sPC ; print_id id ;
          'sTR" and the FW type" ; 'sPC ; print_id id' ; 'sPC ;
          'sTR"do not have the same number" ;
      	  'sPC ; 'sTR"of constructors." >])

let ml_import_inductive names lparams lnamearconstrs finite =

  let assoc_list =
    if (List.length names) <> (List.length lnamearconstrs) then
      not_same_number_types ()
    else
      List.fold_right2 (fun (id,l) (id',_,l') acc ->
      	  if (List.length l)<>(List.length l') then
	    not_same_number_constructors (id,id')
	  else
	    ( (id,id'), List.combine l (List.map fst l') )::acc ) 
            names lnamearconstrs [] in

  fw_build_mutual lparams lnamearconstrs finite;

  List.iter
      (fun i ->
      	  let (mlid,id), l = List.nth assoc_list i in
      	  let sp = Lib.make_path FW id in
	  add_anonymous_object (inMLImport (MutInd (sp,i), mlid)) ;
	  List.iter (fun j ->
      	      let (mlid,id) = List.nth l (j-1) in
      	      add_anonymous_object
      	       	       	   (inMLImport (MutConstruct ((sp,i),j), mlid)) )
	  (List.tl (list0n (List.length l))) )
      (list0n ((List.length assoc_list) - 1)) ;

  pPNL [< 'sTR"ML inductive type(s) " ;
      	  prlist_with_sep (fun () -> [< 'sTR"," ; 'sPC >])
	                  (fun (id,_) -> [< 'sTR(string_of_id id) >]) names ;
         'sTR" imported." >]
  

(*** TODO: remove overwriting ***)
let _ = overwriting_vinterp_add("ML_ONEINDUCTIVE",
    function [VARG_VARGLIST nl;
         VARG_IDENTIFIER s;
         VARG_COMMAND c;
         VARG_BINDERLIST binders;
         VARG_BINDERLIST constructors] ->
        if List.length nl <> 1 then not_same_number_types () ;
	(match nl with
	     [VARG_VARGLIST (v::l)] ->
	       let cnames = List.map id_of_varg l in
               let la = join_binders binders in
               let li = List.map (fun (l,c) -> (List.hd l,c)) constructors in
        	 (function () -> ml_import_inductive [id_of_varg v,cnames] 
		      la [(s,c,li)] true)
	   | _ -> assert false)
      | _ -> anomaly "ML_ONEINDUCTIVE called with bad arguments.")


(*** TODO: remove overwriting ***)
let _ = overwriting_vinterp_add("ML_MUTUALINDUCTIVE",
    function [VARG_VARGLIST l;
      	 VARG_BINDERLIST binders;
      	 VARG_VARGLIST indl] ->
	let names = 
	  List.map (function (VARG_VARGLIST (v::ll)) ->
      	       	      id_of_varg v, List.map id_of_varg ll
		      | _ -> assert false) l in
        let la = join_binders binders in
        let lnamearconstructs = 
          List.map (function (VARG_VARGLIST [VARG_IDENTIFIER arid;
      	       	       	       	   VARG_COMMAND arc;
      	       	       	       	   VARG_BINDERLIST lconstr])
                	-> (arid,arc,
			    List.map (fun (l,c) -> (List.hd l,c)) lconstr)
		      | _ -> assert false)
      	      indl in
        (function () -> ml_import_inductive names la lnamearconstructs true)
      | _ -> anomaly "ML_MUTUALINDUCTIVE called with bad arguments.")



(**************************************************************************)
(*                       Extract Constant id => id                        *)
(*        Extract Inductive (id [id ... id])+ => (id [id ... id])+        *)
(**************************************************************************)

let extract_constant id id' =
  try
    let sp = Nametab.sp_of_id FW id in
      (match global_operator sp id with
	   Const _,_ -> add_anonymous_object (inMLExtract (Const sp,id'))
	 | _ -> raise Not_found)
  with Not_found ->
    errorlabstrm "Ml_import.extract_constant"
      [< pID id; 'sPC; 'sTR"is not an FW constant" >]


(*** TODO: remove overwriting ***)
let _ = overwriting_vinterp_add("EXTRACT_CONSTANT",
  function 
      [VARG_IDENTIFIER id; id'] -> 
	fun () -> extract_constant id (id_of_varg id')
    | _ -> assert false)


let extract_inductive id (id2,l2) =
  try
    let sp = Nametab.sp_of_id FW id in
      (match global_operator sp id with
	  MutInd (sp,i),_ -> 
	    add_anonymous_object (inMLExtract (MutInd (sp,i),id2));
	    (* TODO: verifier le nombre de constructeurs *)
	    List.iter
	      (fun (id,j) -> 
		 add_anonymous_object 
		   (inMLExtract (MutConstruct ((sp,i),j),id)))
	      (List.combine l2 (List.tl (list0n (List.length l2))))
	| _ -> raise Not_found)
  with Not_found ->
    errorlabstrm "Ml_import.extract_inductive"
      [< pID id; 'sPC; 'sTR"is not an FW inductive type" >]


(*** TODO: remove overwriting ***)
let _ = overwriting_vinterp_add("EXTRACT_INDUCTIVE",
  function 
      [VARG_IDENTIFIER id1; VARG_VARGLIST (id2::l2)] ->
	fun () -> extract_inductive id1 (id_of_varg id2,List.map id_of_varg l2)
    | _ -> assert false)


(**************************************************************************)
(*                            Fw Print ident.                             *)
(*                     To see FW constants or axioms.                     *)
(**************************************************************************)

let fprint_recipe = function
    Some{contents=COOKED c} -> pFTERM c
  | Some{contents=RECIPE _} -> [< 'sTR"<recipe>" >]
  | None -> [< 'sTR"<uncookable>" >]


let fprint_name id =
  try let sp = Nametab.sp_of_id FW id in
      let obj = Lib.map_leaf (objsp_of sp) in
      (match object_tag obj with
       	 "CONSTANT" ->
      	     let (cmap,_,_) = outConstant obj in
	     let {cONSTBODY=val_0;cONSTTYPE=typ} = Listmap.map cmap FW in
	     hOV 0 (match val_0 with
	        None -> [< 'sTR"*** [ "; 'sTR(string_of_id id);  'sTR " : ";
                           'cUT ; fprtype typ ; 'sTR" ]"; 'fNL >] 
	      | _    -> [< 'sTR(string_of_id id); 'sTR" = " ; 
                           fprint_recipe val_0 ;
	                   'fNL ; 'sTR "     : "; fprtype typ ; 'fNL >] )

       | "MUTUALINDUCTIVE" ->
       	     let (cmap,_) = outMutualInductive obj in
	     [< print_mutual FW (Listmap.map cmap FW) ; 'fNL >]
  
       | _ -> invalid_arg "fprint_name" )
  with Not_found | Invalid_argument _ -> errorlabstrm "ml_import__fprint_name"
                    [< 'sTR(string_of_id id) ; 'sTR" is not an FW constant." >]


(*** TODO: remove overwriting ***)
let _ = overwriting_vinterp_add("FWPRINT",
    function [VARG_IDENTIFIER id] -> (function () -> mSG(fprint_name id))
      | _ -> anomaly "FWPRINT called with bad arguments.")