]> matita.cs.unibo.it Git - helm.git/blob - helm/ocaml/cic_disambiguation/disambiguate.ml
s/LocatedTerm/AnnotatedTerm + various annotations/
[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     | _ ->
61         debug_print ("%%% PRUNED!!! " ^ CicPp.ppterm term) ;
62         Ko
63
64 let resolve (env: environment) (item: domain_item) ?(num = "") ?(args = []) () =
65   snd (Environment.find item env) env num args
66
67   (* TODO move it to Cic *)
68 let find_in_environment name context =
69   let rec aux acc = function
70     | [] -> raise Not_found
71     | Cic.Name hd :: tl when hd = name -> acc
72     | _ :: tl ->  aux (acc + 1) tl
73   in
74   aux 1 context
75
76 let interpretate ~context ~env ast =
77   let rec aux loc context = function
78     | CicTextualParser2Ast.AttributedTerm (`Loc loc, term) ->
79         aux loc context term
80     | CicTextualParser2Ast.AttributedTerm (_, term) -> aux loc context term
81     | CicTextualParser2Ast.Appl terms ->
82         Cic.Appl (List.map (aux loc context) terms)
83     | CicTextualParser2Ast.Appl_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     | CicTextualParser2Ast.Binder (binder_kind, (var, typ), body) ->
87         let cic_type = aux_option loc context typ in
88         let cic_body = aux loc (var :: context) body in
89         (match binder_kind with
90         | `Lambda -> Cic.Lambda (var, cic_type, cic_body)
91         | `Pi | `Forall -> Cic.Prod (var, cic_type, cic_body)
92         | `Exists ->
93             resolve env (Symbol ("exists", 0))
94               ~args:[ cic_type; Cic.Lambda (var, cic_type, cic_body) ] ())
95     | CicTextualParser2Ast.Case (term, indty_ident, outtype, branches) ->
96         let cic_term = aux loc context term in
97         let cic_outtype = aux_option loc context outtype in
98         let do_branch ((head, args), term) =
99           let rec do_branch' context = function
100             | [] -> aux loc context term
101             | (name, typ) :: tl ->
102                 let cic_body = do_branch' (name :: context) tl in
103                 let typ =
104                   match typ with
105                   | None -> Cic.Implicit
106                   | Some typ -> aux loc context typ
107                 in
108                 Cic.Lambda (name, typ, cic_body)
109           in
110           do_branch' context args
111         in
112         let (indtype_uri, indtype_no) =
113           match resolve env (Id indty_ident) () with
114           | Cic.MutInd (uri, tyno, _) -> uri, tyno
115           | Cic.Implicit -> raise Try_again
116           | _ -> raise DisambiguateChoices.Invalid_choice
117         in
118         Cic.MutCase (indtype_uri, indtype_no, cic_outtype, cic_term,
119           (List.map do_branch branches))
120     | CicTextualParser2Ast.LetIn ((name, typ), def, body) ->
121         let cic_def = aux loc context def in
122         let cic_def =
123           match typ with
124           | None -> cic_def
125           | Some t -> Cic.Cast (cic_def, aux loc context t)
126         in
127         let cic_body = aux loc (name :: context) body in
128         Cic.LetIn (name, cic_def, cic_body)
129     | CicTextualParser2Ast.LetRec (kind, defs, body) ->
130         let context' =
131           List.fold_left (fun acc ((name, _), _, _) -> name :: acc)
132             context defs
133         in
134         let cic_body = aux loc context' body in
135         let inductiveFuns =
136           List.map
137             (fun ((name, typ), body, decr_idx) ->
138               let cic_body = aux loc context' body in
139               let cic_type = aux_option loc context typ in
140               let name =
141                 match name with
142                 | Cic.Anonymous ->
143                     CicTextualParser2.fail loc
144                       "Recursive functions cannot be anonymous"
145                 | Cic.Name name -> name
146               in
147               (name, decr_idx, cic_type, cic_body))
148             defs
149         in
150         let counter = ref ~-1 in
151         let build_term funs =
152           (* this is the body of the fold_right function below. Rationale: Fix
153            * and CoFix cases differs only in an additional index in the
154            * inductiveFun list, see Cic.term *)
155           match kind with
156           | `Inductive ->
157               (fun (var, _, _, _) cic ->
158                 incr counter;
159                 Cic.LetIn (Cic.Name var, Cic.Fix (!counter, funs), cic))
160           | `CoInductive ->
161               let funs =
162                 List.map (fun (name, _, typ, body) -> (name, typ, body)) funs
163               in
164               (fun (var, _, _, _) cic ->
165                 incr counter;
166                 Cic.LetIn (Cic.Name var, Cic.CoFix (!counter, funs), cic))
167         in
168         List.fold_right (build_term inductiveFuns) inductiveFuns cic_body
169     | CicTextualParser2Ast.Ident (name, subst) ->
170         (* TODO hanlde explicit substitutions *)
171         (try
172           let index = find_in_environment name context in
173           if subst <> [] then
174             CicTextualParser2.fail loc
175               "Explicit substitutions not allowed here";
176           Cic.Rel index
177         with Not_found -> resolve env (Id name) ())
178     | CicTextualParser2Ast.Num (num, i) -> resolve env (Num i) ~num ()
179     | CicTextualParser2Ast.Meta (index, subst) ->
180         let cic_subst =
181           List.map
182             (function None -> None | Some term -> Some (aux loc context term))
183             subst
184         in
185         Cic.Meta (index, cic_subst)
186     | CicTextualParser2Ast.Sort `Prop -> Cic.Sort Cic.Prop
187     | CicTextualParser2Ast.Sort `Set -> Cic.Sort Cic.Set
188     | CicTextualParser2Ast.Sort `Type -> Cic.Sort Cic.Type
189     | CicTextualParser2Ast.Sort `CProp -> Cic.Sort Cic.CProp
190   and aux_option loc context = function
191     | None -> Cic.Implicit
192     | Some term -> aux loc context term
193   in
194   match ast with
195   | CicTextualParser2Ast.AttributedTerm (`Loc loc, term) -> aux loc context term
196   | _ -> assert false
197
198 let domain_of_term ~context ast =
199   let rec aux loc context = function
200     | CicTextualParser2Ast.AttributedTerm (`Loc loc, term) ->
201         aux loc context term
202     | CicTextualParser2Ast.AttributedTerm (_, term) -> aux loc context term
203     | CicTextualParser2Ast.Appl terms ->
204         List.fold_left (fun dom term -> Domain.union dom (aux loc context term))
205           Domain.empty terms
206     | CicTextualParser2Ast.Appl_symbol (symb, i, args) ->
207         List.fold_left (fun dom term -> Domain.union dom (aux loc context term))
208           (Domain.singleton (Symbol (symb, i))) args
209     | CicTextualParser2Ast.Binder (_, (var, typ), body) ->
210         let type_dom = aux_option loc context typ in
211         let body_dom = aux loc (var :: context) body in
212         Domain.union type_dom body_dom
213     | CicTextualParser2Ast.Case (term, indty_ident, outtype, branches) ->
214         let term_dom = aux loc context term in
215         let outtype_dom = aux_option loc context outtype in
216         let do_branch ((head, args), term) =
217           let (term_context, args_domain) =
218             List.fold_left
219               (fun (cont, dom) (name, typ) ->
220                 (name :: cont,
221                  (match typ with
222                  | None -> dom
223                  | Some typ -> Domain.union dom (aux loc cont typ))))
224               (context, Domain.empty) args
225           in
226           Domain.union (aux loc term_context term) args_domain
227         in
228         let branches_dom =
229           List.fold_left (fun dom branch -> Domain.union dom (do_branch branch))
230             Domain.empty branches
231         in
232         Domain.add (Id indty_ident)
233           (Domain.union outtype_dom (Domain.union term_dom branches_dom))
234     | CicTextualParser2Ast.LetIn ((var, typ), body, where) ->
235         let body_dom = aux loc context body in
236         let type_dom = 
237           match typ with
238           | None -> Domain.empty
239           | Some typ -> aux loc context typ
240         in
241         let where_dom = aux loc (var :: context) where in
242         Domain.union (Domain.union body_dom where_dom) type_dom
243     | CicTextualParser2Ast.LetRec (kind, defs, where) ->
244         let context' =
245           List.fold_left (fun acc ((var, typ), _, _) -> var :: acc)
246             context defs
247         in
248         let where_dom = aux loc context' where in
249         let defs_dom =
250           List.fold_left
251             (fun dom ((_, typ), body, _) ->
252               Domain.union (aux loc context' body) (aux_option loc context typ))
253             Domain.empty defs
254         in
255         Domain.union where_dom defs_dom
256     | CicTextualParser2Ast.Ident (name, subst) ->
257         (* TODO hanlde explicit substitutions *)
258         (try
259           let index = find_in_environment name context in
260           if subst <> [] then
261             CicTextualParser2.fail loc
262               "Explicit substitutions not allowed here";
263           Domain.empty
264         with Not_found -> Domain.singleton (Id name))
265     | CicTextualParser2Ast.Num (num, i) -> Domain.singleton (Num i)
266     | CicTextualParser2Ast.Meta (index, local_context) ->
267         List.fold_left
268           (fun dom term -> Domain.union dom (aux_option loc context term))
269             Domain.empty local_context
270     | CicTextualParser2Ast.Sort _ -> Domain.empty
271   and aux_option loc context = function
272     | None -> Domain.empty
273     | Some t -> aux loc context t
274   in
275   match ast with
276   | CicTextualParser2Ast.AttributedTerm (`Loc loc, term) -> aux loc context term
277   | _ -> assert false
278
279 module Make (C: Callbacks) =
280   struct
281     let choices_of_id mqi_handle id =
282      let query  =  MQueryGenerator.locate id in
283      let result = MQueryInterpreter.execute mqi_handle query in
284      let uris =
285       List.map
286        (function uri,_ ->
287          MQueryMisc.wrong_xpointer_format_from_wrong_xpointer_format' uri
288        ) result in
289       C.output_html (`Msg (`T "Locate query:"));
290       MQueryUtil.text_of_query
291        (fun s -> C.output_html ~append_NL:false (`Msg (`T s)))
292        "" query; 
293       C.output_html (`Msg (`T "Result:"));
294       MQueryUtil.text_of_result
295         (fun s -> C.output_html (`Msg (`T s))) "" result;
296       let uris' =
297        match uris with
298         | [] ->
299            [UriManager.string_of_uri (C.input_or_locate_uri
300             ~title:("URI matching \"" ^ id ^ "\" unknown."))]
301         | [uri] -> [uri]
302         | _ ->
303             C.interactive_user_uri_choice ~selection_mode:`MULTIPLE
304              ~ok:"Try selected." ~enable_button_for_non_vars:true
305              ~title:"Ambiguous input." ~id
306              ~msg: ("Ambiguous input \"" ^ id ^
307                 "\". Please, choose one or more interpretations:")
308              uris
309       in
310       List.map
311         (fun uri ->
312           (uri,
313            let term =
314              try
315                HelmLibraryObjects.term_of_uri (UriManager.uri_of_string uri)
316              with _ -> assert false
317             in
318            fun _ _ _ -> term))
319         uris'
320
321     let disambiguate_term mqi_handle context metasenv term ~aliases:current_env
322     =
323       let current_dom = (* TODO temporary, remove ASAP *)
324         Environment.fold (fun item _ dom -> Domain.add item dom)
325           current_env Domain.empty
326       in
327       debug_print "NEW DISAMBIGUATE INPUT";
328       let disambiguate_context =  (* cic context -> disambiguate context *)
329         List.map
330           (function None -> Cic.Anonymous | Some (name, _) -> name)
331           context
332       in
333       let term_dom = domain_of_term ~context:disambiguate_context term in
334       debug_print (sprintf "DISAMBIGUATION DOMAIN: %s"
335         (string_of_domain term_dom));
336       let todo_dom = Domain.diff term_dom current_dom in
337       (* (2) lookup function for any item (Id/Symbol/Num) *)
338       let lookup_choices =
339         let id_choices = Hashtbl.create 1023 in
340         fun item ->
341         let choices =
342           match item with
343           | Id id ->
344               (try
345                 Hashtbl.find id_choices id
346               with Not_found ->
347                 let choices = choices_of_id mqi_handle id in
348                 Hashtbl.add id_choices id choices;
349                 choices)
350           | Symbol (symb, _) -> DisambiguateChoices.lookup_symbol_choices symb
351           | Num instance -> DisambiguateChoices.lookup_num_choices ()
352         in
353         if choices = [] then raise (No_choices item);
354         choices
355       in
356       (* (3) test an interpretation filling with meta uninterpreted identifiers
357        *)
358       let test_env current_env todo_dom =
359         let filled_env =
360           Domain.fold
361             (fun item env ->
362               Environment.add item ("Implicit", fun _ _ _ -> Cic.Implicit) env)
363             todo_dom current_env
364         in
365         try
366           let cic_term =
367             interpretate ~context:disambiguate_context ~env:filled_env term
368           in
369           refine metasenv context cic_term
370         with
371         | Try_again -> Uncertain
372         | DisambiguateChoices.Invalid_choice -> Ko
373       in
374       (* (4) build all possible interpretations *)
375       let rec aux current_env todo_dom =
376         if Domain.is_empty todo_dom then
377           match test_env current_env Domain.empty with
378           | Ok (term, metasenv) -> [ current_env, term, metasenv ]
379           | Ko | Uncertain -> []
380         else
381           let item = Domain.choose todo_dom in
382           let remaining_dom = Domain.remove item todo_dom in
383           debug_print (sprintf "CHOOSED ITEM: %s" (string_of_domain_item item));
384           let choices = lookup_choices item in
385           let rec filter = function
386             | [] -> []
387             | codomain_item :: tl ->
388                 debug_print (sprintf "%s CHOSEN" (fst codomain_item)) ;
389                 let new_env = Environment.add item codomain_item current_env in
390                 (match test_env new_env remaining_dom with
391                 | Ok (term, metasenv) ->
392                     (if Domain.is_empty remaining_dom then
393                       [ new_env, term, metasenv ]
394                     else
395                       aux new_env remaining_dom)
396                     @ filter tl
397                 | Uncertain ->
398                     (if Domain.is_empty remaining_dom then
399                       []
400                     else
401                       aux new_env remaining_dom)
402                     @ filter tl
403                 | Ko -> filter tl)
404           in
405           filter choices
406       in
407       let (choosed_env, choosed_term, choosed_metasenv) =
408         match aux current_env todo_dom with
409         | [] -> raise NoWellTypedInterpretation
410         | [ x ] ->
411             debug_print "UNA SOLA SCELTA";
412             x
413         | l ->
414             debug_print (sprintf "PIU' SCELTE (%d)" (List.length l));
415             let choices =
416               List.map
417                 (fun (env, _, _) ->
418                   List.map
419                     (fun domain_item ->
420                       let description =
421                         fst (Environment.find domain_item env)
422                       in
423                       (descr_of_domain_item domain_item, description))
424                     (Domain.elements term_dom))
425                 l
426             in
427             let choosed = C.interactive_interpretation_choice choices in
428             List.nth l choosed
429       in
430       (choosed_env, choosed_metasenv, choosed_term)
431
432   end
433