1 (* Copyright (C) 2004-2005, HELM Team.
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.
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.
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.
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,
22 * For details, see the HELM World-Wide-Web page,
23 * http://helm.cs.unibo.it/
29 type interpretation_id = pattern_id
32 { sort: (Cic.id, CicNotationPt.sort_kind) Hashtbl.t;
33 uri: (Cic.id, string) Hashtbl.t;
41 let compare (x1:t) (x2:t) = Pervasives.compare x2 x1 (* reverse order *)
44 module IntSet = Set.Make (OrderedInt)
46 let int_set_of_int_list l =
47 List.fold_left (fun acc i -> IntSet.add i acc) IntSet.empty l
49 let warning s = prerr_endline ("CicNotation WARNING: " ^ s)
53 type row_t = CicNotationPt.cic_appl_pattern list * pattern_id
58 let first_column t = List.map (fun (patterns, _) -> List.hd patterns) t
59 let pattern_ids t = List.map snd t
61 let prepend_column t column =
63 List.map2 (fun elt (pl, pid) -> (elt :: pl), pid) column t
65 with Invalid_argument _ -> assert false
67 let prepend_columns t columns =
69 (fun column rows -> prepend_column rows column)
72 let partition t pidl =
73 let partitions = Hashtbl.create 11 in
74 let add pid row = Hashtbl.add partitions pid row in
77 with Invalid_argument _ -> assert false);
78 let pidset = int_set_of_int_list pidl in
81 match Hashtbl.find_all partitions pid with
83 | patterns -> (pid, List.rev patterns) :: acc)
86 let are_empty t = fst (List.hd t) = []
87 (* if first row has an empty list of patterns, then others will as well *)
89 (* return 2 lists of rows, first one containing homogeneous rows according
90 * to "compatible" below *)
91 let horizontal_split t =
92 let compatible ap1 ap2 =
94 | CicNotationPt.UriPattern _, CicNotationPt.UriPattern _
95 | CicNotationPt.ArgPattern _, CicNotationPt.ArgPattern _
96 | CicNotationPt.ApplPattern _, CicNotationPt.ApplPattern _ -> true
103 assert false (* are_empty should have been invoked in advance *)
104 | (hd :: _ , _) :: _ -> hd
106 let rec aux prev_t = function
107 | [] -> List.rev prev_t, []
108 | ([], _) :: _ -> assert false
109 | (((hd :: _), _) as row) :: tl when compatible ap hd ->
110 aux (row :: prev_t) tl
111 | t -> List.rev prev_t, t
115 (* return 2 lists, first one representing first column, second one
116 * representing rows stripped of the first element *)
117 let vertical_split t =
121 | (hd :: tl, pid) -> hd, (tl, pid)
128 (* acic -> ast auxiliary function s *)
131 let o,_ = CicEnvironment.get_obj CicUniv.empty_ugraph uri in
133 | Cic.InductiveDefinition (l,_,_,_) -> l
136 let name_of_inductive_type uri i =
137 let types = get_types uri in
138 let (name, _, _, _) = try List.nth types i with Not_found -> assert false in
141 (* returns <name, type> pairs *)
142 let constructors_of_inductive_type uri i =
143 let types = get_types uri in
144 let (_, _, _, constructors) =
145 try List.nth types i with Not_found -> assert false
149 (* returns name only *)
150 let constructor_of_inductive_type uri i j =
152 fst (List.nth (constructors_of_inductive_type uri i) (j-1))
153 with Not_found -> assert false)
155 module Ast = CicNotationPt
157 let string_of_name = function
159 | Cic.Anonymous -> "_"
161 let ident_of_name n = Ast.Ident (string_of_name n, None)
163 let idref id t = Ast.AttributedTerm (`IdRef id, t)
165 let ast_of_acic0 term_info acic k =
166 (* prerr_endline "ast_of_acic0"; *)
167 let k = k term_info in
168 let register_uri id uri = Hashtbl.add term_info.uri id uri in
171 Hashtbl.find term_info.sort id
172 with Not_found -> assert false
174 let aux_substs substs =
177 (fun (uri, annterm) -> (UriManager.name_of_uri uri, k annterm))
180 let aux_context context =
184 | Some annterm -> Some (k annterm))
188 | Cic.ARel (id,_,_,b) -> idref id (Ast.Ident (b, None))
189 | Cic.AVar (id,uri,substs) ->
190 register_uri id (UriManager.string_of_uri uri);
191 idref id (Ast.Ident (UriManager.name_of_uri uri, aux_substs substs))
192 | Cic.AMeta (id,n,l) -> idref id (Ast.Meta (n, aux_context l))
193 | Cic.ASort (id,Cic.Prop) -> idref id (Ast.Sort `Prop)
194 | Cic.ASort (id,Cic.Set) -> idref id (Ast.Sort `Set)
195 | Cic.ASort (id,Cic.Type _) -> idref id (Ast.Sort `Type)
196 | Cic.ASort (id,Cic.CProp) -> idref id (Ast.Sort `CProp)
197 | Cic.AImplicit _ -> assert false
198 | Cic.AProd (id,n,s,t) ->
200 match sort_of_id id with
201 | `Set | `Type -> `Pi
202 | `Prop | `CProp -> `Forall
204 idref id (Ast.Binder (binder_kind, (ident_of_name n, Some (k s)), k t))
205 | Cic.ACast (id,v,t) ->
206 idref id (Ast.Appl [idref id (Ast.Symbol ("cast", 0)); k v; k t])
207 | Cic.ALambda (id,n,s,t) ->
208 idref id (Ast.Binder (`Lambda, (ident_of_name n, Some (k s)), k t))
209 | Cic.ALetIn (id,n,s,t) ->
210 idref id (Ast.LetIn ((ident_of_name n, None), k s, k t))
211 | Cic.AAppl (aid,args) -> idref aid (Ast.Appl (List.map k args))
212 | Cic.AConst (id,uri,substs) ->
213 register_uri id (UriManager.string_of_uri uri);
214 idref id (Ast.Ident (UriManager.name_of_uri uri, aux_substs substs))
215 | Cic.AMutInd (id,uri,i,substs) as t ->
216 let name = name_of_inductive_type uri i in
217 let uri_str = UriManager.string_of_uri uri in
219 uri_str ^ "#xpointer(1/" ^ (string_of_int (i + 1)) ^ ")"
221 register_uri id puri_str;
222 idref id (Ast.Ident (name, aux_substs substs))
223 | Cic.AMutConstruct (id,uri,i,j,substs) ->
224 let name = constructor_of_inductive_type uri i j in
225 let uri_str = UriManager.string_of_uri uri in
226 let puri_str = sprintf "%s#xpointer(1/%d/%d)" uri_str (i + 1) j in
227 register_uri id puri_str;
228 idref id (Ast.Ident (name, aux_substs substs))
229 | Cic.AMutCase (id,uri,typeno,ty,te,patterns) ->
230 let name = name_of_inductive_type uri typeno in
231 let constructors = constructors_of_inductive_type uri typeno in
232 let rec eat_branch ty pat =
234 | Cic.Prod (_, _, t), Cic.ALambda (_, name, s, t') ->
235 let (cv, rhs) = eat_branch t t' in
236 (ident_of_name name, Some (k s)) :: cv, rhs
241 (fun (name, ty) pat ->
242 let (capture_variables, rhs) = eat_branch ty pat in
243 ((name, capture_variables), rhs))
244 constructors patterns
246 idref id (Ast.Case (k te, Some name, Some (k ty), patterns))
247 | Cic.AFix (id, no, funs) ->
250 (fun (_, n, decr_idx, ty, bo) ->
251 ((Ast.Ident (n, None), Some (k ty)), k bo, decr_idx))
256 (match List.nth defs no with
257 | (Ast.Ident (n, _), _), _, _ when n <> "_" -> n
259 with Not_found -> assert false
261 idref id (Ast.LetRec (`Inductive, defs, Ast.Ident (name, None)))
262 | Cic.ACoFix (id, no, funs) ->
265 (fun (_, n, ty, bo) -> ((Ast.Ident (n, None), Some (k ty)), k bo, 0))
270 (match List.nth defs no with
271 | (Ast.Ident (n, _), _), _, _ when n <> "_" -> n
273 with Not_found -> assert false
275 idref id (Ast.LetRec (`CoInductive, defs, Ast.Ident (name, None)))
279 (* persistent state *)
281 let level2_patterns = Hashtbl.create 211
283 let (compiled32: (term_info -> Cic.annterm -> CicNotationPt.term) option ref) =
286 let pattern_matrix = ref Patterns.empty
288 let get_compiled32 () =
289 match !compiled32 with
290 | None -> assert false
293 let set_compiled32 f = compiled32 := Some f
295 (* "envl" is a list of triples:
296 * <name environment, term environment, pattern id>, where
297 * name environment: (string * string) list
298 * term environment: (string * Cic.annterm) list *)
299 let return_closure success_k =
300 (fun term_info terms envl ->
301 (* prerr_endline "return_closure"; *)
305 success_k term_info (List.hd envl)
306 with Failure _ -> assert false)
309 let variable_closure names k =
310 (fun term_info terms envl ->
311 (* prerr_endline "variable_closure"; *)
316 (fun arg (name_env, term_env, pid) ->
317 let rec aux name_env term_env pid arg term =
319 Ast.IdentArg name, _ ->
320 (name_env, (name, term) :: term_env, pid)
321 | Ast.EtaArg (Some name, arg'),
322 Cic.ALambda (id, name', ty, body) ->
324 ((name, (string_of_name name', Some (ty, id))) :: name_env)
325 term_env pid arg' body
326 | Ast.EtaArg (Some name, arg'), _ ->
327 let name' = CicNotationUtil.fresh_name () in
328 aux ((name, (name', None)) :: name_env)
329 term_env pid arg' term
330 | Ast.EtaArg (None, arg'), Cic.ALambda (id, name, ty, body) ->
332 | Ast.EtaArg (None, arg'), _ ->
335 aux name_env term_env pid arg hd)
341 let appl_closure ks k =
342 (fun term_info terms envl ->
343 (* prerr_endline "appl_closure"; *)
345 | Cic.AAppl (_, args) :: tl ->
347 let k' = List.assoc (List.length args) ks in
348 k' term_info (args @ tl) envl
349 with Not_found -> k term_info terms envl)
351 | _ -> k term_info terms envl))
353 let uri_of_term t = CicUtil.uri_of_term (Deannotate.deannotate_term t)
355 let uri_closure ks k =
356 (fun term_info terms envl ->
357 (* prerr_endline "uri_closure"; *)
361 (* prerr_endline (sprintf "uri_of_term = %s" (uri_of_term hd)); *)
364 let k' = List.assoc (uri_of_term hd) ks in
367 | Invalid_argument _ (* raised by uri_of_term *)
368 | Not_found -> k term_info terms envl
371 (* compiler from level 3 to level 2 *)
372 let compiler32 (t: Patterns.t) success_k fail_k =
373 let rec aux t k = (* k is a continuation *)
376 else if Patterns.are_empty t then begin
379 (* optimization possible here: throw away all except one of the rules
380 * which lead to ambiguity *)
381 warning "Ambiguous patterns"
383 return_closure success_k
385 match Patterns.horizontal_split t with
389 | ([], _) :: _ -> assert false
390 | (Ast.ArgPattern (Ast.IdentArg _) :: _, _) :: _
391 | (Ast.ArgPattern (Ast.EtaArg _) :: _, _) :: _ ->
392 let first_column, t'' = Patterns.vertical_split t' in
396 | Ast.ArgPattern arg -> arg
400 variable_closure names (aux t'' k)
401 | (Ast.ApplPattern _ :: _, _) :: _ ->
405 | (Ast.ApplPattern args) :: _, _ -> List.length args
409 (* arity partitioning *)
410 let clusters = Patterns.partition t' pidl in
411 let ks = (* k continuation list *)
413 (fun (len, cluster) ->
415 List.map (* add args as patterns heads *)
417 | (Ast.ApplPattern args) :: tl, pid ->
418 (* let's throw away "teste di cluster" *)
427 | (Ast.UriPattern _ :: _, _) :: _ ->
429 let urimap = ref [] in
430 let uidmap = ref [] in
433 List.assoc uri !urimap
436 let uid = List.length !urimap in
437 urimap := (uri, uid) :: !urimap ;
438 uidmap := (uid, uri) :: !uidmap ;
444 | (Ast.UriPattern uri) :: _, _ -> get_uri_id uri
450 let clusters = Patterns.partition t' pidl in
453 (fun (uid, cluster) ->
457 | (Ast.UriPattern uri) :: tl, pid -> tl, pid
461 List.assoc uid uidmap, aux cluster' k)
465 | t', tl -> aux t' (aux tl k)
467 let matcher = aux t (fun _ _ -> raise No_match) in
468 (fun term_info annterm ->
470 matcher term_info [annterm] (List.map (fun (_, pid) -> [], [], pid) t)
471 with No_match -> fail_k term_info annterm)
473 let ast_of_acic1 term_info annterm = (get_compiled32 ()) term_info annterm
475 let instantiate term_info name_env term_env pid =
478 Hashtbl.find level2_patterns pid
479 with Not_found -> assert false
481 let rec instantiate_arg = function
482 | Ast.IdentArg name ->
483 (try List.assoc name term_env with Not_found -> assert false)
484 | Ast.EtaArg (None, _) -> assert false (* TODO *)
485 | Ast.EtaArg (Some name, arg) ->
486 let (name', ty_opt) =
487 try List.assoc name name_env with Not_found -> assert false
489 let body = instantiate_arg arg in
490 let name' = Ast.Ident (name', None) in
492 | None -> Ast.Binder (`Lambda, (name', None), body)
494 idref id (Ast.Binder (`Lambda, (name', Some ty), body))
496 let args' = List.map instantiate_arg args in
497 Ast.Appl (Ast.Symbol (symbol, 0) :: args')
499 let load_patterns t =
500 let ast_env_of_name_env term_info name_env =
502 (fun (name, (name', ty_opt)) ->
506 | Some (annterm, id) -> Some (ast_of_acic1 term_info annterm, id)
508 (name, (name', ast_ty_opt)))
511 let ast_env_of_term_env term_info =
512 List.map (fun (name, term) -> (name, ast_of_acic1 term_info term))
514 let fail_k term_info annterm = ast_of_acic0 term_info annterm ast_of_acic1 in
515 let success_k term_info (name_env, term_env, pid) =
518 (ast_env_of_name_env term_info name_env)
519 (ast_env_of_term_env term_info term_env)
522 let compiled32 = compiler32 t success_k fail_k in
523 set_compiled32 compiled32
525 let ast_of_acic id_to_sort annterm =
526 let term_info = { sort = id_to_sort; uri = Hashtbl.create 211 } in
527 let ast = ast_of_acic1 term_info annterm in
531 let counter = ref ~-1 in
536 let add_interpretation (symbol, args) appl_pattern =
537 let id = fresh_id () in
538 Hashtbl.add level2_patterns id (symbol, args);
539 pattern_matrix := ([appl_pattern], id) :: !pattern_matrix;
540 load_patterns !pattern_matrix;
543 exception Interpretation_not_found
545 let remove_interpretation id =
547 Hashtbl.remove level2_patterns id;
548 with Not_found -> raise Interpretation_not_found);
549 pattern_matrix := List.filter (fun (_, id') -> id <> id') !pattern_matrix;
550 load_patterns !pattern_matrix
552 let _ = load_patterns []