]> matita.cs.unibo.it Git - helm.git/blob - helm/ocaml/cic_disambiguation/disambiguate.ml
use get_obj to retrieve cic objects instead of typecheck
[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
34   (** raised when an environment is not enough informative to decide *)
35 exception Try_again
36
37 let debug = true
38 let debug_print = if debug then prerr_endline else ignore
39
40 let descr_of_domain_item = function
41  | Id s -> s
42  | Symbol (s, _) -> s
43  | Num i -> string_of_int i
44
45 type test_result =
46   | Ok of Cic.term * Cic.metasenv
47   | Ko
48   | Uncertain
49
50 let refine metasenv context term =
51   let metasenv, term = CicMkImplicit.expand_implicits metasenv context term in
52   debug_print (sprintf "TEST_INTERPRETATION: %s" (CicPp.ppterm term));
53   try
54     let term', _, metasenv' = CicRefine.type_of_aux' metasenv context term in
55     Ok (term', metasenv')
56   with
57     | CicRefine.Uncertain _ ->
58         debug_print ("%%% UNCERTAIN!!! " ^ CicPp.ppterm term) ;
59         Uncertain
60     | CicRefine.RefineFailure _ ->
61         debug_print ("%%% PRUNED!!! " ^ CicPp.ppterm term) ;
62         Ko
63
64 let resolve (env: environment) (item: domain_item) ?(num = "") ?(args = []) () =
65   try
66     snd (Environment.find item env) env num args
67   with Not_found -> assert false
68
69   (* TODO move it to Cic *)
70 let find_in_environment name context =
71   let rec aux acc = function
72     | [] -> raise Not_found
73     | Cic.Name hd :: tl when hd = name -> acc
74     | _ :: tl ->  aux (acc + 1) tl
75   in
76   aux 1 context
77
78 let interpretate ~context ~env ast =
79   let rec aux loc context = function
80     | CicAst.AttributedTerm (`Loc loc, term) ->
81         aux loc context term
82     | CicAst.AttributedTerm (_, term) -> aux loc context term
83     | CicAst.Appl (CicAst.Symbol (symb, i) :: args) ->
84         let cic_args = List.map (aux loc context) args in
85         resolve env (Symbol (symb, i)) ~args:cic_args ()
86     | CicAst.Appl terms -> Cic.Appl (List.map (aux loc context) terms)
87     | CicAst.Binder (binder_kind, (var, typ), body) ->
88         let cic_type = aux_option loc context typ in
89         let cic_body = aux loc (var :: context) body in
90         (match binder_kind with
91         | `Lambda -> Cic.Lambda (var, cic_type, cic_body)
92         | `Pi | `Forall -> Cic.Prod (var, cic_type, cic_body)
93         | `Exists ->
94             resolve env (Symbol ("exists", 0))
95               ~args:[ cic_type; Cic.Lambda (var, cic_type, cic_body) ] ())
96     | CicAst.Case (term, indty_ident, outtype, branches) ->
97         let cic_term = aux loc context term in
98         let cic_outtype = aux_option loc context outtype in
99         let do_branch ((head, args), term) =
100           let rec do_branch' context = function
101             | [] -> aux loc context term
102             | (name, typ) :: tl ->
103                 let cic_body = do_branch' (name :: context) tl in
104                 let typ =
105                   match typ with
106                   | None -> Cic.Implicit (Some `Type)
107                   | Some typ -> aux loc context typ
108                 in
109                 Cic.Lambda (name, typ, cic_body)
110           in
111           do_branch' context args
112         in
113         let (indtype_uri, indtype_no) =
114           match indty_ident with
115           | Some indty_ident ->
116               (match resolve env (Id indty_ident) () with
117               | Cic.MutInd (uri, tyno, _) -> (uri, tyno)
118               | Cic.Implicit _ -> raise Try_again
119               | _ -> raise DisambiguateChoices.Invalid_choice)
120           | None ->
121               let fst_constructor =
122                 match branches with
123                 | ((head, _), _) :: _ -> head
124                 | [] -> raise DisambiguateChoices.Invalid_choice
125               in
126               (match resolve env (Id fst_constructor) () with
127               | Cic.MutConstruct (indtype_uri, indtype_no, _, _) ->
128                   (indtype_uri, indtype_no)
129               | Cic.Implicit _ -> raise Try_again
130               | _ -> raise DisambiguateChoices.Invalid_choice)
131         in
132         Cic.MutCase (indtype_uri, indtype_no, cic_outtype, cic_term,
133           (List.map do_branch branches))
134     | CicAst.LetIn ((name, typ), def, body) ->
135         let cic_def = aux loc context def in
136         let cic_def =
137           match typ with
138           | None -> cic_def
139           | Some t -> Cic.Cast (cic_def, aux loc context t)
140         in
141         let cic_body = aux loc (name :: context) body in
142         Cic.LetIn (name, cic_def, cic_body)
143     | CicAst.LetRec (kind, defs, body) ->
144         let context' =
145           List.fold_left (fun acc ((name, _), _, _) -> name :: acc)
146             context defs
147         in
148         let cic_body = aux loc context' body in
149         let inductiveFuns =
150           List.map
151             (fun ((name, typ), body, decr_idx) ->
152               let cic_body = aux loc context' body in
153               let cic_type = aux_option loc context typ in
154               let name =
155                 match name with
156                 | Cic.Anonymous ->
157                     CicTextualParser2.fail loc
158                       "Recursive functions cannot be anonymous"
159                 | Cic.Name name -> name
160               in
161               (name, decr_idx, cic_type, cic_body))
162             defs
163         in
164         let counter = ref ~-1 in
165         let build_term funs =
166           (* this is the body of the fold_right function below. Rationale: Fix
167            * and CoFix cases differs only in an additional index in the
168            * inductiveFun list, see Cic.term *)
169           match kind with
170           | `Inductive ->
171               (fun (var, _, _, _) cic ->
172                 incr counter;
173                 Cic.LetIn (Cic.Name var, Cic.Fix (!counter, funs), cic))
174           | `CoInductive ->
175               let funs =
176                 List.map (fun (name, _, typ, body) -> (name, typ, body)) funs
177               in
178               (fun (var, _, _, _) cic ->
179                 incr counter;
180                 Cic.LetIn (Cic.Name var, Cic.CoFix (!counter, funs), cic))
181         in
182         List.fold_right (build_term inductiveFuns) inductiveFuns cic_body
183     | CicAst.Ident (name, subst) ->
184         (try
185           let index = find_in_environment name context in
186           if subst <> None then
187             CicTextualParser2.fail loc
188               "Explicit substitutions not allowed here";
189           Cic.Rel index
190         with Not_found ->
191           let cic = resolve env (Id name) () in
192           let mk_subst uris =
193             let ids_to_uris =
194               List.map (fun uri -> UriManager.name_of_uri uri, uri) uris
195             in
196             (match subst with
197             | Some subst ->
198                 List.map
199                   (fun (s, term) ->
200                     (try
201                       List.assoc s ids_to_uris, aux loc context term
202                      with Not_found ->
203                        raise DisambiguateChoices.Invalid_choice))
204                   subst
205             | None -> List.map (fun uri -> uri, Cic.Implicit None) uris)
206           in
207           (* the try is for CicTypeChecker.typecheck *)
208           (try 
209             match cic with
210             | Cic.Const (uri, []) ->
211                 let uris =
212                   match CicEnvironment.get_obj uri with
213                   (*match CicTypeChecker.typecheck uri with*)
214                   | Cic.Constant (_, _, _, uris) -> uris
215                   | _ -> assert false
216                 in
217                 Cic.Const (uri, mk_subst uris)
218             | Cic.Var (uri, []) ->
219                 let uris =
220                   match CicEnvironment.get_obj uri with
221                   (*match CicTypeChecker.typecheck uri with*)
222                   | Cic.Variable (_, _, _, uris) -> uris
223                   | _ -> assert false
224                 in
225                 Cic.Var (uri, mk_subst uris)
226             | Cic.MutInd (uri, i, []) ->
227                 let uris =
228                   match CicEnvironment.get_obj uri with
229                   (*match CicTypeChecker.typecheck uri with*)
230                   | Cic.InductiveDefinition (_, uris, _) -> uris
231                   | _ -> assert false
232                 in
233                 Cic.MutInd (uri, i, mk_subst uris)
234             | Cic.MutConstruct (uri, i, j, []) ->
235                 let uris =
236                   match CicEnvironment.get_obj uri with
237                   (*match CicTypeChecker.typecheck uri with*)
238                   | Cic.InductiveDefinition (_, uris, _) -> uris
239                   | _ -> assert false
240                 in
241                 Cic.MutConstruct (uri, i, j, mk_subst uris)
242             | Cic.Meta _ | Cic.Implicit _ as t ->
243 (*
244                 prerr_endline (sprintf
245                   "Warning: %s must be instantiated with _[%s] but we do not enforce it"
246                   (CicPp.ppterm t)
247                   (String.concat "; "
248                     (List.map
249                       (fun (s, term) -> s ^ " := " ^ CicAstPp.pp_term term)
250                       subst)));
251 *)
252                 t
253             | _ ->
254               raise DisambiguateChoices.Invalid_choice
255            with 
256              CicEnvironment.CircularDependency _ -> 
257                raise DisambiguateChoices.Invalid_choice))
258     | CicAst.Implicit -> Cic.Implicit None
259     | CicAst.Num (num, i) -> resolve env (Num i) ~num ()
260     | CicAst.Meta (index, subst) ->
261         let cic_subst =
262           List.map
263             (function None -> None | Some term -> Some (aux loc context term))
264             subst
265         in
266         Cic.Meta (index, cic_subst)
267     | CicAst.Sort `Prop -> Cic.Sort Cic.Prop
268     | CicAst.Sort `Set -> Cic.Sort Cic.Set
269     | CicAst.Sort `Type -> Cic.Sort (Cic.Type (CicUniv.fresh())) (* TASSI *)
270     | CicAst.Sort `CProp -> Cic.Sort Cic.CProp
271     | CicAst.Symbol (symbol, instance) ->
272         resolve env (Symbol (symbol, instance)) ()
273   and aux_option loc context = function
274     | None -> Cic.Implicit (Some `Type)
275     | Some term -> aux loc context term
276   in
277   match ast with
278   | CicAst.AttributedTerm (`Loc loc, term) -> aux loc context term
279   | term -> aux (-1, -1) context term
280
281 let domain_of_term ~context ast =
282     (* "aux" keeps domain in reverse order and doesn't care about duplicates.
283      * Domain item more in deep in the list will be processed first.
284      *)
285   let rec aux loc context = function
286     | CicAst.AttributedTerm (`Loc loc, term) -> aux loc context term
287     | CicAst.AttributedTerm (_, term) -> aux loc context term
288     | CicAst.Appl terms ->
289         List.fold_left (fun dom term -> aux loc context term @ dom) [] terms
290     | CicAst.Binder (kind, (var, typ), body) ->
291         let kind_dom =
292           match kind with
293           | `Exists -> [ Symbol ("exists", 0) ]
294           | _ -> []
295         in
296         let type_dom = aux_option loc context typ in
297         let body_dom = aux loc (var :: context) body in
298         body_dom @ type_dom @ kind_dom
299     | CicAst.Case (term, indty_ident, outtype, branches) ->
300         let term_dom = aux loc context term in
301         let outtype_dom = aux_option loc context outtype in
302         let do_branch ((head, args), term) =
303           let (term_context, args_domain) =
304             List.fold_left
305               (fun (cont, dom) (name, typ) ->
306                 (name :: cont,
307                  (match typ with
308                  | None -> dom
309                  | Some typ -> aux loc cont typ @ dom)))
310               (context, []) args
311           in
312           args_domain @ aux loc term_context term
313         in
314         let branches_dom =
315           List.fold_left (fun dom branch -> do_branch branch @ dom) [] branches
316         in
317         branches_dom @ outtype_dom @ term_dom @
318         (match indty_ident with None -> [] | Some ident -> [ Id ident ])
319     | CicAst.LetIn ((var, typ), body, where) ->
320         let body_dom = aux loc context body in
321         let type_dom = aux_option loc context typ in
322         let where_dom = aux loc (var :: context) where in
323         where_dom @ type_dom @ body_dom
324     | CicAst.LetRec (kind, defs, where) ->
325         let context' =
326           List.fold_left (fun acc ((var, typ), _, _) -> var :: acc)
327             context defs
328         in
329         let where_dom = aux loc context' where in
330         let defs_dom =
331           List.fold_left
332             (fun dom ((_, typ), body, _) ->
333               aux loc context' body @ aux_option loc context typ)
334             [] defs
335         in
336         where_dom @ defs_dom
337     | CicAst.Ident (name, subst) ->
338         (try
339           let index = find_in_environment name context in
340           if subst <> None then
341             CicTextualParser2.fail loc
342               "Explicit substitutions not allowed here"
343           else
344             []
345         with Not_found ->
346           (match subst with
347           | None -> [Id name]
348           | Some subst ->
349               List.fold_left
350                 (fun dom (_, term) ->
351                   let dom' = aux loc context term in
352                   dom' @ dom)
353                 [Id name] subst))
354     | CicAst.Implicit -> []
355     | CicAst.Num (num, i) -> [ Num i ]
356     | CicAst.Meta (index, local_context) ->
357         List.fold_left (fun dom term -> aux_option loc context term @ dom) []
358           local_context
359     | CicAst.Sort _ -> []
360     | CicAst.Symbol (symbol, instance) -> [ Symbol (symbol, instance) ]
361
362   and aux_option loc context = function
363     | None -> []
364     | Some t -> aux loc context t
365   in
366
367     (* e.g. [5;1;1;1;2;3;4;1;2] -> [2;1;4;3;5] *)
368   let rev_uniq =
369     let module SortedItem =
370       struct
371         type t = DisambiguateTypes.domain_item
372         let compare = Pervasives.compare
373       end
374     in
375     let module Set = Set.Make (SortedItem) in
376     fun l ->
377       let rev_l = List.rev l in
378       let (_, uniq_rev_l) =
379         List.fold_left
380           (fun (members, rev_l) elt ->
381             if Set.mem elt members then
382               (members, rev_l)
383             else
384               Set.add elt members, elt :: rev_l)
385           (Set.empty, []) rev_l
386       in
387       List.rev uniq_rev_l
388   in
389             
390   rev_uniq
391     (match ast with
392     | CicAst.AttributedTerm (`Loc loc, term) -> aux loc context term
393     | term -> aux (-1, -1) context term)
394
395
396   (* dom1 \ dom2 *)
397 let domain_diff dom1 dom2 =
398 (* let domain_diff = Domain.diff *)
399   let is_in_dom2 =
400     List.fold_left (fun pred elt -> (fun elt' -> elt' = elt || pred elt'))
401       (fun _ -> false) dom2
402   in
403   List.filter (fun elt -> not (is_in_dom2 elt)) dom1
404
405 module Make (C: Callbacks) =
406   struct
407     let choices_of_id mqi_handle id =
408      let query  =  MQueryGenerator.locate id in
409      let result = MQueryInterpreter.execute mqi_handle query in
410      let uris =
411       List.map
412        (function uri,_ ->
413          MQueryMisc.wrong_xpointer_format_from_wrong_xpointer_format' uri
414        ) result in
415       let uris' =
416        match uris with
417         | [] ->
418            [UriManager.string_of_uri (C.input_or_locate_uri
419             ~title:("URI matching \"" ^ id ^ "\" unknown.") ~id ())]
420         | [uri] -> [uri]
421         | _ ->
422             C.interactive_user_uri_choice ~selection_mode:`MULTIPLE
423              ~ok:"Try selected." ~enable_button_for_non_vars:true
424              ~title:"Ambiguous input." ~id
425              ~msg: ("Ambiguous input \"" ^ id ^
426                 "\". Please, choose one or more interpretations:")
427              uris
428       in
429       List.map
430         (fun uri ->
431           (uri,
432            let term =
433              try
434                HelmLibraryObjects.term_of_uri (UriManager.uri_of_string uri)
435              with _ -> assert false
436             in
437            fun _ _ _ -> term))
438         uris'
439
440     let disambiguate_term mqi_handle context metasenv term ~aliases:current_env
441     =
442       debug_print "NEW DISAMBIGUATE INPUT";
443       let disambiguate_context =  (* cic context -> disambiguate context *)
444         List.map
445           (function None -> Cic.Anonymous | Some (name, _) -> name)
446           context
447       in
448       let term_dom = domain_of_term ~context:disambiguate_context term in
449       debug_print (sprintf "DISAMBIGUATION DOMAIN: %s"
450         (string_of_domain term_dom));
451       let current_dom =
452         Environment.fold (fun item _ dom -> item :: dom) current_env []
453       in
454       let todo_dom = domain_diff term_dom current_dom in
455       (* (2) lookup function for any item (Id/Symbol/Num) *)
456       let lookup_choices =
457         let id_choices = Hashtbl.create 1023 in
458         fun item ->
459         let choices =
460           match item with
461           | Id id ->
462               (try
463                 Hashtbl.find id_choices id
464               with Not_found ->
465                 let choices = choices_of_id mqi_handle id in
466                 Hashtbl.add id_choices id choices;
467                 choices)
468           | Symbol (symb, _) -> DisambiguateChoices.lookup_symbol_choices symb
469           | Num instance -> DisambiguateChoices.lookup_num_choices ()
470         in
471         if choices = [] then raise (No_choices item);
472         choices
473       in
474       (* (3) test an interpretation filling with meta uninterpreted identifiers
475        *)
476       let test_env current_env todo_dom univ = 
477         let filled_env =
478           List.fold_left
479             (fun env item ->
480               Environment.add item
481                 ("Implicit",
482                  (match item with
483                  | Id _ | Num _ -> (fun _ _ _ -> Cic.Implicit (Some `Closed))
484                  | Symbol _ -> (fun _ _ _ -> Cic.Implicit None))) env)
485             current_env todo_dom 
486         in
487         try
488           CicUniv.set_working univ; 
489           let cic_term =
490             interpretate ~context:disambiguate_context ~env:filled_env term
491           in
492            let k = refine metasenv context cic_term in
493            let new_univ = CicUniv.get_working () in
494             (k , new_univ )
495         with
496         | Try_again -> Uncertain,univ 
497         | DisambiguateChoices.Invalid_choice -> Ko,univ 
498       in
499       (* (4) build all possible interpretations *)
500       let rec aux current_env todo_dom base_univ =
501         match todo_dom with
502         | [] ->
503             (match test_env current_env [] base_univ with
504             | Ok (term, metasenv),new_univ -> 
505                                [ current_env, metasenv, term, new_univ ]
506             | Ko,_ | Uncertain,_ -> [])
507         | item :: remaining_dom ->
508             debug_print (sprintf "CHOOSED ITEM: %s"
509              (string_of_domain_item item));
510             let choices = lookup_choices item in
511             let rec filter univ = function 
512               | [] -> []
513               | codomain_item :: tl ->
514                   debug_print (sprintf "%s CHOSEN" (fst codomain_item)) ;
515                   let new_env =
516                     Environment.add item codomain_item current_env
517                   in
518                   (match test_env new_env remaining_dom univ with
519                   | Ok (term, metasenv),new_univ ->
520                       (match remaining_dom with
521                       | [] -> [ new_env, metasenv, term, new_univ ]
522                       | _ -> aux new_env remaining_dom new_univ )@ 
523                         filter univ tl
524                   | Uncertain,new_univ ->
525                       (match remaining_dom with
526                       | [] -> []
527                       | _ -> aux new_env remaining_dom new_univ )@ 
528                         filter univ tl
529                   | Ko,_ -> filter univ tl)
530             in
531             filter base_univ choices 
532       in
533        let base_univ = CicUniv.get_working () in
534       try
535        match aux current_env todo_dom base_univ with
536        | [] -> raise NoWellTypedInterpretation
537        | [ e,me,t,u ] as l ->
538            debug_print "UNA SOLA SCELTA";
539            CicUniv.set_working u;
540            [ e,me,t ]
541        | l ->
542            debug_print (sprintf "PIU' SCELTE (%d)" (List.length l));
543            let choices =
544              List.map
545                (fun (env, _, _, _) ->
546                  List.map
547                    (fun domain_item ->
548                      let description =
549                        fst (Environment.find domain_item env)
550                      in
551                      (descr_of_domain_item domain_item, description))
552                    term_dom)
553                l
554            in
555            let choosed = C.interactive_interpretation_choice choices in
556            let l' = List.map (List.nth l) choosed in
557            match l' with
558              [] -> assert false
559            | [e,me,t,u] -> 
560                CicUniv.set_working u;
561                (*CicUniv.print_working_graph ();*)
562                [e,me,t]
563            | hd::tl -> (* ok, testlibrary... cosi' stampa MANY... bah *)
564                List.map (fun (e,me,t,u) -> (e,me,t)) l'
565      with
566       CicEnvironment.CircularDependency s -> 
567         raise (Failure "e chi la becca sta CircularDependency?");
568   end
569