]> matita.cs.unibo.it Git - helm.git/blob - helm/software/components/ng_disambiguation/nCicDisambiguate.ml
The aliases and multi_aliases in the lexicon status are now
[helm.git] / helm / software / components / ng_disambiguation / nCicDisambiguate.ml
1 (*
2     ||M||  This file is part of HELM, an Hypertextual, Electronic        
3     ||A||  Library of Mathematics, developed at the Computer Science     
4     ||T||  Department, University of Bologna, Italy.                     
5     ||I||                                                                
6     ||T||  HELM is free software; you can redistribute it and/or         
7     ||A||  modify it under the terms of the GNU General Public License   
8     \   /  version 2 or (at your option) any later version.      
9      \ /   This software is distributed as is, NO WARRANTY.     
10       V_______________________________________________________________ *)
11
12 (* $Id: nCic.ml 9058 2008-10-13 17:42:30Z tassi $ *)
13
14 open Printf
15
16 open DisambiguateTypes
17 open UriManager
18
19 module Ast = CicNotationPt
20 module NRef = NReference 
21
22 let debug_print _ = ();;
23 (* let debug_print s = prerr_endline (Lazy.force s);; *)
24
25 let cic_name_of_name = function
26   | Ast.Ident (n, None) ->  n
27   | _ -> assert false
28 ;;
29
30 let refine_term metasenv subst context uri ~use_coercions:_ term _ ~localization_tbl =
31   assert (uri=None);
32   debug_print (lazy (sprintf "TEST_INTERPRETATION: %s" 
33     (NCicPp.ppterm ~metasenv ~subst ~context term)));
34   try
35     let localise t = 
36       try NCicUntrusted.NCicHash.find localization_tbl t
37       with Not_found -> assert false
38     in
39     let metasenv, subst, term, _ = 
40       NCicRefiner.typeof metasenv subst context term None ~localise 
41     in
42      Disambiguate.Ok (term, metasenv, subst, ())
43   with
44   | NCicRefiner.Uncertain loc_msg ->
45       debug_print (lazy ("UNCERTAIN: [" ^ snd (Lazy.force loc_msg) ^ "] " ^ 
46         NCicPp.ppterm ~metasenv ~subst ~context term)) ;
47       Disambiguate.Uncertain loc_msg
48   | NCicRefiner.RefineFailure loc_msg ->
49       debug_print (lazy (sprintf "PRUNED:\nterm%s\nmessage:%s"
50         (NCicPp.ppterm ~metasenv ~subst ~context term) (snd(Lazy.force loc_msg))));
51       Disambiguate.Ko loc_msg
52 ;;
53
54   (* TODO move it to Cic *)
55 let find_in_context name context =
56   let rec aux acc = function
57     | [] -> raise Not_found
58     | hd :: _ when hd = name -> acc
59     | _ :: tl ->  aux (acc + 1) tl
60   in
61   aux 1 context
62
63 let interpretate_term 
64   ?(create_dummy_ids=false) ~mk_choice ~context ~env ~uri ~is_path ast 
65   ~localization_tbl
66 =
67   (* create_dummy_ids shouldbe used only for interpretating patterns *)
68   assert (uri = None);
69
70   let rec aux ~localize loc context = function
71     | CicNotationPt.AttributedTerm (`Loc loc, term) ->
72         let res = aux ~localize loc context term in
73          if localize then NCicUntrusted.NCicHash.add localization_tbl res loc;
74          res
75     | CicNotationPt.AttributedTerm (_, term) -> aux ~localize loc context term
76     | CicNotationPt.Appl (CicNotationPt.Symbol (symb, i) :: args) ->
77         let cic_args = List.map (aux ~localize loc context) args in
78         Disambiguate.resolve ~mk_choice ~env (Symbol (symb, i)) (`Args cic_args)
79     | CicNotationPt.Appl terms ->
80        NCic.Appl (List.map (aux ~localize loc context) terms)
81     | CicNotationPt.Binder (binder_kind, (var, typ), body) ->
82         let cic_type = aux_option ~localize loc context `Type typ in
83         let cic_name = cic_name_of_name var  in
84         let cic_body = aux ~localize loc (cic_name :: context) body in
85         (match binder_kind with
86         | `Lambda -> NCic.Lambda (cic_name, cic_type, cic_body)
87         | `Pi
88         | `Forall -> NCic.Prod (cic_name, cic_type, cic_body)
89         | `Exists ->
90             Disambiguate.resolve ~env ~mk_choice (Symbol ("exists", 0))
91               (`Args [ cic_type; NCic.Lambda (cic_name, cic_type, cic_body) ]))
92     | CicNotationPt.Case (term, indty_ident, outtype, branches) ->
93         let cic_term = aux ~localize loc context term in
94         let cic_outtype = aux_option ~localize loc context `Term outtype in
95         let do_branch ((_, _, args), term) =
96          let rec do_branch' context = function
97            | [] -> aux ~localize loc context term
98            | (name, typ) :: tl ->
99                let cic_name = cic_name_of_name name in
100                let cic_body = do_branch' (cic_name :: context) tl in
101                let typ =
102                  match typ with
103                  | None -> NCic.Implicit `Type
104                  | Some typ -> aux ~localize loc context typ
105                in
106                NCic.Lambda (cic_name, typ, cic_body)
107          in
108           do_branch' context args
109         in
110         if create_dummy_ids then
111          let branches =
112           List.map
113            (function
114                Ast.Wildcard,term -> ("wildcard",None,[]), term
115              | Ast.Pattern _,_ ->
116                 raise (DisambiguateTypes.Invalid_choice 
117                  (lazy (loc, "Syntax error: the left hand side of a "^
118                    "branch pattern must be \"_\"")))
119            ) branches
120          in
121          (*
122           NCic.MutCase (ref, cic_outtype, cic_term,
123             (List.map do_branch branches))
124           *) ignore branches; assert false (* patterns not implemented yet *)
125         else
126          let indtype_ref =
127           match indty_ident with
128           | Some (indty_ident, _) ->
129              (match Disambiguate.resolve ~env ~mk_choice 
130                 (Id indty_ident) (`Args []) with
131               | NCic.Const r -> r
132               | NCic.Implicit _ ->
133                  raise (Disambiguate.Try_again 
134                   (lazy "The type of the term to be matched is still unknown"))
135               | _ ->
136                 raise (DisambiguateTypes.Invalid_choice 
137                   (lazy (loc,"The type of the term to be matched "^
138                           "is not (co)inductive!"))))
139           | None ->
140               let rec fst_constructor =
141                 function
142                    (Ast.Pattern (head, _, _), _) :: _ -> head
143                  | (Ast.Wildcard, _) :: tl -> fst_constructor tl
144                  | [] -> raise (Invalid_choice (lazy (loc,"The type "^
145                      "of the term to be matched cannot be determined "^
146                      "because it is an inductive type without constructors "^
147                      "or because all patterns use wildcards")))
148               in
149               (match Disambiguate.resolve ~env ~mk_choice 
150                 (Id (fst_constructor branches)) (`Args []) with
151               | NCic.Const r -> r
152               | NCic.Implicit _ ->
153                  raise (Disambiguate.Try_again 
154                   (lazy "The type of the term to be matched is still unknown"))
155               | _ ->
156                 raise (DisambiguateTypes.Invalid_choice 
157                   (lazy (loc, 
158                   "The type of the term to be matched is not (co)inductive!"))))
159          in
160          let _,leftsno,itl,_,indtyp_no =
161           NCicEnvironment.get_checked_indtys indtype_ref in
162          let _,_,_,cl =
163           try
164            List.nth itl indtyp_no
165           with _ -> assert false in
166          let rec count_prod t =
167            match NCicReduction.whd [] t with
168                NCic.Prod (_, _, t) -> 1 + (count_prod t)
169              | _ -> 0 
170          in 
171          let rec sort branches cl =
172           match cl with
173              [] ->
174               let rec analyze unused unrecognized useless =
175                function
176                   [] ->
177                    if unrecognized != [] then
178                     raise (DisambiguateTypes.Invalid_choice
179                      (lazy
180                        (loc,"Unrecognized constructors: " ^
181                         String.concat " " unrecognized)))
182                    else if useless > 0 then
183                     raise (DisambiguateTypes.Invalid_choice
184                      (lazy
185                        (loc,"The last " ^ string_of_int useless ^
186                         "case" ^ if useless > 1 then "s are" else " is" ^
187                         " unused")))
188                    else
189                     []
190                 | (Ast.Wildcard,_)::tl when not unused ->
191                     analyze true unrecognized useless tl
192                 | (Ast.Pattern (head,_,_),_)::tl when not unused ->
193                     analyze unused (head::unrecognized) useless tl
194                 | _::tl -> analyze unused unrecognized (useless + 1) tl
195               in
196                analyze false [] 0 branches
197            | (_,name,ty)::cltl ->
198               let rec find_and_remove =
199                function
200                   [] ->
201                    raise
202                     (DisambiguateTypes.Invalid_choice
203                      (lazy (loc, "Missing case: " ^ name)))
204                 | ((Ast.Wildcard, _) as branch :: _) as branches ->
205                     branch, branches
206                 | (Ast.Pattern (name',_,_),_) as branch :: tl
207                    when name = name' ->
208                     branch,tl
209                 | branch::tl ->
210                    let found,rest = find_and_remove tl in
211                     found, branch::rest
212               in
213                let branch,tl = find_and_remove branches in
214                match branch with
215                   Ast.Pattern (name,y,args),term ->
216                    if List.length args = count_prod ty - leftsno then
217                     ((name,y,args),term)::sort tl cltl
218                    else
219                     raise
220                      (DisambiguateTypes.Invalid_choice
221                       (lazy (loc,"Wrong number of arguments for " ^ name)))
222                 | Ast.Wildcard,term ->
223                    let rec mk_lambdas =
224                     function
225                        0 -> term
226                      | n ->
227                         CicNotationPt.Binder
228                          (`Lambda, (CicNotationPt.Ident ("_", None), None),
229                            mk_lambdas (n - 1))
230                    in
231                     (("wildcard",None,[]),
232                      mk_lambdas (count_prod ty - leftsno)) :: sort tl cltl
233          in
234           let branches = sort branches cl in
235            NCic.Match (indtype_ref, cic_outtype, cic_term,
236             (List.map do_branch branches))
237     | CicNotationPt.Cast (t1, t2) ->
238         let cic_t1 = aux ~localize loc context t1 in
239         let cic_t2 = aux ~localize loc context t2 in
240         NCic.LetIn ("_",cic_t2,cic_t1, NCic.Rel 1)
241     | CicNotationPt.LetIn ((name, typ), def, body) ->
242         let cic_def = aux ~localize loc context def in
243         let cic_name = cic_name_of_name name in
244         let cic_typ =
245           match typ with
246           | None -> NCic.Implicit `Type
247           | Some t -> aux ~localize loc context t
248         in
249         let cic_body = aux ~localize loc (cic_name :: context) body in
250         NCic.LetIn (cic_name, cic_def, cic_typ, cic_body)
251     | CicNotationPt.LetRec (_kind, _defs, _body) ->
252        assert false (*
253         let context' =
254           List.fold_left
255             (fun acc (_, (name, _), _, _) ->
256               cic_name_of_name name :: acc)
257             context defs
258         in
259         let cic_body =
260          let unlocalized_body = aux ~localize:false loc context' body in
261          match unlocalized_body with
262             NCic.Rel n when n <= List.length defs -> `AvoidLetInNoAppl n
263           | NCic.Appl (NCic.Rel n::l) when n <= List.length defs ->
264              (try
265                let l' =
266                 List.map
267                  (function t ->
268                    let t',subst,metasenv =
269                     CicMetaSubst.delift_rels [] [] (List.length defs) t
270                    in
271                     assert (subst=[]);
272                     assert (metasenv=[]);
273                     t') l
274                in
275                 (* We can avoid the LetIn. But maybe we need to recompute l'
276                    so that it is localized *)
277                 if localize then
278                  match body with
279                     CicNotationPt.AttributedTerm (_,CicNotationPt.Appl(_::l)) ->
280                      (* since we avoid the letin, the context has no
281                       * recfuns in it *)
282                      let l' = List.map (aux ~localize loc context) l in
283                       `AvoidLetIn (n,l')
284                   | _ -> assert false
285                 else
286                  `AvoidLetIn (n,l')
287               with
288                CicMetaSubst.DeliftingARelWouldCaptureAFreeVariable ->
289                 if localize then
290                  `AddLetIn (aux ~localize loc context' body)
291                 else
292                  `AddLetIn unlocalized_body)
293           | _ ->
294              if localize then
295               `AddLetIn (aux ~localize loc context' body)
296              else
297               `AddLetIn unlocalized_body
298         in
299         let inductiveFuns =
300           List.map
301             (fun (params, (name, typ), body, decr_idx) ->
302               let add_binders kind t =
303                List.fold_right
304                 (fun var t -> CicNotationPt.Binder (kind, var, t)) params t
305               in
306               let cic_body =
307                aux ~localize loc context' (add_binders `Lambda body) in
308               let cic_type =
309                aux_option ~localize loc context (Some `Type)
310                 (HExtlib.map_option (add_binders `Pi) typ) in
311               let name =
312                 match cic_name_of_name name with
313                 | NCic.Anonymous ->
314                     CicNotationPt.fail loc
315                       "Recursive functions cannot be anonymous"
316                 | NCic.Name name -> name
317               in
318               (name, decr_idx, cic_type, cic_body))
319             defs
320         in
321         let fix_or_cofix n =
322          match kind with
323             `Inductive -> NCic.Fix (n,inductiveFuns)
324           | `CoInductive ->
325               let coinductiveFuns =
326                 List.map
327                  (fun (name, _, typ, body) -> name, typ, body)
328                  inductiveFuns
329               in
330                NCic.CoFix (n,coinductiveFuns)
331         in
332          let counter = ref ~-1 in
333          let build_term _ (var,_,ty,_) t =
334           incr counter;
335           NCic.LetIn (NCic.Name var, fix_or_cofix !counter, ty, t)
336          in
337           (match cic_body with
338               `AvoidLetInNoAppl n ->
339                 let n' = List.length inductiveFuns - n in
340                  fix_or_cofix n'
341             | `AvoidLetIn (n,l) ->
342                 let n' = List.length inductiveFuns - n in
343                  NCic.Appl (fix_or_cofix n'::l)
344             | `AddLetIn cic_body ->         
345                 List.fold_right (build_term inductiveFuns) inductiveFuns
346                  cic_body)
347 *)
348     | CicNotationPt.Ident _
349     | CicNotationPt.Uri _ when is_path -> raise Disambiguate.PathNotWellFormed
350     | CicNotationPt.Ident (name, subst) ->
351        assert (subst = None);
352        (try
353          NCic.Rel (find_in_context name context)
354        with Not_found -> 
355          Disambiguate.resolve ~env ~mk_choice (Id name) (`Args []))
356     | CicNotationPt.Uri (name, subst) ->
357        assert (subst = None);
358        (try
359          NCic.Const (NRef.reference_of_string name)
360         with NRef.IllFormedReference _ ->
361          CicNotationPt.fail loc "Ill formed reference")
362     | CicNotationPt.Implicit -> NCic.Implicit `Term
363     | CicNotationPt.UserInput -> assert false (*NCic.Implicit (Some `Hole)
364 patterns not implemented *)
365     | CicNotationPt.Num (num, i) -> 
366         Disambiguate.resolve ~env ~mk_choice (Num i) (`Num_arg num)
367     | CicNotationPt.Meta (index, subst) ->
368         let cic_subst =
369          List.map
370           (function None -> assert false| Some t -> aux ~localize loc context t)
371           subst
372         in
373          NCic.Meta (index, (0, NCic.Ctx cic_subst))
374     | CicNotationPt.Sort `Prop -> NCic.Sort NCic.Prop
375     | CicNotationPt.Sort `Set -> assert false
376     | CicNotationPt.Sort (`Type _u) -> NCic.Sort (NCic.Type
377        [false,NUri.uri_of_string "cic:/matita/pts/Type.univ"])
378     | CicNotationPt.Sort (`CProp _u) -> NCic.Sort (NCic.Type
379        [false,NUri.uri_of_string "cic:/matita/pts/CProp.univ"])
380     | CicNotationPt.Symbol (symbol, instance) ->
381         Disambiguate.resolve ~env ~mk_choice 
382          (Symbol (symbol, instance)) (`Args [])
383     | _ -> assert false (* god bless Bologna *)
384   and aux_option ~localize loc context annotation = function
385     | None -> NCic.Implicit annotation
386     | Some (CicNotationPt.AttributedTerm (`Loc loc, term)) ->
387         let res = aux_option ~localize loc context annotation (Some term) in
388         if localize then NCicUntrusted.NCicHash.add localization_tbl res loc;
389         res
390     | Some (CicNotationPt.AttributedTerm (_, term)) ->
391         aux_option ~localize loc context annotation (Some term)
392     | Some CicNotationPt.Implicit -> NCic.Implicit annotation
393     | Some term -> aux ~localize loc context term
394   in
395    aux ~localize:true HExtlib.dummy_floc context ast
396
397 let interpretate_term ?(create_dummy_ids=false) ~context ~env ~uri ~is_path ast
398      ~localization_tbl
399 =
400   let context = List.map fst context in
401   interpretate_term ~create_dummy_ids ~context ~env ~uri ~is_path ast
402 ~localization_tbl
403 ;;
404
405 let domain_of_term ~context = 
406   Disambiguate.domain_of_ast_term ~context
407 ;; 
408
409 let disambiguate_term ~context ~metasenv ~subst ?goal
410    ~mk_implicit ~description_of_alias ~mk_choice
411    ~aliases ~universe ~lookup_in_library 
412    (text,prefix_len,term) 
413  =
414   let localization_tbl = NCicUntrusted.NCicHash.create 503 in
415   let hint =
416    match goal with
417       None -> (fun _ y -> y),(fun x -> x)
418     | Some n ->
419        (fun metasenv y ->
420          let _,_,ty = NCicUtils.lookup_meta n metasenv in
421           NCic.LetIn ("_",ty,y,NCic.Rel 1)),
422        (function  
423         | Disambiguate.Ok (t,m,s,ug) ->
424             (match t with
425             | NCic.LetIn ("_",_,y,NCic.Rel 1) -> Disambiguate.Ok (y,m,s,ug)
426             | _ -> assert false)
427         | k -> k)
428   in
429    let res,b =
430     MultiPassDisambiguator.disambiguate_thing
431      ~freshen_thing:CicNotationUtil.freshen_term
432      ~context ~metasenv ~initial_ugraph:() ~aliases
433      ~mk_implicit ~description_of_alias
434      ~string_context_of_context:(List.map (fun (x,_) -> Some x))
435      ~universe ~uri:None ~pp_thing:CicNotationPp.pp_term
436      ~passes:(MultiPassDisambiguator.passes ())
437      ~lookup_in_library ~domain_of_thing:domain_of_term
438      ~interpretate_thing:(interpretate_term ~mk_choice (?create_dummy_ids:None))
439      ~refine_thing:refine_term (text,prefix_len,term)
440      ~localization_tbl ~hint ~subst
441    in
442     List.map (function (a,b,c,d,_) -> a,b,c,d) res, b
443 ;;
444