aboutsummaryrefslogtreecommitdiffhomepage
path: root/toplevel/record.ml
blob: cc44bc22bd2727187c99334bc4052c274cdcd975 (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

(* $:Id$ *)

open Util;;
open Names;;
open Term;;
(*
open Generic;;
open Mach;;
open Command;;
open More_util;;
open Pp;;

open Constrtypes;;
open Termenv;;
open Trad;;
open Ast;;
open CoqAst;;

open Machops;;
open Classops;;
open Recordops;;
*)

(********** definition d'un record (structure) **************)

let make_constructor fields appc =
 let rec aux fields =
  match fields with
     [] -> appc
   | (id,ty)::l -> ope("PROD",[ty; slam(Some (string_of_id id), aux l)]) 
 in aux fields;;

(* free_vars existe de'ja` dans ast.ml *)

let rec drop = function
    [] -> []
  | (None::t) -> drop t
  | ((Some id)::t) -> id::(drop t)
;;

let fold curriedf l base =
  List.fold_right (fun a -> fun b -> curriedf(a,b)) l base
;;

let free_vars t = 
 let rec aux = function
  (Nvar(_,s),accum) -> add_set (id_of_string s) accum
| (Node(_,_,tl),accum) -> fold aux tl accum
| (Slam(_,None,body),accum) ->
        (aux(body,[]))@accum
| (Slam(_,Some id,body),accum) ->
        (subtract (aux(body,[])) [(id_of_string id)])@accum
| (_,accum) -> accum
 in aux(t,[]) 
;;

let free_in_asts id l = 
  let rec aux =
    function [] -> true
      | a::l -> (not (List.mem id (free_vars a))) & (aux l) in
  aux l;;

let all_vars t = 
 let rec aux = function
  (Nvar(_,id),accum) -> add_set (id_of_string id) accum
| (Node(_,_,tl),accum) -> fold aux tl accum
| (Slam(_,None,body),accum) -> aux (body,accum)
| (Slam(_,Some id,body),accum) ->
    aux (body,(union accum [(id_of_string id)]))
| (_,accum) -> accum
 in aux(t,[]) 
;;
   
let print_id_list l =
  [< 'sTR "[" ; prlist (fun id -> [< 'sTR (string_of_id id) >]) l; 'sTR "]" >]
;; 

let typecheck_params_and_field ps fs =
  let sign0 = initial_sign() in
  let sign1,newps =
    List.fold_left
      (fun (sign,newps) (id,t) -> 
         let tj = type_of_com sign t in
           (add_sign (id,tj) sign,(id,tj.body)::newps))
      (sign0,[]) ps in
  let sign2,newfs =
    List.fold_left
      (fun (sign,newfs) (id,t) -> 
         let tj = type_of_com sign t in
           (add_sign (id,tj) sign,(id,tj.body)::newfs)) (sign1,[]) fs
  in List.rev(newps),List.rev(newfs)
;;


let mk_LambdaCit = List.fold_right (fun (x,a) b -> mkNamedLambda x a b);;


let definition_structure (coe_constr,struc,ps,cfs,const,s) =

 let (sign,fsign) = initial_assumptions() in
 let fs = List.map snd cfs in     
 let coers = List.map fst cfs in  
 let idps = List.map fst ps in      
 let typs = List.map snd ps in
 let idfs = List.map fst fs in
 let tyfs = List.map snd fs in
 let _ = if not (free_in_asts struc tyfs)
            then message "Error: A record cannot be recursive" in
 let newps,newfs = typecheck_params_and_field ps fs in
 let app_constructor = ope("APPLIST",
                           (ope("XTRA",[str "!";(nvar (string_of_id struc))]))::
                           List.map (fun id -> nvar(string_of_id id)) idps) in
 let type_constructor = make_constructor fs app_constructor in 
 let _ = build_mutual ps [(struc,s,[(const,type_constructor)])] true in

 let x = next_ident_away (id_of_string "x") 
               (List.fold_left (fun l ty -> union (all_vars ty) l) 
               (union idps (fst sign)) tyfs) in
 let r = Machops.global (gLOB sign) struc in
 let (rsp,_,_) = destMutInd r in
 let rid = basename rsp in
 let lp = length idps in
 let rp1 = applist (r,(rel_list 0 lp)) in
 let rp2 = applist (r,(rel_list 1 lp)) in
 let warning_or_error coe st = if coe then (errorlabstrm "structure" st)
                               else pPNL [< 'sTR"Warning: "; st >] in
        
 let (sp_projs,_,_,_,_) =
   List.fold_left 
   (fun (sp_projs,ids_ok,ids_not_ok,sigma,coes) (fi,ti) -> 
      let fv_ti = global_vars ti in
      let bad_projs = (intersect ids_not_ok fv_ti) in
      if bad_projs <> []
      then begin (warning_or_error (hd coes)
                   [< 'sTR(string_of_id fi); 
                      'sTR" cannot be defined. The projections ";
                         print_id_list bad_projs; 'sTR " were not defined" >]);
                 (None::sp_projs,ids_ok,fi::ids_not_ok,sigma,(tl coes))
           end
      else 

      let p = mkNamedLambda x rp2 (replace_vars sigma ti) in
      let branch = mk_LambdaCit newfs (VAR fi) in
      let proj = mk_LambdaCit newps 
             (mkNamedLambda x rp1 (mkMutCaseA (ci_of_mind r) p (Rel 1) [|branch|])) in
      let ok = try (Declare.machine_constant (sign,fsign)
                    ((fi,false,NeverDischarge),proj); true)
               with UserError(s,pps) ->
                 ((warning_or_error (hd coes) 
                     [<'sTR (string_of_id fi); 
                       'sTR" cannot be defined. "; pps >]);false) in
      if not ok
      then (None::sp_projs,ids_ok,fi::ids_not_ok,sigma,(tl coes))
      else begin
        if List.hd coes then
           Class.try_add_new_coercion_record fi NeverDischarge rsp;
        let constr_fi = Machops.global (gLOB sign) fi in
        let constr_fip =
          applist (constr_fi,(List.map (fun id -> VAR id) idps)@[VAR x])
        in (Some(path_of_const constr_fi)::sp_projs,fi::ids_ok,ids_not_ok,
            (fi,{sinfo=Closed;sit=constr_fip})::sigma,(tl coes))
      end)
     ([],[],[],[],coers) newfs
   in (if coe_constr="COERCION" 
     then Class.try_add_new_coercion const NeverDischarge);
          add_new_struc (rsp,const,lp,rev sp_projs)
;;
         
(* $Id$ *)