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