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