]> matita.cs.unibo.it Git - helm.git/blob - matitaB/components/disambiguation/disambiguate.ml
Matitaweb:
[helm.git] / matitaB / components / 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 (* $Id$ *)
27
28 open Printf
29
30 open DisambiguateTypes
31
32 module Ast = NotationPt
33
34 (* hard errors, spurious errors *)
35 exception NoWellTypedInterpretation of
36  ((Stdpp.location * string) list *
37   (Stdpp.location * string) list)
38
39 exception PathNotWellFormed
40
41   (** raised when an environment is not enough informative to decide *)
42 exception Try_again of string Lazy.t
43
44 type ('alias,'term) aliases =
45  bool * 'term DisambiguateTypes.codomain_item DisambiguateTypes.Environment.t
46 type 'a disambiguator_input = string * int * 'a
47
48 type domain = domain_tree list
49 and domain_tree = Node of Stdpp.location list * domain_item * domain
50
51 (*
52 let mono_uris_callback ~selection_mode ?ok
53           ?(enable_button_for_non_vars = true) ~title ~msg ~id =
54  if Helm_registry.get_opt_default Helm_registry.get_bool ~default:true
55       "matita.auto_disambiguation"
56  then
57   function l -> l
58  else
59   raise Ambiguous_input
60
61 let mono_interp_callback _ _ _ = assert false
62 let mono_disamb_callback _ = assert false
63
64 let _choose_uris_callback = ref mono_uris_callback
65 let _choose_interp_callback = ref mono_interp_callback
66 let _choose_disamb_callback = ref mono_disamb_callback
67 let set_choose_uris_callback f = _choose_uris_callback := f
68 let set_choose_interp_callback f = _choose_interp_callback := f
69 let set_choose_disamb_callback f = _choose_disamb_callback := f
70
71 let interactive_user_uri_choice = !_choose_uris_callback
72 let interactive_interpretation_choice interp = !_choose_interp_callback interp
73 let interactive_ast_choice interp = !_choose_disamb_callback interp
74 *)
75
76 let input_or_locate_uri ~(title:string) ?id () = None
77   (* Zack: I try to avoid using this callback. I therefore assume that
78   * the presence of an identifier that can't be resolved via "locate"
79   * query is a syntax error *)
80   
81
82 let rec string_of_domain =
83  function
84     [] -> ""
85   | Node (_,domain_item,l)::tl ->
86      DisambiguateTypes.string_of_domain_item domain_item ^
87       " [ " ^ string_of_domain l ^ " ] " ^ string_of_domain tl
88
89 let rec filter_map_domain f =
90  function
91     [] -> []
92   | Node (locs,domain_item,l)::tl ->
93      match f locs domain_item with
94         None -> filter_map_domain f l @ filter_map_domain f tl
95       | Some res -> res :: filter_map_domain f l @ filter_map_domain f tl
96
97 let rec map_domain f =
98  function
99     [] -> []
100   | Node (locs,domain_item,l)::tl ->
101      f locs domain_item :: map_domain f l @ map_domain f tl
102
103 let uniq_domain dom =
104  let rec aux seen =
105   function
106      [] -> seen,[]
107    | Node (locs,domain_item,l)::tl ->
108       if List.mem domain_item seen then
109        let seen,l = aux seen l in
110        let seen,tl = aux seen tl in
111         seen, l @ tl
112       else
113        let seen,l = aux (domain_item::seen) l in
114        let seen,tl = aux seen tl in
115         seen, Node (locs,domain_item,l)::tl
116  in
117   snd (aux [] dom)
118
119 let debug = false
120 let debug_print s = if debug then prerr_endline (Lazy.force s) else ()
121
122 (*
123   (** print benchmark information *)
124 let benchmark = true
125 let max_refinements = ref 0       (* benchmarking is not thread safe *)
126 let actual_refinements = ref 0
127 let domain_size = ref 0
128 let choices_avg = ref 0.
129 *)
130
131 type ('term,'metasenv,'subst,'graph) test_result =
132   | Ok of 'term * 'metasenv * 'subst * 'graph
133   | Ko of (Stdpp.location * string) Lazy.t
134   | Uncertain of (Stdpp.location * string) Lazy.t
135
136 type ('alias,'ast_thing,'metasenv,'subst,'thing,'ugraph) disamb_result =
137   | Disamb_success of ('ast_thing * 'metasenv * 'subst * 'thing * 'ugraph) list 
138       (* each element of this list is a list of partially instantiated asts, 
139        * sharing the last instantiated node, together with the location of that
140        * node; each ast is associated with the actual instantiation of the node, 
141        * the refinement error, and the location at which refinement fails *)
142   | Disamb_failure of
143       (* hard errors, spurious errors *) 
144       (('ast_thing * 'alias option * Stdpp.location * string) list * Stdpp.location) list *
145       (('ast_thing * 'alias option * Stdpp.location * string) list * Stdpp.location) list
146
147 let resolve ~env ~universe ~mk_choice item interpr arg =
148   (* let _ = (mk_choice : (GrafiteAst.alias_spec -> 'b
149      DisambiguateTypes.codomain_item)) in *)
150   try
151    let interpr = 
152      match interpr with
153      | None -> InterprEnv.find item env 
154      | Some i -> i 
155    in
156    (* one, and only one interpretation is returned (or Not_found) *)
157    (*if (List.length interpr <> 1)
158    then (let strinterpr = 
159           String.concat ", " (List.map GrafiteAst.description_of_alias interpr) in
160            prerr_endline (Printf.sprintf "choices for %s: %s"
161              (DisambiguateTypes.string_of_domain_item item) strinterpr);
162           assert false)
163      else
164    let interpr = List.hd interpr in*)
165    match snd (mk_choice interpr), arg with
166       `Num_interp f, `Num_arg n -> f n
167     | `Sym_interp f, `Args l -> f l
168     | `Sym_interp f, `Num_arg n -> (* Implicit number! *) f []
169     | _,_ -> assert false
170   with Not_found -> 
171     failwith (": InterprEnv.find failed")
172
173   (* TODO move it to Cic *)
174 let find_in_context name context =
175   let rec aux acc = function
176     | [] -> raise Not_found
177     | Some hd :: tl when hd = name -> acc
178     | _ :: tl ->  aux (acc + 1) tl
179   in
180   aux 1 context
181
182 let string_of_name =
183  function
184   | Ast.Ident (n, _) -> Some n
185   | _ -> assert false
186 ;;
187
188 (* XXX: assuming the domain is composed of uninterpreted items only *)
189 let rec domain_of_term ?(loc = HExtlib.dummy_floc) ~context = function
190   | Ast.AttributedTerm (`Loc loc, term) ->
191      domain_of_term ~loc ~context term
192   | Ast.AttributedTerm (_, term) ->
193       domain_of_term ~loc ~context term
194   | Ast.Symbol (name, attr) ->
195       (match attr with
196        | None ->  [ Node ([loc], Symbol name, []) ]
197        | _ -> [])
198       (* to be kept in sync with Ast.Appl (Ast.Symbol ...) *)
199   | Ast.Appl (Ast.Symbol (name, None)  as hd :: args)
200   | Ast.Appl (Ast.AttributedTerm (_,Ast.Symbol (name,None)) as hd :: args)
201      ->
202       let args_dom =
203         List.fold_right
204           (fun term acc -> domain_of_term ~loc ~context term @ acc)
205           args [] in
206       let loc =
207        match hd with
208           Ast.AttributedTerm (`Loc loc,_)  -> loc
209         | _ -> loc
210       in
211        [ Node ([loc], Symbol name, args_dom) ]
212   | Ast.Appl (Ast.Ident (id,`Ambiguous) as hd :: args)
213   | Ast.Appl (Ast.AttributedTerm (_,Ast.Ident (id,`Ambiguous)) as hd :: args) ->
214       let args_dom =
215         List.fold_right
216           (fun term acc -> domain_of_term ~loc ~context term @ acc)
217           args [] in
218       let loc =
219        match hd with
220           Ast.AttributedTerm (`Loc loc,_)  -> loc
221         | _ -> loc
222       in
223       (try
224         (* the next line can raise Not_found *)
225         ignore(find_in_context id context);
226           args_dom
227       with Not_found ->
228         [ Node ([loc], Id id, args_dom) ] )
229   | Ast.Appl terms ->
230       List.fold_right
231         (fun term acc -> domain_of_term ~loc ~context term @ acc)
232         terms []
233   | Ast.Binder (kind, (var, typ), body) ->
234       let type_dom = domain_of_term_option ~loc ~context typ in
235       let body_dom =
236         domain_of_term ~loc
237           ~context:(string_of_name var :: context) body in
238       (match kind with
239       | `Exists -> [ Node ([loc], Symbol "exists", (type_dom @ body_dom)) ]
240       | _ -> type_dom @ body_dom)
241   | Ast.Case (term, indty_ident, outtype, branches) ->
242       let term_dom = domain_of_term ~loc ~context term in
243       let outtype_dom = domain_of_term_option ~loc ~context outtype in
244       let rec get_first_constructor = function
245         | [] -> []
246         | (Ast.Pattern (head, Some r, _), _) :: _ -> []
247              (* [ Node ([loc], Id (head,Some (NReference.string_of_reference r)), []) ] *)
248         | (Ast.Pattern (head, None, _), _) :: _ -> 
249              [ Node ([loc], Id head, []) ]
250         | _ :: tl -> get_first_constructor tl in
251       let do_branch =
252        function
253           Ast.Pattern (head, _, args), term ->
254            let (term_context, args_domain) =
255              List.fold_left
256                (fun (cont, dom) (name, typ) ->
257                  (string_of_name name :: cont,
258                   (match typ with
259                   | None -> dom
260                   | Some typ -> dom @ domain_of_term ~loc ~context:cont typ)))
261                (context, []) args
262            in
263             domain_of_term ~loc ~context:term_context term @ args_domain
264         | Ast.Wildcard, term ->
265             domain_of_term ~loc ~context term
266       in
267       let branches_dom =
268         List.fold_left (fun dom branch -> dom @ do_branch branch) [] branches in
269       (match indty_ident with
270        | None -> get_first_constructor branches
271        | Some (ident, None) -> [ Node ([loc], Id ident , []) ]
272        | Some (ident, Some r) -> [])
273            (* [ Node ([loc], Id (ident,Some (NReference.string_of_reference r)), []) ]) *)
274       @ term_dom @ outtype_dom @ branches_dom
275   | Ast.Cast (term, ty) ->
276       let term_dom = domain_of_term ~loc ~context term in
277       let ty_dom = domain_of_term ~loc ~context ty in
278       term_dom @ ty_dom
279   | Ast.LetIn ((var, typ), body, where) ->
280       let body_dom = domain_of_term ~loc ~context body in
281       let type_dom = domain_of_term_option ~loc ~context typ in
282       let where_dom =
283         domain_of_term ~loc ~context:(string_of_name var :: context) where in
284       body_dom @ type_dom @ where_dom
285   | Ast.LetRec (kind, defs, where) ->
286       let add_defs context =
287         List.fold_left
288           (fun acc (_, (var, _), _, _) -> string_of_name var :: acc
289           ) context defs in
290       let where_dom = domain_of_term ~loc ~context:(add_defs context) where in
291       let defs_dom =
292         List.fold_left
293           (fun dom (params, (_, typ), body, _) ->
294             let context' =
295              add_defs
296               (List.fold_left
297                 (fun acc (var,_) -> string_of_name var :: acc)
298                 context params)
299             in
300             List.rev
301              (snd
302                (List.fold_left
303                 (fun (context,res) (var,ty) ->
304                   string_of_name var :: context,
305                   domain_of_term_option ~loc ~context ty @ res)
306                 (add_defs context,[]) params))
307             @ dom
308             @ domain_of_term_option ~loc ~context:context' typ
309             @ domain_of_term ~loc ~context:context' body
310           ) [] defs
311       in
312       defs_dom @ where_dom
313   | Ast.Ident (name, _x) ->
314       (* let x = match x with
315         | `Uri u -> Some u
316         | _ -> None 
317       in *)
318       (try
319         (* the next line can raise Not_found *)
320         ignore(find_in_context name context); []
321       with Not_found ->
322         (*
323         (match subst with
324         | None -> [ Node ([loc], Id name, []) ]
325         | Some subst ->
326             let terms =
327               List.fold_left
328                 (fun dom (_, term) ->
329                   let dom' = domain_of_term ~loc ~context term in
330                   dom @ dom')
331                 [] subst in
332             [ Node ([loc], Id name, terms) ]))*)
333         [ Node ([loc], Id name, []) ])
334   | Ast.NRef _ -> []
335   | Ast.NCic _ -> []
336   | Ast.Implicit _ -> []
337   | Ast.Num (num, i) -> [ Node ([loc], Num, []) ]
338   | Ast.Meta (index, local_context) ->
339       List.fold_left
340        (fun dom term -> dom @ domain_of_term_option ~loc ~context term)
341        [] local_context
342   | Ast.Sort _ -> []
343   | Ast.UserInput
344   | Ast.Literal _
345   | Ast.Layout _
346   | Ast.Magic _
347   | Ast.Variable _ -> assert false
348
349 and domain_of_term_option ~loc ~context = function
350   | None -> []
351   | Some t -> domain_of_term ~loc ~context t
352
353 let domain_of_term ~context term = 
354  uniq_domain (domain_of_term ~context term)
355
356 let domain_of_obj ~context ast =
357  assert (context = []);
358   match ast with
359    | Ast.Theorem (_,_,ty,bo,_) ->
360       domain_of_term [] ty
361       @ (match bo with
362           None -> []
363         | Some bo -> domain_of_term [] bo)
364    | Ast.Inductive (params,tyl) ->
365       let context, dom = 
366        List.fold_left
367         (fun (context, dom) (var, ty) ->
368           let context' = string_of_name var :: context in
369           match ty with
370              None -> context', dom
371            | Some ty -> context', dom @ domain_of_term context ty
372         ) ([], []) params in
373       let context_w_types =
374         List.rev_map (fun (var, _, _, _) -> Some var) tyl @ context in
375       dom
376       @ List.flatten (
377          List.map
378           (fun (_,_,ty,cl) ->
379             domain_of_term context ty
380             @ List.flatten (
381                List.map
382                 (fun (_,ty) -> domain_of_term context_w_types ty) cl))
383                 tyl)
384    | Ast.Record (params,var,ty,fields) ->
385       let context, dom = 
386        List.fold_left
387         (fun (context, dom) (var, ty) ->
388           let context' = string_of_name var :: context in
389           match ty with
390              None -> context', dom
391            | Some ty -> context', dom @ domain_of_term context ty
392         ) ([], []) params in
393       let context_w_types = Some var :: context in
394       dom
395       @ domain_of_term context ty
396       @ snd
397          (List.fold_left
398           (fun (context,res) (name,ty,_,_) ->
399             Some name::context, res @ domain_of_term context ty
400           ) (context_w_types,[]) fields)
401
402 let domain_of_obj ~context obj = 
403  uniq_domain (domain_of_obj ~context obj)
404
405   (* dom1 \ dom2 *)
406 (* XXX: possibly should take into account locs? *)
407 let domain_diff dom1 dom2 =
408 (* let domain_diff = Domain.diff *)
409   let is_in_dom2 elt =
410     List.exists
411      (function
412        | Symbol symb ->
413           (match elt with
414               Symbol symb' when symb = symb' -> true
415             | _ -> false)
416        | Num ->
417           (match elt with
418               Num -> true
419             | _ -> false)
420        | item -> elt = item
421      ) dom2
422   in
423    let rec aux =
424     function
425        [] -> []
426      | Node (_,elt,l)::tl when is_in_dom2 elt -> aux (l @ tl)
427      | Node (loc,elt,l)::tl -> Node (loc,elt,aux l)::(aux tl)
428    in
429     aux dom1
430
431 let refine_profiler = HExtlib.profile "disambiguate_thing.refine_thing"
432
433 (* generic function lifting splitting from type T to type (T list) *) 
434 let rec list_split item_split ctx pre post =
435   match post with
436   | [] -> []
437   | x :: post' ->
438       (item_split (fun v1 -> ctx (pre@v1::post')) x)@
439         list_split item_split ctx (pre@[x]) post'
440 ;;
441
442 (* splits a 'term capture_variable *)
443 let var_split ctx = function
444   | (_,None) -> []
445   | (v,Some ty) -> [(fun x -> ctx (v,Some x)),ty]
446 ;;
447
448 let ity_split ctx (n,isind,ty,cl) = 
449   [(fun x -> ctx (n,isind,x,cl)),ty]@
450   list_split (fun ctx0 (v,ty) -> [(fun x -> ctx0 (v,x)),ty]) 
451     (fun x -> ctx (n,isind,ty,x)) [] cl
452 ;;
453
454 let field_split ctx (n,ty,b,m) =
455         [(fun x -> ctx (n,x,b,m)),ty]
456 ;;
457
458 (* splits a defn. in a mutual LetRec block *)
459 let letrecaux_split ctx (args,f,bo,n) =
460         list_split var_split (fun x -> ctx (x,f,bo,n)) [] args@
461         var_split (fun x -> ctx (args,x,bo,n)) f@
462         [(fun x -> ctx (args,f,x,n)),bo]
463 ;;
464
465 let mk_ident s = function
466 | None -> Ast.Ident (s,`Ambiguous)
467 | Some u -> Ast.Ident (s,`Uri (NReference.string_of_reference u))
468 ;;
469
470 (* splits a pattern (for case analysis) *)
471 let pattern_split ctx = function
472   | Ast.Wildcard -> []
473   | Ast.Pattern (s,href,pl) -> 
474      let rec auxpatt pre = function
475      | [] -> []
476      | (x,Some y as x')::post' ->
477          ((fun v -> ctx (Ast.Pattern (s,href,pre@(x,Some v)::post'))),y)
478          ::auxpatt (pre@[x']) post'
479      | (x,None as x')::post' -> auxpatt (pre@[x']) post'
480      in 
481      ((fun x -> 
482        let id0, href0 = 
483          match x with
484          | Ast.Ident (id,`Ambiguous) -> id, None
485          | Ast.Ident (id,`Uri u) -> id, Some u
486          | _ -> assert false
487        in
488        let href0 = HExtlib.map_option NReference.reference_of_string href0 
489        in ctx (Ast.Pattern (id0,href0,pl))),
490        mk_ident s href)::auxpatt [] pl
491 ;;
492
493   (* this function is used to get the children of a given node, together with
494    * their context and their location
495    * contexts are expressed in the form of functions Ast -> Ast *)
496 (* split : location -> ('term -> 'a) -> 'term -> (('term -> 'a) * 'term * loc) list *)
497 let rec split loc ctx t = 
498   let loc_of_attr oldloc = function
499     | `Loc l -> l
500     | _ -> oldloc
501   in
502   match t with
503   | Ast.AttributedTerm (attr,t) -> 
504      [(fun x -> ctx (Ast.AttributedTerm(attr,x))),t, loc_of_attr loc attr]
505   | Ast.Appl tl -> list_split (*split*) (fun ctx0 t0 -> [ctx0,t0,loc]) (fun x -> ctx (Ast.Appl x)) [] tl
506   | Ast.Binder (k,((n,None) as n'),body) -> 
507      [ (fun v -> ctx (Ast.Binder (k,n',v))),body, loc]
508   | Ast.Binder (k,((n,Some ty) as n'),body) -> 
509      [(fun v -> ctx (Ast.Binder (k,(n,Some v),body))), ty, loc
510      ;(fun v -> ctx (Ast.Binder (k,n',v))),body, loc]
511   | Ast.Case (t,ity,outty,pl) -> 
512      let outty_split = match outty with
513      | None -> []
514      | Some u -> [(fun x -> ctx (Ast.Case (t,ity,Some x,pl))),u]
515      in
516      List.map (fun (a,b) -> a,b,loc)
517      (((fun x -> ctx (Ast.Case (x,ity,outty,pl))),t)::
518        outty_split@list_split
519          (fun ctx0 (p,x) -> 
520             ((fun y -> ctx0 (p,y)),x)::pattern_split 
521               (fun y -> ctx0 (y,x)) p) (fun x -> ctx (Ast.Case(t,ity,outty,x)))
522               [] pl)
523   | Ast.Cast (u,v) -> [ (fun x -> ctx (Ast.Cast (x,v))),u,loc
524                   ; (fun x -> ctx (Ast.Cast (u,x))),v,loc ]
525   | Ast.LetIn ((n,None) as n',u,v) ->
526                   [ (fun x -> ctx (Ast.LetIn (n',x,v))), u,loc
527                   ; (fun x -> ctx (Ast.LetIn (n',u,x))), v,loc ]
528   | Ast.LetIn ((n,Some t) as n',u,v) ->
529                   [ (fun x -> ctx (Ast.LetIn ((n,Some x),u,v))), t,loc
530                   ; (fun x -> ctx (Ast.LetIn (n',x,v))), u, loc
531                   ; (fun x -> ctx (Ast.LetIn (n',u,x))), v, loc ]
532   | Ast.LetRec (k,funs,where) -> (* we do not use where any more?? *)
533       List.map (fun (a,b) -> a,b,loc) 
534        (list_split letrecaux_split (fun x -> ctx (Ast.LetRec(k,x,where))) [] funs)
535   | _ -> [] (* leaves *)
536 ;;
537
538 type 'ast marked_ast = 
539   (NotationPt.term -> 'ast) * NotationPt.term * Stdpp.location
540
541 (* top_split : 'a -> ((term -> 'a) * term * loc) list
542  * such that it returns all the possible top-level (ctx,t,dummy_loc) for its input *)
543 let bfvisit ~pp_term top_split test t = 
544   let rec aux = function
545   | [] -> None
546   | (ctx0,t0,loc as hd)::tl ->
547 (*      prerr_endline ("ok! length tl = " ^ string_of_int (List.length tl)); *)
548       debug_print (lazy ("visiting t0 = " ^ pp_term t0)); 
549       if test t0 then (debug_print (lazy "t0 is ambiguous"); Some hd)
550       else 
551       (*
552          (prerr_endline ("splitting not ambiguous t0:");
553           let t0' = split ctx0 t0 in
554           List.iter (fun (ctx',t') -> prerr_endline ("-- subnode " ^
555              (pp_term t'))) t0';
556           aux (tl@t0')) *)
557           let t0' = split loc ctx0 t0 in
558           aux (tl@t0')
559   (* in aux [(fun x -> x),t] *)
560   in aux (top_split t)
561 ;;
562
563 let obj_split (o:Ast.term Ast.obj) = match o with
564   | Ast.Inductive (ls,itl) -> 
565       List.map (fun (a,b) -> a,b,Stdpp.dummy_loc)
566        (list_split var_split (fun x -> Ast.Inductive (x,itl)) [] ls@
567         list_split ity_split (fun x -> Ast.Inductive (ls,x)) [] itl)
568   | Ast.Theorem (flav,n,ty,None,p) ->
569       [(fun x -> Ast.Theorem (flav,n,x,None,p)), ty, Stdpp.dummy_loc]
570   | Ast.Theorem (flav,n,ty,(Some bo as bo'),p) ->
571       [(fun x -> Ast.Theorem (flav,n,x,bo',p)), ty, Stdpp.dummy_loc
572       ;(fun x -> Ast.Theorem (flav,n,ty,Some x,p)), bo, Stdpp.dummy_loc]
573   | Ast.Record (ls,n,ty,fl) ->
574       List.map (fun (a,b) -> a,b,Stdpp.dummy_loc)
575        (list_split var_split (fun x -> Ast.Record (x,n,ty,fl)) [] ls@
576         [(fun x -> Ast.Record (ls,n,x,fl)),ty]@
577         list_split field_split (fun x -> Ast.Record (ls,n,ty,x)) [] fl)
578 ;;
579
580 let bfvisit_obj = bfvisit obj_split;;
581
582 let bfvisit = bfvisit (fun t -> [(fun x -> x),t,Stdpp.dummy_loc]) ;;
583
584 let domain_item_of_ast = function
585   | Ast.Ident (id,_) -> DisambiguateTypes.Id id
586   | Ast.Symbol (sym,_) -> DisambiguateTypes.Symbol sym
587   | Ast.Num (n,_) -> DisambiguateTypes.Num 
588   | Ast.Case(_,Some (ityname,_),_,_) -> DisambiguateTypes.Id ityname
589   | _ -> assert false
590 ;;
591
592 let ast_of_alias_spec t alias = match (t,alias) with
593   | Ast.Ident _, GrafiteAst.Ident_alias (id,uri) -> Ast.Ident(id,`Uri uri)
594   | Ast.Case (t,_,oty,pl), GrafiteAst.Ident_alias (id,uri) -> 
595       Ast.Case (t,Some (id,Some (NReference.reference_of_string uri)),oty,pl)
596   | _, GrafiteAst.Symbol_alias (sym,uri,desc) -> Ast.Symbol (sym,Some (uri,desc))
597   | Ast.Num(m,_), GrafiteAst.Number_alias (uri,desc) -> Ast.Num(m,Some (uri,desc))
598   | _ -> assert false
599 ;;
600
601 (* returns an optional (loc*string):
602  *  - None means success (the ast is refinable)
603  *  - Some (loc,err) means refinement has failed with error err at location loc
604  *)
605 let test_interpr ~context ~metasenv ~subst ~use_coercions ~expty ~env ~universe ~uri 
606   ~interpretate_thing ~refine_thing ~ugraph ~mk_localization_tbl t =
607   try
608    let localization_tbl = mk_localization_tbl 503 in
609     let cic_thing =
610       interpretate_thing ~context ~env ~universe
611        ~uri ~is_path:false t ~localization_tbl
612     in
613     let foo () =
614            refine_thing metasenv subst context uri
615             ~use_coercions cic_thing expty ugraph ~localization_tbl
616     in match (refine_profiler.HExtlib.profile foo ()) with
617     | Ko x ->
618         let loc,err = Lazy.force x in
619         debug_print (lazy ("test_interpr error: " ^ err)); 
620         Some (loc,err)
621     | _ -> None
622   with
623      (*| Try_again msg -> Uncertain (lazy (Stdpp.dummy_loc,Lazy.force msg))
624      | Invalid_choice loc_msg -> Ko loc_msg*)
625      | Invalid_choice x -> 
626         let loc,err = Lazy.force x in Some (loc,err)
627      | _ -> None
628 ;;
629
630 exception Not_ambiguous;;
631
632 let rec disambiguate_list
633   ~context ~metasenv ~subst ~use_coercions ~expty ~env ~uri ~interpretate_thing
634   ~refine_thing ~ugraph ~visit ~universe ~mk_localization_tbl ~pp_thing ~pp_term
635   ts errors =
636
637   let disambiguate_list = 
638     disambiguate_list ~context ~metasenv ~subst ~use_coercions ~expty ~env ~uri
639       ~interpretate_thing ~refine_thing ~ugraph ~visit ~universe
640       ~mk_localization_tbl ~pp_thing ~pp_term
641   in
642   let test_interpr = test_interpr ~context ~metasenv ~subst ~use_coercions ~expty 
643     ~env ~universe ~uri ~interpretate_thing ~refine_thing ~ugraph ~mk_localization_tbl
644   in
645   let find_choices item = 
646     let a2s = function
647     | GrafiteAst.Ident_alias (_id,uri) -> uri
648     | GrafiteAst.Symbol_alias (_id,_,desc) -> desc
649     | GrafiteAst.Number_alias (_,desc) -> desc
650     in
651     let d2s = function
652     | Id id
653     | Symbol id -> id
654     | Num -> "NUM"
655     in
656     let res =
657       Environment.find item universe 
658     in
659     debug_print (lazy (Printf.sprintf "choices for %s :\n%s"
660       (d2s item) (String.concat ", " (List.map a2s res))));
661     res
662   in
663
664   let get_instances ctx t = 
665     try 
666       let choices = find_choices (domain_item_of_ast t) in
667       List.map (fun t0 -> ctx (ast_of_alias_spec t t0), t0) choices
668     with
669     | Not_found -> []
670   in
671
672   match ts with
673   | [] -> [], errors
674   | _ ->
675       (* debug_print (lazy ("disambiguate_list: t0 = " ^ pp_thing t0));  *)
676       let is_ambiguous = function
677       | Ast.Ident (_,`Ambiguous)
678       | Ast.Num (_,None)
679       | Ast.Symbol (_,None) -> true
680       | Ast.Case (_,Some (ity,None),_,_) -> true
681       | _ -> false
682       in
683       let astpp = function
684               | Ast.Ident (id,_) -> "ID " ^ id
685               | Ast.Num _ -> "NUM"
686               | Ast.Symbol (sym,_) -> "SYM " ^ sym
687               | _ -> "ERROR!"
688       in
689       let process_ast t0 =
690         (* get first ambiguous subterm (or return disambiguated term) *)
691         match visit ~pp_term is_ambiguous t0 with
692         | None -> 
693 (*            debug_print (lazy ("visit -- not ambiguous node:\n" ^ pp_thing
694  *            t0));*)
695             (* Some (t0,tl), errors *)
696             raise Not_ambiguous
697         | Some (ctx, t, loc_t) -> 
698           debug_print (lazy ("visit -- found ambiguous node: " ^ astpp t ^
699           "\nin " ^ pp_thing (ctx t)));
700           (* get possible instantiations of t *)
701           let instances = get_instances ctx t in
702           debug_print (lazy "-- possible instances:");
703 (*          List.iter 
704            (fun u0 -> debug_print (lazy ("-- instance: " ^ (pp_thing u0))))
705 instances; *)
706           (* perforate ambiguous subterms and test refinement *)
707           let instances = List.map (fun (x,a) -> (x,Some a),test_interpr x) instances in
708           debug_print (lazy "-- survivors:");
709           let survivors, defuncts = 
710             List.partition (fun (_,o) -> o = None) instances in
711           survivors, (defuncts, loc_t)
712
713       in
714       try 
715         let ts', new_errors = List.split (List.map process_ast ts) in
716         let ts' = List.map (fun ((t,_),_) -> t) (List.flatten ts') in
717         let errors' = match new_errors with
718           | (_,l)::_ -> 
719              let ne' = 
720                List.map (fun (a,b) -> a, HExtlib.unopt b) 
721                  (List.flatten (List.map fst new_errors)) in
722              let ne' = List.map (fun ((x,a),(l,e)) -> x,a,l,e) ne' in
723              (ne',l)::errors
724           | _ -> errors
725         in disambiguate_list ts' errors' 
726       with Not_ambiguous -> ts,errors
727 ;;
728
729 let disambiguate_thing 
730   ~context ~metasenv ~subst ~use_coercions
731   ~string_context_of_context ~initial_ugraph:base_univ
732   ~expty ~mk_implicit ~description_of_alias
733   ~fix_instance ~aliases ~universe
734   ~lookup_in_library ~uri ~pp_thing ~pp_term
735   ~domain_of_thing ~interpretate_thing ~refine_thing
736   ~visit ~mk_localization_tbl
737   (thing_txt,thing_txt_prefix_len,thing)
738 =
739   let env = aliases in
740
741   let test_interpr = test_interpr ~context ~metasenv ~subst ~use_coercions ~expty 
742     ~env ~universe ~uri ~interpretate_thing ~refine_thing ~ugraph:base_univ ~mk_localization_tbl
743   in
744 (* real function *)
745   let aux tl =
746     disambiguate_list ~mk_localization_tbl ~context ~metasenv ~subst
747       ~interpretate_thing ~refine_thing ~ugraph:base_univ ~visit
748       ~use_coercions ~expty ~uri ~env ~universe ~pp_thing
749       ~pp_term tl []
750   in
751   let refine t = 
752     let localization_tbl = mk_localization_tbl 503 in
753     debug_print (lazy "before interpretate_thing");
754     let t' = 
755       interpretate_thing ~context ~env ~universe ~uri ~is_path:false t ~localization_tbl
756     in 
757     debug_print (lazy "after interpretate_thing");
758      match refine_thing metasenv subst context uri ~use_coercions t' expty
759           base_univ ~localization_tbl with
760     | Ok (t',m',s',u') -> t,m',s',t',u'
761     | Uncertain x ->
762         let _,err = Lazy.force x in
763         debug_print (lazy ("refinement uncertain after disambiguation: " ^ err));
764         assert false
765     | _ -> assert false
766   in
767   match (test_interpr thing) with
768   | Some (loc,err) ->
769 (*     debug_print (lazy ("preliminary test fail: " ^ pp_thing thing)); *)
770      Disamb_failure ([[thing,None,loc,err],loc],[])
771   | None -> 
772     let res,errors = aux [thing] in
773     let res = 
774       HExtlib.filter_map (fun t ->
775         try Some (refine t)
776         with _ -> 
777 (*          debug_print (lazy ("can't interpretate/refine " ^ (pp_thing t)));*)
778                 None) res
779     in
780     (match res with
781     | [] -> Disamb_failure (errors,[])
782     | _ -> Disamb_success res) 
783 ;;
784