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