]> matita.cs.unibo.it Git - helm.git/blob - helm/ocaml/cic_notation/cicNotationRew.ml
snapshot (the thing on the doorstep)
[helm.git] / helm / ocaml / cic_notation / cicNotationRew.ml
1 (* Copyright (C) 2004-2005, HELM Team.
2  * 
3  * This file is part of HELM, an Hypertextual, Electronic
4  * Library of Mathematics, developed at the Computer Science
5  * Department, University of Bologna, Italy.
6  * 
7  * HELM is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  * 
12  * HELM is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with HELM; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place - Suite 330, Boston,
20  * MA  02111-1307, USA.
21  * 
22  * For details, see the HELM World-Wide-Web page,
23  * http://helm.cs.unibo.it/
24  *)
25
26 type pattern_id = int
27
28 type term_info =
29   { sort: (Cic.id, CicNotationPt.sort_kind) Hashtbl.t;
30     uri: (Cic.id, string) Hashtbl.t;
31   }
32
33 exception No_match
34
35 module OrderedInt =
36   struct
37   type t = int
38   let compare (x1:t) (x2:t) = Pervasives.compare x2 x1  (* reverse order *)
39   end
40
41 module IntSet = Set.Make (OrderedInt)
42
43 let int_set_of_int_list l =
44   List.fold_left (fun acc i -> IntSet.add i acc) IntSet.empty l
45
46 let (compiled32: (term_info -> Cic.annterm -> CicNotationPt.term) option ref) =
47   ref None
48
49 let get_compiled32 () =
50   match !compiled32 with
51   | None -> assert false
52   | Some f -> f
53
54 let set_compiled32 f = compiled32 := Some f
55
56 let warning s = prerr_endline ("CicNotation WARNING: " ^ s)
57
58 module Patterns =
59   struct
60   type row_t = CicNotationPt.cic_appl_pattern list * pattern_id
61   type t = row_t list
62
63   let first_column t = List.map (fun (patterns, _) -> List.hd patterns) t
64   let pattern_ids t = List.map snd t
65
66   let prepend_column t column =
67     try
68       List.map2 (fun elt (pl, pid) -> (elt :: pl), pid) column t
69
70     with Invalid_argument _ -> assert false
71
72   let prepend_columns t columns =
73     List.fold_right
74       (fun column rows -> prepend_column rows column)
75       columns t
76
77   let partition t pidl =
78     let partitions = Hashtbl.create 11 in
79     let add pid row = Hashtbl.add partitions pid row in
80     (try
81       List.iter2 add pidl t
82     with Invalid_argument _ -> assert false);
83     let pidset = int_set_of_int_list pidl in
84     IntSet.fold
85       (fun pid acc ->
86         match Hashtbl.find_all partitions pid with
87         | [] -> acc
88         | patterns -> (pid, List.rev patterns) :: acc)
89       pidset []
90
91   let are_empty t = fst (List.hd t) = []
92     (* if first row has an empty list of patterns, then others will as well *)
93
94     (* return 2 lists of rows, first one containing homogeneous rows according
95      * to "compatible" below *)
96   let horizontal_split t =
97     let compatible ap1 ap2 =
98       match ap1, ap2 with
99       | CicNotationPt.UriPattern _, CicNotationPt.UriPattern _
100       | CicNotationPt.ArgPattern _, CicNotationPt.ArgPattern _
101       | CicNotationPt.ApplPattern _, CicNotationPt.ApplPattern _ -> true
102       | _ -> false
103     in
104     let ap =
105       match t with
106       | [] -> assert false
107       | ([], _) :: _ ->
108           assert false  (* are_empty should have been invoked in advance *)
109       | (hd :: _ , _) :: _ -> hd
110     in
111     let rec aux prev_t = function
112       | [] -> List.rev prev_t, []
113       | ([], _) :: _ -> assert false
114       | (((hd :: _), _) as row) :: tl when compatible ap hd ->
115           aux (row :: prev_t) tl
116       | t -> List.rev prev_t, t
117     in
118     aux [] t
119
120     (* return 2 lists, first one representing first column, second one
121      * representing rows stripped of the first element *)
122   let vertical_split t =
123     let l =
124       List.map
125         (function
126           | (hd :: tl, pid) -> hd, (tl, pid)
127           | _ -> assert false)
128         t
129     in
130     List.split l
131   end
132
133 let get_types uri =
134   let o,_ = CicEnvironment.get_obj CicUniv.empty_ugraph uri in
135     match o with
136       | Cic.InductiveDefinition (l,_,_,_) -> l 
137       | _ -> assert false
138
139 let name_of_inductive_type uri i = 
140   let types = get_types uri in
141   let (name, _, _, _) = try List.nth types i with Not_found -> assert false in
142   name
143
144   (* returns <name, type> pairs *)
145 let constructors_of_inductive_type uri i =
146   let types = get_types uri in
147   let (_, _, _, constructors) = 
148     try List.nth types i with Not_found -> assert false
149   in
150   constructors
151
152   (* returns name only *)
153 let constructor_of_inductive_type uri i j =
154   (try
155     fst (List.nth (constructors_of_inductive_type uri i) (j-1))
156   with Not_found -> assert false)
157
158 module Ast = CicNotationPt
159
160 let string_of_name = function
161   | Cic.Name s -> s
162   | Cic.Anonymous -> "_"
163
164 let ident_of_name n = Ast.Ident (string_of_name n, None)
165
166 let ast_of_acic0 term_info acic k =
167   let k = k term_info in
168   let register_uri id uri = Hashtbl.add term_info.uri id uri in
169   let sort_of_id id =
170     try
171       Hashtbl.find term_info.sort id
172     with Not_found -> assert false
173   in
174   let idref id t = Ast.AttributedTerm (`IdRef id, t) in
175   let aux_substs substs =
176     Some
177       (List.map
178         (fun (uri, annterm) -> (UriManager.name_of_uri uri, k annterm))
179         substs)
180   in
181   let aux_context context =
182     List.map
183       (function
184         | None -> None
185         | Some annterm -> Some (k annterm))
186       context
187   in
188   let aux = function
189     | Cic.ARel (id,_,_,b) -> idref id (Ast.Ident (b, None))
190     | Cic.AVar (id,uri,substs) ->
191         register_uri id (UriManager.string_of_uri uri);
192         idref id (Ast.Ident (UriManager.name_of_uri uri, aux_substs substs))
193     | Cic.AMeta (id,n,l) -> idref id (Ast.Meta (n, aux_context l))
194     | Cic.ASort (id,Cic.Prop) -> idref id (Ast.Sort `Prop)
195     | Cic.ASort (id,Cic.Set) -> idref id (Ast.Sort `Set)
196     | Cic.ASort (id,Cic.Type _) -> idref id (Ast.Sort `Type)
197     | Cic.ASort (id,Cic.CProp) -> idref id (Ast.Sort `CProp)
198     | Cic.AImplicit _ -> assert false
199     | Cic.AProd (id,n,s,t) ->
200         let binder_kind =
201           match sort_of_id id with
202           | `Set | `Type -> `Pi
203           | `Prop | `CProp -> `Forall
204         in
205         idref id (Ast.Binder (binder_kind, (ident_of_name n, Some (k s)), k t))
206     | Cic.ACast (id,v,t) ->
207         idref id (Ast.Appl [idref id (Ast.Symbol ("cast", 0)); k v; k t])
208     | Cic.ALambda (id,n,s,t) ->
209         idref id (Ast.Binder (`Lambda, (ident_of_name n, Some (k s)), k t))
210     | Cic.ALetIn (id,n,s,t) ->
211         idref id (Ast.LetIn ((ident_of_name n, None), k s, k t))
212     | Cic.AAppl (aid,args) -> idref aid (Ast.Appl (List.map k args))
213     | Cic.AConst (id,uri,substs) ->
214         idref id (Ast.Ident (UriManager.name_of_uri uri, aux_substs substs))
215     | Cic.AMutInd (id,uri,i,substs) ->
216         let name = name_of_inductive_type uri i in
217         idref id (Ast.Ident (name, aux_substs substs))
218     | Cic.AMutConstruct (id,uri,i,j,substs) ->
219         let name = constructor_of_inductive_type uri i j in
220         idref id (Ast.Ident (name, aux_substs substs))
221     | Cic.AMutCase (id,uri,typeno,ty,te,patterns) ->
222         let name = name_of_inductive_type uri typeno in
223         let constructors = constructors_of_inductive_type uri typeno in
224         let rec eat_branch ty pat =
225           match (ty, pat) with
226           | Cic.Prod (_, _, t), Cic.ALambda (_, name, s, t') ->
227               let (cv, rhs) = eat_branch t t' in
228               (ident_of_name name, Some (k s)) :: cv, rhs
229           | _, _ -> [], k pat
230         in
231         let patterns =
232           List.map2
233             (fun (name, ty) pat ->
234               let (capture_variables, rhs) = eat_branch ty pat in
235               ((name, capture_variables), rhs))
236             constructors patterns
237         in
238         idref id (Ast.Case (k te, Some name, Some (k ty), patterns))
239     | Cic.AFix (id, no, funs) -> 
240         let defs = 
241           List.map
242             (fun (_, n, decr_idx, ty, bo) ->
243               ((Ast.Ident (n, None), Some (k ty)), k bo, decr_idx))
244             funs
245         in
246         let name =
247           try
248             (match List.nth defs no with
249             | (Ast.Ident (n, _), _), _, _ when n <> "_" -> n
250             | _ -> assert false)
251           with Not_found -> assert false
252         in
253         idref id (Ast.LetRec (`Inductive, defs, Ast.Ident (name, None)))
254     | Cic.ACoFix (id, no, funs) -> 
255         let defs = 
256           List.map
257             (fun (_, n, ty, bo) -> ((Ast.Ident (n, None), Some (k ty)), k bo, 0))
258             funs
259         in
260         let name =
261           try
262             (match List.nth defs no with
263             | (Ast.Ident (n, _), _), _, _ when n <> "_" -> n
264             | _ -> assert false)
265           with Not_found -> assert false
266         in
267         idref id (Ast.LetRec (`CoInductive, defs, Ast.Ident (name, None)))
268   in
269   aux acic
270
271   (* "envl" is a list of triples:
272    *   <name environment, term environment, pattern id>, where
273    *   name environment: (string * string) list
274    *   term environment: (string * Cic.annterm) list *)
275 let return_closure success_k =
276   (fun term_info terms envl ->
277     match terms with
278     | [] ->
279         (try
280           success_k term_info (List.hd envl)
281         with Failure _ -> assert false)
282     | _ -> assert false)
283
284 let variable_closure names k =
285   (fun term_info terms envl ->
286     match terms with
287     | hd :: tl ->
288         let envl' =
289           List.map2
290             (fun arg (name_env, term_env, pid) ->
291               let rec aux name_env term_env pid arg term =
292                 match arg, term with
293                   Ast.IdentArg name, _ ->
294                     (name_env, (name, term) :: term_env, pid)
295                 | Ast.EtaArg (Some name, arg'),
296                   Cic.ALambda (_, name', ty, body) ->
297                     aux ((name, (string_of_name name', Some ty)) :: name_env)
298                       term_env pid arg' body
299                 | Ast.EtaArg (Some name, arg'), _ ->
300                     let name' = CicNotationUtil.fresh_name () in
301                     aux ((name, (name', None)) :: name_env)
302                       term_env pid arg' term
303                 | Ast.EtaArg (None, arg'), Cic.ALambda (_, name, ty, body) ->
304                     assert false
305                 | Ast.EtaArg (None, arg'), _ ->
306                     assert false
307               in
308                 aux name_env term_env pid arg hd)
309             names envl
310         in
311         k term_info tl envl'
312     | _ -> assert false)
313
314 let appl_closure ks k =
315   (fun term_info terms envl ->
316     (match terms with
317     | Cic.AAppl (_, args) :: tl ->
318         (try
319           let k' = List.assoc (List.length args) ks in
320           k' term_info (args @ tl) envl
321         with Not_found -> k term_info terms envl)
322     | [] -> assert false
323     | _ -> k term_info terms envl))
324
325 let uri_of_term t = CicUtil.uri_of_term (Deannotate.deannotate_term t)
326
327 let uri_closure ks k =
328   (fun term_info terms envl ->
329     (match terms with
330     | [] -> assert false
331     | hd :: tl ->
332         begin
333           try
334             let k' = List.assoc (uri_of_term hd) ks in
335             k' term_info tl envl
336           with
337           | Invalid_argument _  (* raised by uri_of_term *)
338           | Not_found -> k term_info terms envl
339         end))
340
341   (* compiler from level 3 to level 2 *)
342 let compiler32 (t: Patterns.t) success_k fail_k =
343   let rec aux t k = (* k is a continuation *)
344     if t = [] then
345       k
346     else if Patterns.are_empty t then begin
347       (match t with
348       | _::_::_ -> warning "Ambiguous patterns"
349       | _ -> ());
350       return_closure success_k
351     end else
352       match Patterns.horizontal_split t with
353       | t', [] ->
354           (match t' with
355           | []
356           | ([], _) :: _ -> assert false
357           | (Ast.ArgPattern (Ast.IdentArg _) :: _, _) :: _
358           | (Ast.ArgPattern (Ast.EtaArg _) :: _, _) :: _ ->
359               let first_column, t'' = Patterns.vertical_split t' in
360               let names =
361                 List.map
362                   (function
363                     | Ast.ArgPattern arg -> arg
364                     | _ -> assert false)
365                   first_column
366               in
367               variable_closure names (aux t'' k)
368           | (Ast.ApplPattern _ :: _, _) :: _ ->
369               let pidl =
370                 List.map
371                   (function
372                     | (Ast.ApplPattern args) :: _, _ -> List.length args
373                     | _ -> assert false)
374                   t'
375               in
376                 (* arity partitioning *)
377               let clusters = Patterns.partition t' pidl in
378               let ks =  (* k continuation list *)
379                 List.map
380                   (fun (len, cluster) ->
381                     let cluster' =
382                       List.map  (* add args as patterns heads *)
383                         (function
384                           | (Ast.ApplPattern args) :: tl, pid ->
385                               (* let's throw away "teste di cluster" *)
386                               args @ tl, pid
387                           | _ -> assert false)
388                         cluster
389                     in
390                     len, aux cluster' k)
391                   clusters
392               in
393               appl_closure ks k
394           | (Ast.UriPattern _ :: _, _) :: _ ->
395               let uidmap, pidl =
396                 let urimap = ref [] in
397                 let uidmap = ref [] in
398                 let get_uri_id uri =
399                   try
400                     List.assoc uri !urimap
401                   with
402                     Not_found ->
403                       let uid = List.length !urimap in
404                       urimap := (uri, uid) :: !urimap ;
405                       uidmap := (uid, uri) :: !uidmap ;
406                       uid
407                 in
408                 let uidl =
409                   List.map
410                     (function
411                       | (Ast.UriPattern uri) :: _, _ -> get_uri_id uri
412                       | _ -> assert false)
413                     t'
414                 in
415                   !uidmap, uidl
416               in
417               let clusters = Patterns.partition t' pidl in
418               let ks =
419                 List.map
420                   (fun (uid, cluster) ->
421                     let cluster' =
422                       List.map
423                         (function
424                         | (Ast.UriPattern uri) :: tl, pid -> tl, pid
425                         | _ -> assert false)
426                       cluster
427                     in
428                     List.assoc uid uidmap, aux cluster' k)
429                   clusters
430               in
431               uri_closure ks k)
432       | t', tl -> aux t' (aux tl k)
433   in
434   let matcher = aux t (fun _ _ -> raise No_match) in
435   (fun term_info annterm ->
436     try
437       matcher term_info [annterm] (List.map (fun (_, pid) -> [], [], pid) t)
438     with No_match -> fail_k term_info annterm)
439
440 let ast_of_acic1 term_info annterm = (get_compiled32 ()) term_info annterm
441
442 let load_patterns t instantiate =
443   let ast_env_of_name_env term_info name_env =
444     List.map
445       (fun (name, (name', ty_opt)) ->
446         let ast_ty_opt =
447           match ty_opt with
448           | None -> None
449           | Some annterm -> Some (ast_of_acic1 term_info annterm)
450         in
451         (name, (name', ast_ty_opt)))
452       name_env
453   in
454   let ast_env_of_term_env term_info =
455     List.map (fun (name, term) -> (name, ast_of_acic1 term_info term))
456   in
457   let fail_k term_info annterm = ast_of_acic0 term_info annterm ast_of_acic1 in
458   let success_k term_info (name_env, term_env, pid) =
459     instantiate
460       term_info
461       (ast_env_of_name_env term_info name_env)
462       (ast_env_of_term_env term_info term_env)
463       pid
464   in
465   let compiled32 = compiler32 t success_k fail_k in
466   set_compiled32 compiled32
467
468 let ast_of_acic id_to_sort annterm =
469   let term_info = { sort = id_to_sort; uri = Hashtbl.create 211 } in
470   let ast = ast_of_acic1 term_info annterm in
471   ast, term_info.uri
472