]> matita.cs.unibo.it Git - helm.git/blob - helm/ocaml/cic_disambiguation/disambiguate.ml
bugfix: removed unneeded No_choices exception
[helm.git] / helm / ocaml / cic_disambiguation / disambiguate.ml
1 (* Copyright (C) 2004, 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 open Printf
27
28 open DisambiguateTypes
29 open UriManager
30
31 exception NoWellTypedInterpretation of string Lazy.t list
32 exception PathNotWellFormed
33
34   (** raised when an environment is not enough informative to decide *)
35 exception Try_again of string Lazy.t
36
37 type aliases = bool * DisambiguateTypes.environment
38
39 let debug = false
40 let debug_print s = if debug then prerr_endline (Lazy.force s) else ()
41
42 (*
43   (** print benchmark information *)
44 let benchmark = true
45 let max_refinements = ref 0       (* benchmarking is not thread safe *)
46 let actual_refinements = ref 0
47 let domain_size = ref 0
48 let choices_avg = ref 0.
49 *)
50
51 let descr_of_domain_item = function
52  | Id s -> s
53  | Symbol (s, _) -> s
54  | Num i -> string_of_int i
55
56 type 'a test_result =
57   | Ok of 'a * Cic.metasenv
58   | Ko of string Lazy.t
59   | Uncertain of string Lazy.t
60
61 let refine_term metasenv context uri term ugraph =
62 (*   if benchmark then incr actual_refinements; *)
63   assert (uri=None);
64     debug_print (lazy (sprintf "TEST_INTERPRETATION: %s" (CicPp.ppterm term)));
65     try
66       let term', _, metasenv',ugraph1 = 
67         CicRefine.type_of_aux' metasenv context term ugraph in
68         (Ok (term', metasenv')),ugraph1
69     with
70       | CicRefine.Uncertain msg ->
71           debug_print (lazy ("UNCERTAIN!!! [" ^ (Lazy.force msg) ^ "] " ^ CicPp.ppterm term)) ;
72           Uncertain (msg (*lazy ("Uncertain trying to refine: " ^ CicMetaSubst.ppterm_in_context [] term context ^ "\n" ^ Lazy.force msg)*)),ugraph
73       | CicRefine.RefineFailure msg ->
74           debug_print (lazy (sprintf "PRUNED!!!\nterm%s\nmessage:%s"
75             (CicPp.ppterm term) (Lazy.force msg)));
76           Ko (msg (*lazy ("Error trying to refine: " ^ CicMetaSubst.ppterm_in_context [] term context ^ "\n" ^ Lazy.force msg)*)),ugraph
77
78 let refine_obj metasenv context uri obj ugraph =
79  assert (context = []);
80    debug_print (lazy (sprintf "TEST_INTERPRETATION: %s" (CicPp.ppobj obj))) ;
81    try
82      let obj', metasenv,ugraph = CicRefine.typecheck metasenv uri obj in
83        (Ok (obj', metasenv)),ugraph
84    with
85      | CicRefine.Uncertain msg ->
86          debug_print (lazy ("UNCERTAIN!!! [" ^ (Lazy.force msg) ^ "] " ^ CicPp.ppobj obj)) ;
87          Uncertain (msg (*lazy ("Uncertain trying to refine: " ^ CicPp.ppobj obj ^ "\n" ^ Lazy.force msg)*)),ugraph
88      | CicRefine.RefineFailure msg ->
89          debug_print (lazy (sprintf "PRUNED!!!\nterm%s\nmessage:%s"
90            (CicPp.ppobj obj) (Lazy.force msg))) ;
91          Ko (msg (*lazy ("Error trying to refine: " ^ CicPp.ppobj obj ^ "\n" ^ Lazy.force msg)*)),ugraph
92
93 let resolve (env: codomain_item Environment.t) (item: domain_item) ?(num = "") ?(args = []) () =
94   try
95     snd (Environment.find item env) env num args
96   with Not_found -> 
97     failwith ("Domain item not found: " ^ 
98       (DisambiguateTypes.string_of_domain_item item))
99
100   (* TODO move it to Cic *)
101 let find_in_context name (context: Cic.name list) =
102   let rec aux acc = function
103     | [] -> raise Not_found
104     | Cic.Name hd :: tl when hd = name -> acc
105     | _ :: tl ->  aux (acc + 1) tl
106   in
107   aux 1 context
108
109 let interpretate_term ~(context: Cic.name list) ~env ~uri ~is_path ast =
110   assert (uri = None);
111   let rec aux loc (context: Cic.name list) = function
112     | CicNotationPt.AttributedTerm (`Loc loc, term) ->
113         aux loc context term
114     | CicNotationPt.AttributedTerm (_, term) -> aux loc context term
115     | CicNotationPt.Appl (CicNotationPt.Symbol (symb, i) :: args) ->
116         let cic_args = List.map (aux loc context) args in
117         resolve env (Symbol (symb, i)) ~args:cic_args ()
118     | CicNotationPt.Appl terms -> Cic.Appl (List.map (aux loc context) terms)
119     | CicNotationPt.Binder (binder_kind, (var, typ), body) ->
120         let cic_type = aux_option loc context (Some `Type) typ in
121         let cic_name = CicNotationUtil.cic_name_of_name var in
122         let cic_body = aux loc (cic_name :: context) body in
123         (match binder_kind with
124         | `Lambda -> Cic.Lambda (cic_name, cic_type, cic_body)
125         | `Pi
126         | `Forall -> Cic.Prod (cic_name, cic_type, cic_body)
127         | `Exists ->
128             resolve env (Symbol ("exists", 0))
129               ~args:[ cic_type; Cic.Lambda (cic_name, cic_type, cic_body) ] ())
130     | CicNotationPt.Case (term, indty_ident, outtype, branches) ->
131         let cic_term = aux loc context term in
132         let cic_outtype = aux_option loc context None outtype in
133         let do_branch ((head, _, args), term) =
134           let rec do_branch' context = function
135             | [] -> aux loc context term
136             | (name, typ) :: tl ->
137                 let cic_name = CicNotationUtil.cic_name_of_name name in
138                 let cic_body = do_branch' (cic_name :: context) tl in
139                 let typ =
140                   match typ with
141                   | None -> Cic.Implicit (Some `Type)
142                   | Some typ -> aux loc context typ
143                 in
144                 Cic.Lambda (cic_name, typ, cic_body)
145           in
146           do_branch' context args
147         in
148         let (indtype_uri, indtype_no) =
149           match indty_ident with
150           | Some (indty_ident, _) ->
151              (match resolve env (Id indty_ident) () with
152               | Cic.MutInd (uri, tyno, _) -> (uri, tyno)
153               | Cic.Implicit _ ->
154                  raise (Try_again (lazy "The type of the term to be matched
155                   is still unknown"))
156               | _ ->
157                 raise (Invalid_choice (lazy "The type of the term to be matched is not (co)inductive!")))
158           | None ->
159               let fst_constructor =
160                 match branches with
161                 | ((head, _, _), _) :: _ -> head
162                 | [] -> raise (Invalid_choice (lazy "The type of the term to be matched is an inductive type without constructors that cannot be determined"))
163               in
164               (match resolve env (Id fst_constructor) () with
165               | Cic.MutConstruct (indtype_uri, indtype_no, _, _) ->
166                   (indtype_uri, indtype_no)
167               | Cic.Implicit _ ->
168                  raise (Try_again (lazy "The type of the term to be matched
169                   is still unknown"))
170               | _ ->
171                 raise (Invalid_choice (lazy "The type of the term to be matched is not (co)inductive!")))
172         in
173         Cic.MutCase (indtype_uri, indtype_no, cic_outtype, cic_term,
174           (List.map do_branch branches))
175     | CicNotationPt.Cast (t1, t2) ->
176         let cic_t1 = aux loc context t1 in
177         let cic_t2 = aux loc context t2 in
178         Cic.Cast (cic_t1, cic_t2)
179     | CicNotationPt.LetIn ((name, typ), def, body) ->
180         let cic_def = aux loc context def in
181         let cic_name = CicNotationUtil.cic_name_of_name name in
182         let cic_def =
183           match typ with
184           | None -> cic_def
185           | Some t -> Cic.Cast (cic_def, aux loc context t)
186         in
187         let cic_body = aux loc (cic_name :: context) body in
188         Cic.LetIn (cic_name, cic_def, cic_body)
189     | CicNotationPt.LetRec (kind, defs, body) ->
190         let context' =
191           List.fold_left
192             (fun acc ((name, _), _, _) ->
193               CicNotationUtil.cic_name_of_name name :: acc)
194             context defs
195         in
196         let cic_body = aux loc context' body in
197         let inductiveFuns =
198           List.map
199             (fun ((name, typ), body, decr_idx) ->
200               let cic_body = aux loc context' body in
201               let cic_type = aux_option loc context (Some `Type) typ in
202               let name =
203                 match CicNotationUtil.cic_name_of_name name with
204                 | Cic.Anonymous ->
205                     CicNotationPt.fail loc
206                       "Recursive functions cannot be anonymous"
207                 | Cic.Name name -> name
208               in
209               (name, decr_idx, cic_type, cic_body))
210             defs
211         in
212         let counter = ref ~-1 in
213         let build_term funs =
214           (* this is the body of the fold_right function below. Rationale: Fix
215            * and CoFix cases differs only in an additional index in the
216            * inductiveFun list, see Cic.term *)
217           match kind with
218           | `Inductive ->
219               (fun (var, _, _, _) cic ->
220                 incr counter;
221                 let fix = Cic.Fix (!counter,funs) in
222                  match cic with
223                     Cic.Rel 1 -> fix
224                   | (Cic.Appl (Cic.Rel 1::l)) ->
225                      (try
226                        let l' =
227                         List.map
228                          (function t ->
229                            let t',subst,metasenv =
230                             CicMetaSubst.delift_rels [] [] 1 t
231                            in
232                             assert (subst=[]);
233                             assert (metasenv=[]);
234                             t') l
235                        in
236                         Cic.Appl (fix::l')
237                       with
238                        CicMetaSubst.DeliftingARelWouldCaptureAFreeVariable ->
239                         Cic.LetIn (Cic.Name var, fix, cic))
240                   | _ -> Cic.LetIn (Cic.Name var, fix, cic))
241           | `CoInductive ->
242               let funs =
243                 List.map (fun (name, _, typ, body) -> (name, typ, body)) funs
244               in
245               (fun (var, _, _, _) cic ->
246                 incr counter;
247                 let cofix = Cic.CoFix (!counter,funs) in
248                  match cic with
249                     Cic.Rel 1 -> cofix
250                   | (Cic.Appl (Cic.Rel 1::l)) -> Cic.Appl (cofix::l)
251                   | _ -> Cic.LetIn (Cic.Name var, cofix, cic))
252         in
253         List.fold_right (build_term inductiveFuns) inductiveFuns cic_body
254     | CicNotationPt.Ident _
255     | CicNotationPt.Uri _ when is_path -> raise PathNotWellFormed
256     | CicNotationPt.Ident (name, subst)
257     | CicNotationPt.Uri (name, subst) as ast ->
258         let is_uri = function CicNotationPt.Uri _ -> true | _ -> false in
259         (try
260           if is_uri ast then raise Not_found;(* don't search the env for URIs *)
261           let index = find_in_context name context in
262           if subst <> None then
263             CicNotationPt.fail loc "Explicit substitutions not allowed here";
264           Cic.Rel index
265         with Not_found ->
266           let cic =
267             if is_uri ast then  (* we have the URI, build the term out of it *)
268               try
269                 CicUtil.term_of_uri (UriManager.uri_of_string name)
270               with UriManager.IllFormedUri _ ->
271                 CicNotationPt.fail loc "Ill formed URI"
272             else
273               resolve env (Id name) ()
274           in
275           let mk_subst uris =
276             let ids_to_uris =
277               List.map (fun uri -> UriManager.name_of_uri uri, uri) uris
278             in
279             (match subst with
280             | Some subst ->
281                 List.map
282                   (fun (s, term) ->
283                     (try
284                       List.assoc s ids_to_uris, aux loc context term
285                      with Not_found ->
286                        raise (Invalid_choice (lazy "The provided explicit named substitution is trying to instantiate a named variable the object is not abstracted on"))))
287                   subst
288             | None -> List.map (fun uri -> uri, Cic.Implicit None) uris)
289           in
290           (try 
291             match cic with
292             | Cic.Const (uri, []) ->
293                 let o,_ = CicEnvironment.get_obj CicUniv.empty_ugraph uri in
294                 let uris = CicUtil.params_of_obj o in
295                 Cic.Const (uri, mk_subst uris)
296             | Cic.Var (uri, []) ->
297                 let o,_ = CicEnvironment.get_obj CicUniv.empty_ugraph uri in
298                 let uris = CicUtil.params_of_obj o in
299                 Cic.Var (uri, mk_subst uris)
300             | Cic.MutInd (uri, i, []) ->
301                (try
302                  let o,_ = CicEnvironment.get_obj CicUniv.empty_ugraph uri in
303                  let uris = CicUtil.params_of_obj o in
304                  Cic.MutInd (uri, i, mk_subst uris)
305                 with
306                  CicEnvironment.Object_not_found _ ->
307                   (* if we are here it is probably the case that during the
308                      definition of a mutual inductive type we have met an
309                      occurrence of the type in one of its constructors.
310                      However, the inductive type is not yet in the environment
311                   *)
312                   (*here the explicit_named_substituion is assumed to be of length 0 *)
313                   Cic.MutInd (uri,i,[]))
314             | Cic.MutConstruct (uri, i, j, []) ->
315                 let o,_ = CicEnvironment.get_obj CicUniv.empty_ugraph uri in
316                 let uris = CicUtil.params_of_obj o in
317                 Cic.MutConstruct (uri, i, j, mk_subst uris)
318             | Cic.Meta _ | Cic.Implicit _ as t ->
319 (*
320                 debug_print (lazy (sprintf
321                   "Warning: %s must be instantiated with _[%s] but we do not enforce it"
322                   (CicPp.ppterm t)
323                   (String.concat "; "
324                     (List.map
325                       (fun (s, term) -> s ^ " := " ^ CicNotationPtPp.pp_term term)
326                       subst))));
327 *)
328                 t
329             | _ ->
330               raise (Invalid_choice (lazy "??? Can this happen?"))
331            with 
332              CicEnvironment.CircularDependency _ -> 
333                raise (Invalid_choice (lazy "Circular dependency in the environment"))))
334     | CicNotationPt.Implicit -> Cic.Implicit None
335     | CicNotationPt.UserInput -> Cic.Implicit (Some `Hole)
336     | CicNotationPt.Num (num, i) -> resolve env (Num i) ~num ()
337     | CicNotationPt.Meta (index, subst) ->
338         let cic_subst =
339           List.map
340             (function None -> None | Some term -> Some (aux loc context term))
341             subst
342         in
343         Cic.Meta (index, cic_subst)
344     | CicNotationPt.Sort `Prop -> Cic.Sort Cic.Prop
345     | CicNotationPt.Sort `Set -> Cic.Sort Cic.Set
346     | CicNotationPt.Sort (`Type u) -> Cic.Sort (Cic.Type u)
347     | CicNotationPt.Sort `CProp -> Cic.Sort Cic.CProp
348     | CicNotationPt.Symbol (symbol, instance) ->
349         resolve env (Symbol (symbol, instance)) ()
350     | _ -> assert false (* god bless Bologna *)
351   and aux_option loc (context: Cic.name list) annotation = function
352     | None -> Cic.Implicit annotation
353     | Some term -> aux loc context term
354   in
355   match ast with
356   | CicNotationPt.AttributedTerm (`Loc loc, term) -> aux loc context term
357   | term -> aux dummy_floc context term
358
359 let interpretate_path ~context path =
360  interpretate_term ~context ~env:Environment.empty ~uri:None ~is_path:true path
361
362 let interpretate_obj ~context ~env ~uri ~is_path obj =
363  assert (context = []);
364  assert (is_path = false);
365  match obj with
366   | CicNotationPt.Inductive (params,tyl) ->
367      let uri = match uri with Some uri -> uri | None -> assert false in
368      let context,params =
369       let context,res =
370        List.fold_left
371         (fun (context,res) (name,t) ->
372           Cic.Name name :: context,
373           (name, interpretate_term context env None false t)::res
374         ) ([],[]) params
375       in
376        context,List.rev res in
377      let add_params =
378       List.fold_right
379        (fun (name,ty) t -> Cic.Prod (Cic.Name name,ty,t)) params in
380      let name_to_uris =
381       snd (
382        List.fold_left
383         (*here the explicit_named_substituion is assumed to be of length 0 *)
384         (fun (i,res) (name,_,_,_) ->
385           i + 1,(name,name,Cic.MutInd (uri,i,[]))::res
386         ) (0,[]) tyl) in
387      let con_env = DisambiguateTypes.env_of_list name_to_uris env in
388      let undebrujin t =
389       snd
390        (List.fold_right
391          (fun (name,_,_,_) (i,t) ->
392            (*here the explicit_named_substituion is assumed to be of length 0 *)
393            let t' = Cic.MutInd (uri,i,[])  in
394            let t = CicSubstitution.subst t' t in
395             i - 1,t
396          ) tyl (List.length tyl - 1,t)) in
397      let tyl =
398       List.map
399        (fun (name,b,ty,cl) ->
400          let ty' = add_params (interpretate_term context env None false ty) in
401          let cl' =
402           List.map
403            (fun (name,ty) ->
404              let ty' =
405               add_params (interpretate_term context con_env None false ty)
406              in
407               name,undebrujin ty'
408            ) cl
409          in
410           name,b,ty',cl'
411        ) tyl
412      in
413       Cic.InductiveDefinition (tyl,[],List.length params,[])
414   | CicNotationPt.Record (params,name,ty,fields) ->
415      let uri = match uri with Some uri -> uri | None -> assert false in
416      let context,params =
417       let context,res =
418        List.fold_left
419         (fun (context,res) (name,t) ->
420           (Cic.Name name :: context),
421           (name, interpretate_term context env None false t)::res
422         ) ([],[]) params
423       in
424        context,List.rev res in
425      let add_params =
426       List.fold_right
427        (fun (name,ty) t -> Cic.Prod (Cic.Name name,ty,t)) params in
428      let ty' = add_params (interpretate_term context env None false ty) in
429      let fields' =
430       snd (
431        List.fold_left
432         (fun (context,res) (name,ty) ->
433           let context' = Cic.Name name :: context in
434            context',(name,interpretate_term context env None false ty)::res
435         ) (context,[]) fields) in
436      let concl =
437       (*here the explicit_named_substituion is assumed to be of length 0 *)
438       let mutind = Cic.MutInd (uri,0,[]) in
439       if params = [] then mutind
440       else
441        Cic.Appl
442         (mutind::CicUtil.mk_rels (List.length params) (List.length fields)) in
443      let con =
444       List.fold_left
445        (fun t (name,ty) -> Cic.Prod (Cic.Name name,ty,t))
446        concl fields' in
447      let con' = add_params con in
448      let tyl = [name,true,ty',["mk_" ^ name,con']] in
449      let field_names = List.map fst fields in
450       Cic.InductiveDefinition
451        (tyl,[],List.length params,[`Class (`Record field_names)])
452   | CicNotationPt.Theorem (flavour, name, ty, bo) ->
453      let attrs = [`Flavour flavour] in
454      let ty' = interpretate_term [] env None false ty in
455      (match bo with
456         None ->
457          Cic.CurrentProof (name,[],Cic.Implicit None,ty',[],attrs)
458       | Some bo ->
459          let bo' = Some (interpretate_term [] env None false bo) in
460           Cic.Constant (name,bo',ty',[],attrs))
461           
462
463   (* e.g. [5;1;1;1;2;3;4;1;2] -> [2;1;4;3;5] *)
464 let rev_uniq =
465   let module SortedItem =
466     struct
467       type t = DisambiguateTypes.domain_item
468       let compare = Pervasives.compare
469     end
470   in
471   let module Set = Set.Make (SortedItem) in
472   fun l ->
473     let rev_l = List.rev l in
474     let (_, uniq_rev_l) =
475       List.fold_left
476         (fun (members, rev_l) elt ->
477           if Set.mem elt members then
478             (members, rev_l)
479           else
480             Set.add elt members, elt :: rev_l)
481         (Set.empty, []) rev_l
482     in
483     List.rev uniq_rev_l
484
485 (* "aux" keeps domain in reverse order and doesn't care about duplicates.
486  * Domain item more in deep in the list will be processed first.
487  *)
488 let rec domain_rev_of_term ?(loc = dummy_floc) context = function
489   | CicNotationPt.AttributedTerm (`Loc loc, term) ->
490      domain_rev_of_term ~loc context term
491   | CicNotationPt.AttributedTerm (_, term) ->
492       domain_rev_of_term ~loc context term
493   | CicNotationPt.Appl terms ->
494       List.fold_left
495        (fun dom term -> domain_rev_of_term ~loc context term @ dom) [] terms
496   | CicNotationPt.Binder (kind, (var, typ), body) ->
497       let kind_dom =
498         match kind with
499         | `Exists -> [ Symbol ("exists", 0) ]
500         | _ -> []
501       in
502       let type_dom = domain_rev_of_term_option loc context typ in
503       let body_dom =
504         domain_rev_of_term ~loc
505           (CicNotationUtil.cic_name_of_name var :: context) body
506       in
507       body_dom @ type_dom @ kind_dom
508   | CicNotationPt.Case (term, indty_ident, outtype, branches) ->
509       let term_dom = domain_rev_of_term ~loc context term in
510       let outtype_dom = domain_rev_of_term_option loc context outtype in
511       let get_first_constructor = function
512         | [] -> []
513         | ((head, _, _), _) :: _ -> [ Id head ]
514       in
515       let do_branch ((head, _, args), term) =
516         let (term_context, args_domain) =
517           List.fold_left
518             (fun (cont, dom) (name, typ) ->
519               (CicNotationUtil.cic_name_of_name name :: cont,
520                (match typ with
521                | None -> dom
522                | Some typ -> domain_rev_of_term ~loc cont typ @ dom)))
523             (context, []) args
524         in
525         args_domain @ domain_rev_of_term ~loc term_context term
526       in
527       let branches_dom =
528         List.fold_left (fun dom branch -> do_branch branch @ dom) [] branches
529       in
530       branches_dom @ outtype_dom @ term_dom @
531       (match indty_ident with
532        | None -> get_first_constructor branches
533        | Some (ident, _) -> [ Id ident ])
534   | CicNotationPt.Cast (term, ty) ->
535       let term_dom = domain_rev_of_term ~loc context term in
536       let ty_dom = domain_rev_of_term ~loc context ty in
537       ty_dom @ term_dom
538   | CicNotationPt.LetIn ((var, typ), body, where) ->
539       let body_dom = domain_rev_of_term ~loc context body in
540       let type_dom = domain_rev_of_term_option loc context typ in
541       let where_dom =
542         domain_rev_of_term ~loc
543           (CicNotationUtil.cic_name_of_name var :: context) where
544       in
545       where_dom @ type_dom @ body_dom
546   | CicNotationPt.LetRec (kind, defs, where) ->
547       let context' =
548         List.fold_left
549           (fun acc ((var, typ), _, _) ->
550             CicNotationUtil.cic_name_of_name var :: acc)
551           context defs
552       in
553       let where_dom = domain_rev_of_term ~loc context' where in
554       let defs_dom =
555         List.fold_left
556           (fun dom ((_, typ), body, _) ->
557             domain_rev_of_term ~loc context' body @
558             domain_rev_of_term_option loc context typ)
559           [] defs
560       in
561       where_dom @ defs_dom
562   | CicNotationPt.Ident (name, subst) ->
563       (try
564         let index = find_in_context name context in
565         if subst <> None then
566           CicNotationPt.fail loc "Explicit substitutions not allowed here"
567         else
568           []
569       with Not_found ->
570         (match subst with
571         | None -> [Id name]
572         | Some subst ->
573             List.fold_left
574               (fun dom (_, term) ->
575                 let dom' = domain_rev_of_term ~loc context term in
576                 dom' @ dom)
577               [Id name] subst))
578   | CicNotationPt.Uri _ -> []
579   | CicNotationPt.Implicit -> []
580   | CicNotationPt.Num (num, i) -> [ Num i ]
581   | CicNotationPt.Meta (index, local_context) ->
582       List.fold_left
583        (fun dom term -> domain_rev_of_term_option loc context term @ dom) []
584         local_context
585   | CicNotationPt.Sort _ -> []
586   | CicNotationPt.Symbol (symbol, instance) -> [ Symbol (symbol, instance) ]
587   | CicNotationPt.UserInput
588   | CicNotationPt.Literal _
589   | CicNotationPt.Layout _
590   | CicNotationPt.Magic _
591   | CicNotationPt.Variable _ -> assert false
592
593 and domain_rev_of_term_option loc context = function
594   | None -> []
595   | Some t -> domain_rev_of_term ~loc context t
596
597 let domain_of_term ~context ast = rev_uniq (domain_rev_of_term context ast)
598
599 let domain_of_obj ~context ast =
600  assert (context = []);
601  let domain_rev =
602   match ast with
603    | CicNotationPt.Theorem (_,_,ty,bo) ->
604       (match bo with
605           None -> []
606         | Some bo -> domain_rev_of_term [] bo) @
607       domain_of_term [] ty
608    | CicNotationPt.Inductive (params,tyl) ->
609       let dom =
610        List.flatten (
611         List.rev_map
612          (fun (_,_,ty,cl) ->
613            List.flatten (
614             List.rev_map
615              (fun (_,ty) -> domain_rev_of_term [] ty) cl) @
616             domain_rev_of_term [] ty) tyl) in
617       let dom = 
618        List.fold_left
619         (fun dom (_,ty) ->
620           domain_rev_of_term [] ty @ dom
621         ) dom params
622       in
623        List.filter
624         (fun name ->
625           not (  List.exists (fun (name',_) -> name = Id name') params
626               || List.exists (fun (name',_,_,_) -> name = Id name') tyl)
627         ) dom
628    | CicNotationPt.Record (params,_,ty,fields) ->
629       let dom =
630        List.flatten
631         (List.rev_map (fun (_,ty) -> domain_rev_of_term [] ty) fields) in
632       let dom =
633        List.filter
634         (fun name->
635           not (  List.exists (fun (name',_) -> name = Id name') params
636               || List.exists (fun (name',_) -> name = Id name') fields)
637         ) dom
638       in
639        List.fold_left
640         (fun dom (_,ty) ->
641           domain_rev_of_term [] ty @ dom
642         ) (dom @ domain_rev_of_term [] ty) params
643  in
644   rev_uniq domain_rev
645
646   (* dom1 \ dom2 *)
647 let domain_diff dom1 dom2 =
648 (* let domain_diff = Domain.diff *)
649   let is_in_dom2 =
650     List.fold_left (fun pred elt -> (fun elt' -> elt' = elt || pred elt'))
651       (fun _ -> false) dom2
652   in
653   List.filter (fun elt -> not (is_in_dom2 elt)) dom1
654
655 module type Disambiguator =
656 sig
657   val disambiguate_term :
658     ?fresh_instances:bool ->
659     dbd:HMysql.dbd ->
660     context:Cic.context ->
661     metasenv:Cic.metasenv ->
662     ?initial_ugraph:CicUniv.universe_graph -> 
663     aliases:DisambiguateTypes.environment ->(* previous interpretation status *)
664     universe:DisambiguateTypes.multiple_environment option ->
665     CicNotationPt.term ->
666     ((DisambiguateTypes.domain_item * DisambiguateTypes.codomain_item) list *
667      Cic.metasenv *                  (* new metasenv *)
668      Cic.term*
669      CicUniv.universe_graph) list *  (* disambiguated term *)
670     bool
671
672   val disambiguate_obj :
673     ?fresh_instances:bool ->
674     dbd:HMysql.dbd ->
675     aliases:DisambiguateTypes.environment ->(* previous interpretation status *)
676     universe:DisambiguateTypes.multiple_environment option ->
677     uri:UriManager.uri option ->     (* required only for inductive types *)
678     CicNotationPt.obj ->
679     ((DisambiguateTypes.domain_item * DisambiguateTypes.codomain_item) list *
680      Cic.metasenv *                  (* new metasenv *)
681      Cic.obj *
682      CicUniv.universe_graph) list *  (* disambiguated obj *)
683     bool
684 end
685
686 module Make (C: Callbacks) =
687   struct
688     let choices_of_id dbd id =
689       let uris = Whelp.locate ~dbd id in
690       let uris =
691        match uris with
692         | [] ->
693            [(C.input_or_locate_uri
694             ~title:("URI matching \"" ^ id ^ "\" unknown.") ~id ())]
695         | [uri] -> [uri]
696         | _ ->
697             C.interactive_user_uri_choice ~selection_mode:`MULTIPLE
698              ~ok:"Try selected." ~enable_button_for_non_vars:true
699              ~title:"Ambiguous input." ~id
700              ~msg: ("Ambiguous input \"" ^ id ^
701                 "\". Please, choose one or more interpretations:")
702              uris
703       in
704       List.map
705         (fun uri ->
706           (UriManager.string_of_uri uri,
707            let term =
708              try
709                CicUtil.term_of_uri uri
710              with exn ->
711                debug_print (lazy (UriManager.string_of_uri uri));
712                debug_print (lazy (Printexc.to_string exn));
713                assert false
714             in
715            fun _ _ _ -> term))
716         uris
717
718 let refine_profiler = HExtlib.profile "disambiguate_thing.refine_thing"
719
720     let disambiguate_thing ~dbd ~context ~metasenv
721       ?(initial_ugraph = CicUniv.empty_ugraph) ~aliases ~universe
722       ~uri ~pp_thing ~domain_of_thing ~interpretate_thing ~refine_thing thing
723     =
724       debug_print (lazy "DISAMBIGUATE INPUT");
725       let disambiguate_context =  (* cic context -> disambiguate context *)
726         List.map
727           (function None -> Cic.Anonymous | Some (name, _) -> name)
728           context
729       in
730       debug_print (lazy ("TERM IS: " ^ (pp_thing thing)));
731       let thing_dom = domain_of_thing ~context:disambiguate_context thing in
732       debug_print (lazy (sprintf "DISAMBIGUATION DOMAIN: %s"
733         (string_of_domain thing_dom)));
734 (*
735       debug_print (lazy (sprintf "DISAMBIGUATION ENVIRONMENT: %s"
736         (DisambiguatePp.pp_environment aliases)));
737       debug_print (lazy (sprintf "DISAMBIGUATION UNIVERSE: %s"
738         (match universe with None -> "None" | Some _ -> "Some _")));
739 *)
740       let current_dom =
741         Environment.fold (fun item _ dom -> item :: dom) aliases []
742       in
743       let todo_dom = domain_diff thing_dom current_dom in
744       (* (2) lookup function for any item (Id/Symbol/Num) *)
745       let lookup_choices =
746         let id_choices = Hashtbl.create 1023 in
747         fun item ->
748           let choices =
749             let lookup_in_library () =
750               match item with
751               | Id id -> choices_of_id dbd id
752               | Symbol (symb, _) ->
753                   List.map DisambiguateChoices.mk_choice
754                     (TermAcicContent.lookup_interpretations symb)
755               | Num instance ->
756                   DisambiguateChoices.lookup_num_choices ()
757             in
758             match universe with
759             | None -> lookup_in_library ()
760             | Some e ->
761                 (try
762                   let item =
763                     match item with
764                     | Symbol (symb, _) -> Symbol (symb, 0)
765                     | item -> item
766                   in
767                   Environment.find item e
768                 with Not_found -> [])
769           in
770           choices
771       in
772 (*
773       (* <benchmark> *)
774       let _ =
775         if benchmark then begin
776           let per_item_choices =
777             List.map
778               (fun dom_item ->
779                 try
780                   let len = List.length (lookup_choices dom_item) in
781                   debug_print (lazy (sprintf "BENCHMARK %s: %d"
782                     (string_of_domain_item dom_item) len));
783                   len
784                 with No_choices _ -> 0)
785               thing_dom
786           in
787           max_refinements := List.fold_left ( * ) 1 per_item_choices;
788           actual_refinements := 0;
789           domain_size := List.length thing_dom;
790           choices_avg :=
791             (float_of_int !max_refinements) ** (1. /. float_of_int !domain_size)
792         end
793       in
794       (* </benchmark> *)
795 *)
796
797       (* (3) test an interpretation filling with meta uninterpreted identifiers
798        *)
799       let test_env aliases todo_dom ugraph = 
800         let filled_env =
801           List.fold_left
802             (fun env item ->
803                Environment.add item
804                ("Implicit",
805                  (match item with
806                     | Id _ | Num _ -> (fun _ _ _ -> Cic.Implicit (Some `Closed))
807                     | Symbol _ -> (fun _ _ _ -> Cic.Implicit None))) env)
808             aliases todo_dom 
809         in
810         try
811           let cic_thing =
812             interpretate_thing ~context:disambiguate_context ~env:filled_env
813              ~uri ~is_path:false thing
814           in
815 let foo () =
816           let k,ugraph1 = refine_thing metasenv context uri cic_thing ugraph in
817             (k , ugraph1 )
818 in refine_profiler.HExtlib.profile foo ()
819         with
820         | Try_again msg -> Uncertain msg, ugraph
821         | Invalid_choice msg -> Ko msg, ugraph
822       in
823       (* (4) build all possible interpretations *)
824       let (@@) (l1,l2) (l1',l2') = l1@l1', l2@l2' in
825       let rec aux aliases diff lookup_in_todo_dom todo_dom base_univ =
826         match todo_dom with
827         | [] ->
828             assert (lookup_in_todo_dom = None);
829             (match test_env aliases [] base_univ with
830             | Ok (thing, metasenv),new_univ -> 
831                [ aliases, diff, metasenv, thing, new_univ ], []
832             | Ko msg,_ | Uncertain msg,_ -> [],[msg])
833         | item :: remaining_dom ->
834             debug_print (lazy (sprintf "CHOOSED ITEM: %s"
835              (string_of_domain_item item)));
836             let choices =
837              match lookup_in_todo_dom with
838                 None -> lookup_choices item
839               | Some choices -> choices in
840             match choices with
841                [] -> [], [lazy ("No choices for " ^ string_of_domain_item item)]
842              | [codomain_item] ->
843                  (* just one choice. We perform a one-step look-up and
844                     if the next set of choices is also a singleton we
845                     skip this refinement step *)
846                  debug_print(lazy (sprintf "%s CHOSEN" (fst codomain_item)));
847                  let new_env = Environment.add item codomain_item aliases in
848                  let new_diff = (item,codomain_item)::diff in
849                  let lookup_in_todo_dom,next_choice_is_single =
850                   match remaining_dom with
851                      [] -> None,false
852                    | he::_ ->
853                       let choices = lookup_choices he in
854                        Some choices,List.length choices = 1
855                  in
856                   if next_choice_is_single then
857                    aux new_env new_diff lookup_in_todo_dom remaining_dom
858                     base_univ
859                   else
860                     (match test_env new_env remaining_dom base_univ with
861                     | Ok (thing, metasenv),new_univ ->
862                         (match remaining_dom with
863                         | [] ->
864                            [ new_env, new_diff, metasenv, thing, new_univ ], []
865                         | _ ->
866                            aux new_env new_diff lookup_in_todo_dom
867                             remaining_dom new_univ)
868                     | Uncertain msg,new_univ ->
869                         (match remaining_dom with
870                         | [] -> [], [msg]
871                         | _ ->
872                            aux new_env new_diff lookup_in_todo_dom
873                             remaining_dom new_univ)
874                     | Ko msg,_ -> [], [msg])
875              | _::_ ->
876                let rec filter univ = function 
877                 | [] -> [],[]
878                 | codomain_item :: tl ->
879                     debug_print(lazy (sprintf "%s CHOSEN" (fst codomain_item)));
880                     let new_env = Environment.add item codomain_item aliases in
881                     let new_diff = (item,codomain_item)::diff in
882                     (match test_env new_env remaining_dom univ with
883                     | Ok (thing, metasenv),new_univ ->
884                         (match remaining_dom with
885                         | [] -> [ new_env, new_diff, metasenv, thing, new_univ ], []
886                         | _ -> aux new_env new_diff None remaining_dom new_univ
887                         ) @@ 
888                           filter univ tl
889                     | Uncertain msg,new_univ ->
890                         (match remaining_dom with
891                         | [] -> [],[msg]
892                         | _ -> aux new_env new_diff None remaining_dom new_univ
893                         ) @@ 
894                           filter univ tl
895                     | Ko msg,_ -> ([],[msg]) @@ filter univ tl)
896                in
897                 filter base_univ choices
898       in
899       let base_univ = initial_ugraph in
900       try
901         let res =
902          match aux aliases [] None todo_dom base_univ with
903          | [],errors -> raise (NoWellTypedInterpretation errors)
904          | [_,diff,metasenv,t,ugraph],_ ->
905              debug_print (lazy "SINGLE INTERPRETATION");
906              [diff,metasenv,t,ugraph], false
907          | l,_ ->
908              debug_print (lazy (sprintf "MANY INTERPRETATIONS (%d)" (List.length l)));
909              let choices =
910                List.map
911                  (fun (env, _, _, _, _) ->
912                    List.map
913                      (fun domain_item ->
914                        let description =
915                          fst (Environment.find domain_item env)
916                        in
917                        (descr_of_domain_item domain_item, description))
918                      thing_dom)
919                  l
920              in
921              let choosed = C.interactive_interpretation_choice choices in
922              (List.map (fun n->let _,d,m,t,u= List.nth l n in d,m,t,u) choosed),
923               true
924         in
925          res
926      with
927       CicEnvironment.CircularDependency s -> 
928         failwith "Disambiguate: circular dependency"
929
930     let disambiguate_term ?(fresh_instances=false) ~dbd ~context ~metasenv
931       ?(initial_ugraph = CicUniv.empty_ugraph) ~aliases ~universe term
932     =
933       let term =
934         if fresh_instances then CicNotationUtil.freshen_term term else term
935       in
936       disambiguate_thing ~dbd ~context ~metasenv ~initial_ugraph ~aliases
937         ~universe ~uri:None ~pp_thing:CicNotationPp.pp_term
938         ~domain_of_thing:domain_of_term ~interpretate_thing:interpretate_term
939         ~refine_thing:refine_term term
940
941     let disambiguate_obj ?(fresh_instances=false) ~dbd ~aliases ~universe ~uri
942      obj
943     =
944       let obj =
945         if fresh_instances then CicNotationUtil.freshen_obj obj else obj
946       in
947       disambiguate_thing ~dbd ~context:[] ~metasenv:[] ~aliases ~universe ~uri
948         ~pp_thing:CicNotationPp.pp_obj ~domain_of_thing:domain_of_obj
949         ~interpretate_thing:interpretate_obj ~refine_thing:refine_obj
950         obj
951   end
952