1 (* Copyright (C) 2004, HELM Team.
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.
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.
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.
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,
22 * For details, see the HELM World-Wide-Web page,
23 * http://helm.cs.unibo.it/
30 open DisambiguateTypes
33 module Ast = CicNotationPt
35 (* the integer is an offset to be added to each location *)
36 exception NoWellTypedInterpretation of
38 ((Stdpp.location list * string * string) list *
39 (DisambiguateTypes.domain_item * DisambiguateTypes.codomain_item) list *
40 Stdpp.location option * string Lazy.t * bool) list
41 exception PathNotWellFormed
43 (** raised when an environment is not enough informative to decide *)
44 exception Try_again of string Lazy.t
46 type aliases = bool * DisambiguateTypes.environment
47 type 'a disambiguator_input = string * int * 'a
49 type domain = domain_tree list
50 and domain_tree = Node of Stdpp.location list * domain_item * domain
52 let rec string_of_domain =
55 | Node (_,domain_item,l)::tl ->
56 DisambiguateTypes.string_of_domain_item domain_item ^
57 " [ " ^ string_of_domain l ^ " ] " ^ string_of_domain tl
59 let rec filter_map_domain f =
62 | Node (locs,domain_item,l)::tl ->
63 match f locs domain_item with
64 None -> filter_map_domain f l @ filter_map_domain f tl
65 | Some res -> res :: filter_map_domain f l @ filter_map_domain f tl
67 let rec map_domain f =
70 | Node (locs,domain_item,l)::tl ->
71 f locs domain_item :: map_domain f l @ map_domain f tl
77 | Node (locs,domain_item,l)::tl ->
78 if List.mem domain_item seen then
79 let seen,l = aux seen l in
80 let seen,tl = aux seen tl in
83 let seen,l = aux (domain_item::seen) l in
84 let seen,tl = aux seen tl in
85 seen, Node (locs,domain_item,l)::tl
90 let debug_print s = if debug then prerr_endline (Lazy.force s) else ()
93 (** print benchmark information *)
95 let max_refinements = ref 0 (* benchmarking is not thread safe *)
96 let actual_refinements = ref 0
97 let domain_size = ref 0
98 let choices_avg = ref 0.
101 let descr_of_domain_item = function
104 | Num i -> string_of_int i
106 type 'a test_result =
107 | Ok of 'a * Cic.metasenv
108 | Ko of Stdpp.location option * string Lazy.t
109 | Uncertain of Stdpp.location option * string Lazy.t
111 let refine_term metasenv context uri term ugraph ~localization_tbl =
112 (* if benchmark then incr actual_refinements; *)
114 debug_print (lazy (sprintf "TEST_INTERPRETATION: %s" (CicPp.ppterm term)));
116 let term', _, metasenv',ugraph1 =
117 CicRefine.type_of_aux' metasenv context term ugraph ~localization_tbl in
118 (Ok (term', metasenv')),ugraph1
121 let rec process_exn loc =
123 HExtlib.Localized (loc,exn) -> process_exn (Some loc) exn
124 | CicRefine.Uncertain msg ->
125 debug_print (lazy ("UNCERTAIN!!! [" ^ (Lazy.force msg) ^ "] " ^ CicPp.ppterm term)) ;
126 Uncertain (loc,msg),ugraph
127 | CicRefine.RefineFailure msg ->
128 debug_print (lazy (sprintf "PRUNED!!!\nterm%s\nmessage:%s"
129 (CicPp.ppterm term) (Lazy.force msg)));
135 let refine_obj metasenv context uri obj ugraph ~localization_tbl =
136 assert (context = []);
137 debug_print (lazy (sprintf "TEST_INTERPRETATION: %s" (CicPp.ppobj obj))) ;
139 let obj', metasenv,ugraph =
140 CicRefine.typecheck metasenv uri obj ~localization_tbl
142 (Ok (obj', metasenv)),ugraph
145 let rec process_exn loc =
147 HExtlib.Localized (loc,exn) -> process_exn (Some loc) exn
148 | CicRefine.Uncertain msg ->
149 debug_print (lazy ("UNCERTAIN!!! [" ^ (Lazy.force msg) ^ "] " ^ CicPp.ppobj obj)) ;
150 Uncertain (loc,msg),ugraph
151 | CicRefine.RefineFailure msg ->
152 debug_print (lazy (sprintf "PRUNED!!!\nterm%s\nmessage:%s"
153 (CicPp.ppobj obj) (Lazy.force msg))) ;
159 let resolve (env: codomain_item Environment.t) (item: domain_item) ?(num = "") ?(args = []) () =
161 snd (Environment.find item env) env num args
163 failwith ("Domain item not found: " ^
164 (DisambiguateTypes.string_of_domain_item item))
166 (* TODO move it to Cic *)
167 let find_in_context name context =
168 let rec aux acc = function
169 | [] -> raise Not_found
170 | Cic.Name hd :: tl when hd = name -> acc
171 | _ :: tl -> aux (acc + 1) tl
175 let interpretate_term ?(create_dummy_ids=false) ~(context: Cic.name list) ~env ~uri ~is_path ast
178 (* create_dummy_ids shouldbe used only for interpretating patterns *)
180 let rec aux ~localize loc (context: Cic.name list) = function
181 | CicNotationPt.AttributedTerm (`Loc loc, term) ->
182 let res = aux ~localize loc context term in
183 if localize then Cic.CicHash.add localization_tbl res loc;
185 | CicNotationPt.AttributedTerm (_, term) -> aux ~localize loc context term
186 | CicNotationPt.Appl (CicNotationPt.Symbol (symb, i) :: args) ->
187 let cic_args = List.map (aux ~localize loc context) args in
188 resolve env (Symbol (symb, i)) ~args:cic_args ()
189 | CicNotationPt.Appl terms ->
190 Cic.Appl (List.map (aux ~localize loc context) terms)
191 | CicNotationPt.Binder (binder_kind, (var, typ), body) ->
192 let cic_type = aux_option ~localize loc context (Some `Type) typ in
193 let cic_name = CicNotationUtil.cic_name_of_name var in
194 let cic_body = aux ~localize loc (cic_name :: context) body in
195 (match binder_kind with
196 | `Lambda -> Cic.Lambda (cic_name, cic_type, cic_body)
198 | `Forall -> Cic.Prod (cic_name, cic_type, cic_body)
200 resolve env (Symbol ("exists", 0))
201 ~args:[ cic_type; Cic.Lambda (cic_name, cic_type, cic_body) ] ())
202 | CicNotationPt.Case (term, indty_ident, outtype, branches) ->
203 let cic_term = aux ~localize loc context term in
204 let cic_outtype = aux_option ~localize loc context None outtype in
205 let do_branch ((head, _, args), term) =
206 let rec do_branch' context = function
207 | [] -> aux ~localize loc context term
208 | (name, typ) :: tl ->
209 let cic_name = CicNotationUtil.cic_name_of_name name in
210 let cic_body = do_branch' (cic_name :: context) tl in
213 | None -> Cic.Implicit (Some `Type)
214 | Some typ -> aux ~localize loc context typ
216 Cic.Lambda (cic_name, typ, cic_body)
218 do_branch' context args
220 let indtype_uri, indtype_no =
221 if create_dummy_ids then
222 (UriManager.uri_of_string "cic:/fake_indty.con", 0)
224 match indty_ident with
225 | Some (indty_ident, _) ->
226 (match resolve env (Id indty_ident) () with
227 | Cic.MutInd (uri, tyno, _) -> (uri, tyno)
229 raise (Try_again (lazy "The type of the term to be matched
232 raise (Invalid_choice (Some loc, lazy "The type of the term to be matched is not (co)inductive!")))
234 let rec fst_constructor =
236 (Ast.Pattern (head, _, _), _) :: _ -> head
237 | (Ast.Wildcard, _) :: tl -> fst_constructor tl
238 | [] -> raise (Invalid_choice (Some loc, lazy "The type of the term to be matched cannot be determined because it is an inductive type without constructors or because all patterns use wildcards"))
240 (match resolve env (Id (fst_constructor branches)) () with
241 | Cic.MutConstruct (indtype_uri, indtype_no, _, _) ->
242 (indtype_uri, indtype_no)
244 raise (Try_again (lazy "The type of the term to be matched
247 raise (Invalid_choice (Some loc, lazy "The type of the term to be matched is not (co)inductive!")))
250 match fst(CicEnvironment.get_obj CicUniv.empty_ugraph indtype_uri) with
251 Cic.InductiveDefinition (il,_,leftsno,_) ->
254 List.nth il indtype_no
255 with _ -> assert false
257 let rec count_prod t =
258 match CicReduction.whd [] t with
259 Cic.Prod (_, _, t) -> 1 + (count_prod t)
262 let rec sort branches cl =
265 let rec analyze unused unrecognized useless =
268 if unrecognized != [] then
269 raise (Invalid_choice
272 ("Unrecognized constructors: " ^
273 String.concat " " unrecognized)))
274 else if useless > 0 then
275 raise (Invalid_choice
278 ("The last " ^ string_of_int useless ^
279 "case" ^ if useless > 1 then "s are" else " is" ^
283 | (Ast.Wildcard,_)::tl when not unused ->
284 analyze true unrecognized useless tl
285 | (Ast.Pattern (head,_,_),_)::tl when not unused ->
286 analyze unused (head::unrecognized) useless tl
287 | _::tl -> analyze unused unrecognized (useless + 1) tl
289 analyze false [] 0 branches
291 let rec find_and_remove =
296 (Some loc, lazy ("Missing case: " ^ name)))
297 | ((Ast.Wildcard, _) as branch :: _) as branches ->
299 | (Ast.Pattern (name',_,_),_) as branch :: tl
303 let found,rest = find_and_remove tl in
306 let branch,tl = find_and_remove branches in
308 Ast.Pattern (name,y,args),term ->
309 if List.length args = count_prod ty - leftsno then
310 ((name,y,args),term)::sort tl cltl
315 lazy ("Wrong number of arguments for " ^ name)))
316 | Ast.Wildcard,term ->
322 (`Lambda, (CicNotationPt.Ident ("_", None), None),
325 (("wildcard",None,[]),
326 mk_lambdas (count_prod ty - leftsno)) :: sort tl cltl
331 Cic.MutCase (indtype_uri, indtype_no, cic_outtype, cic_term,
332 (List.map do_branch branches))
333 | CicNotationPt.Cast (t1, t2) ->
334 let cic_t1 = aux ~localize loc context t1 in
335 let cic_t2 = aux ~localize loc context t2 in
336 Cic.Cast (cic_t1, cic_t2)
337 | CicNotationPt.LetIn ((name, typ), def, body) ->
338 let cic_def = aux ~localize loc context def in
339 let cic_name = CicNotationUtil.cic_name_of_name name in
343 | Some t -> Cic.Cast (cic_def, aux ~localize loc context t)
345 let cic_body = aux ~localize loc (cic_name :: context) body in
346 Cic.LetIn (cic_name, cic_def, cic_body)
347 | CicNotationPt.LetRec (kind, defs, body) ->
350 (fun acc (_, (name, _), _, _) ->
351 CicNotationUtil.cic_name_of_name name :: acc)
355 let unlocalized_body = aux ~localize:false loc context' body in
356 match unlocalized_body with
357 Cic.Rel n when n <= List.length defs -> `AvoidLetInNoAppl n
358 | Cic.Appl (Cic.Rel n::l) when n <= List.length defs ->
363 let t',subst,metasenv =
364 CicMetaSubst.delift_rels [] [] (List.length defs) t
367 assert (metasenv=[]);
370 (* We can avoid the LetIn. But maybe we need to recompute l'
371 so that it is localized *)
374 CicNotationPt.AttributedTerm (_,CicNotationPt.Appl(_::l)) ->
375 let l' = List.map (aux ~localize loc context) l in
381 CicMetaSubst.DeliftingARelWouldCaptureAFreeVariable ->
383 `AddLetIn (aux ~localize loc context' body)
385 `AddLetIn unlocalized_body)
388 `AddLetIn (aux ~localize loc context' body)
390 `AddLetIn unlocalized_body
394 (fun (params, (name, typ), body, decr_idx) ->
395 let add_binders kind t =
397 (fun var t -> CicNotationPt.Binder (kind, var, t)) params t
400 aux ~localize loc context' (add_binders `Lambda body) in
402 aux_option ~localize loc context (Some `Type)
403 (HExtlib.map_option (add_binders `Pi) typ) in
405 match CicNotationUtil.cic_name_of_name name with
407 CicNotationPt.fail loc
408 "Recursive functions cannot be anonymous"
409 | Cic.Name name -> name
411 (name, decr_idx, cic_type, cic_body))
416 `Inductive -> Cic.Fix (n,inductiveFuns)
418 let coinductiveFuns =
420 (fun (name, _, typ, body) -> name, typ, body)
423 Cic.CoFix (n,coinductiveFuns)
425 let counter = ref ~-1 in
426 let build_term funs (var,_,_,_) t =
428 Cic.LetIn (Cic.Name var, fix_or_cofix !counter, t)
431 `AvoidLetInNoAppl n ->
432 let n' = List.length inductiveFuns - n in
434 | `AvoidLetIn (n,l) ->
435 let n' = List.length inductiveFuns - n in
436 Cic.Appl (fix_or_cofix n'::l)
437 | `AddLetIn cic_body ->
438 List.fold_right (build_term inductiveFuns) inductiveFuns
440 | CicNotationPt.Ident _
441 | CicNotationPt.Uri _ when is_path -> raise PathNotWellFormed
442 | CicNotationPt.Ident (name, subst)
443 | CicNotationPt.Uri (name, subst) as ast ->
444 let is_uri = function CicNotationPt.Uri _ -> true | _ -> false in
446 if is_uri ast then raise Not_found;(* don't search the env for URIs *)
447 let index = find_in_context name context in
448 if subst <> None then
449 CicNotationPt.fail loc "Explicit substitutions not allowed here";
453 if is_uri ast then (* we have the URI, build the term out of it *)
455 CicUtil.term_of_uri (UriManager.uri_of_string name)
456 with UriManager.IllFormedUri _ ->
457 CicNotationPt.fail loc "Ill formed URI"
459 resolve env (Id name) ()
463 List.map (fun uri -> UriManager.name_of_uri uri, uri) uris
470 List.assoc s ids_to_uris, aux ~localize loc context term
472 raise (Invalid_choice (Some loc, lazy "The provided explicit named substitution is trying to instantiate a named variable the object is not abstracted on"))))
474 | None -> List.map (fun uri -> uri, Cic.Implicit None) uris)
478 | Cic.Const (uri, []) ->
479 let o,_ = CicEnvironment.get_obj CicUniv.empty_ugraph uri in
480 let uris = CicUtil.params_of_obj o in
481 Cic.Const (uri, mk_subst uris)
482 | Cic.Var (uri, []) ->
483 let o,_ = CicEnvironment.get_obj CicUniv.empty_ugraph uri in
484 let uris = CicUtil.params_of_obj o in
485 Cic.Var (uri, mk_subst uris)
486 | Cic.MutInd (uri, i, []) ->
488 let o,_ = CicEnvironment.get_obj CicUniv.empty_ugraph uri in
489 let uris = CicUtil.params_of_obj o in
490 Cic.MutInd (uri, i, mk_subst uris)
492 CicEnvironment.Object_not_found _ ->
493 (* if we are here it is probably the case that during the
494 definition of a mutual inductive type we have met an
495 occurrence of the type in one of its constructors.
496 However, the inductive type is not yet in the environment
498 (*here the explicit_named_substituion is assumed to be of length 0 *)
499 Cic.MutInd (uri,i,[]))
500 | Cic.MutConstruct (uri, i, j, []) ->
501 let o,_ = CicEnvironment.get_obj CicUniv.empty_ugraph uri in
502 let uris = CicUtil.params_of_obj o in
503 Cic.MutConstruct (uri, i, j, mk_subst uris)
504 | Cic.Meta _ | Cic.Implicit _ as t ->
506 debug_print (lazy (sprintf
507 "Warning: %s must be instantiated with _[%s] but we do not enforce it"
511 (fun (s, term) -> s ^ " := " ^ CicNotationPtPp.pp_term term)
516 raise (Invalid_choice (Some loc, lazy "??? Can this happen?"))
518 CicEnvironment.CircularDependency _ ->
519 raise (Invalid_choice (None, lazy "Circular dependency in the environment"))))
520 | CicNotationPt.Implicit -> Cic.Implicit None
521 | CicNotationPt.UserInput -> Cic.Implicit (Some `Hole)
522 | CicNotationPt.Num (num, i) -> resolve env (Num i) ~num ()
523 | CicNotationPt.Meta (index, subst) ->
528 | Some term -> Some (aux ~localize loc context term))
531 Cic.Meta (index, cic_subst)
532 | CicNotationPt.Sort `Prop -> Cic.Sort Cic.Prop
533 | CicNotationPt.Sort `Set -> Cic.Sort Cic.Set
534 | CicNotationPt.Sort (`Type u) -> Cic.Sort (Cic.Type u)
535 | CicNotationPt.Sort `CProp -> Cic.Sort Cic.CProp
536 | CicNotationPt.Symbol (symbol, instance) ->
537 resolve env (Symbol (symbol, instance)) ()
538 | _ -> assert false (* god bless Bologna *)
539 and aux_option ~localize loc (context: Cic.name list) annotation = function
540 | None -> Cic.Implicit annotation
541 | Some term -> aux ~localize loc context term
543 aux ~localize:true HExtlib.dummy_floc context ast
545 let interpretate_path ~context path =
546 let localization_tbl = Cic.CicHash.create 23 in
547 (* here we are throwing away useful localization informations!!! *)
549 interpretate_term ~create_dummy_ids:true
550 ~context ~env:Environment.empty ~uri:None ~is_path:true
551 path ~localization_tbl, localization_tbl)
553 let interpretate_obj ~context ~env ~uri ~is_path obj ~localization_tbl =
554 assert (context = []);
555 assert (is_path = false);
556 let interpretate_term = interpretate_term ~localization_tbl in
558 | CicNotationPt.Inductive (params,tyl) ->
559 let uri = match uri with Some uri -> uri | None -> assert false in
563 (fun (context,res) (name,t) ->
566 None -> CicNotationPt.Implicit
568 let name = CicNotationUtil.cic_name_of_name name in
569 name::context,(name, interpretate_term context env None false t)::res
572 context,List.rev res in
574 List.fold_right (fun (name,ty) t -> Cic.Prod (name,ty,t)) params in
578 (*here the explicit_named_substituion is assumed to be of length 0 *)
579 (fun (i,res) (name,_,_,_) ->
580 i + 1,(name,name,Cic.MutInd (uri,i,[]))::res
582 let con_env = DisambiguateTypes.env_of_list name_to_uris env in
585 (fun (name,b,ty,cl) ->
586 let ty' = add_params (interpretate_term context env None false ty) in
591 add_params (interpretate_term context con_env None false ty)
599 Cic.InductiveDefinition (tyl,[],List.length params,[])
600 | CicNotationPt.Record (params,name,ty,fields) ->
601 let uri = match uri with Some uri -> uri | None -> assert false in
605 (fun (context,res) (name,t) ->
608 None -> CicNotationPt.Implicit
610 let name = CicNotationUtil.cic_name_of_name name in
611 name::context,(name, interpretate_term context env None false t)::res
614 context,List.rev res in
617 (fun (name,ty) t -> Cic.Prod (name,ty,t)) params in
618 let ty' = add_params (interpretate_term context env None false ty) in
622 (fun (context,res) (name,ty,_coercion,arity) ->
623 let context' = Cic.Name name :: context in
624 context',(name,interpretate_term context env None false ty)::res
625 ) (context,[]) fields) in
627 (*here the explicit_named_substituion is assumed to be of length 0 *)
628 let mutind = Cic.MutInd (uri,0,[]) in
629 if params = [] then mutind
632 (mutind::CicUtil.mk_rels (List.length params) (List.length fields)) in
635 (fun t (name,ty) -> Cic.Prod (Cic.Name name,ty,t))
637 let con' = add_params con in
638 let tyl = [name,true,ty',["mk_" ^ name,con']] in
639 let field_names = List.map (fun (x,_,y,z) -> x,y,z) fields in
640 Cic.InductiveDefinition
641 (tyl,[],List.length params,[`Class (`Record field_names)])
642 | CicNotationPt.Theorem (flavour, name, ty, bo) ->
643 let attrs = [`Flavour flavour] in
644 let ty' = interpretate_term [] env None false ty in
645 (match bo,flavour with
647 Cic.Constant (name,None,ty',[],attrs)
648 | Some bo,`Axiom -> assert false
650 Cic.CurrentProof (name,[],Cic.Implicit None,ty',[],attrs)
652 let bo' = Some (interpretate_term [] env None false bo) in
653 Cic.Constant (name,bo',ty',[],attrs))
655 let rec domain_of_term ?(loc = HExtlib.dummy_floc) ~context = function
656 | Ast.AttributedTerm (`Loc loc, term) ->
657 domain_of_term ~loc ~context term
658 | Ast.AttributedTerm (_, term) ->
659 domain_of_term ~loc ~context term
660 | Ast.Symbol (symbol, instance) ->
661 [ Node ([loc], Symbol (symbol, instance), []) ]
662 (* to be kept in sync with Ast.Appl (Ast.Symbol ...) *)
663 | Ast.Appl (Ast.Symbol (symbol, instance) as hd :: args)
664 | Ast.Appl (Ast.AttributedTerm (_,Ast.Symbol (symbol, instance)) as hd :: args)
668 (fun term acc -> domain_of_term ~loc ~context term @ acc)
672 Ast.AttributedTerm (`Loc loc,_) -> loc
675 [ Node ([loc], Symbol (symbol, instance), args_dom) ]
676 | Ast.Appl (Ast.Ident (name, subst) as hd :: args)
677 | Ast.Appl (Ast.AttributedTerm (_,Ast.Ident (name, subst)) as hd :: args) ->
680 (fun term acc -> domain_of_term ~loc ~context term @ acc)
684 Ast.AttributedTerm (`Loc loc,_) -> loc
688 (* the next line can raise Not_found *)
689 ignore(find_in_context name context);
690 if subst <> None then
691 Ast.fail loc "Explicit substitutions not allowed here"
696 | None -> [ Node ([loc], Id name, args_dom) ]
700 (fun dom (_, term) ->
701 let dom' = domain_of_term ~loc ~context term in
704 [ Node ([loc], Id name, terms @ args_dom) ]))
707 (fun term acc -> domain_of_term ~loc ~context term @ acc)
709 | Ast.Binder (kind, (var, typ), body) ->
710 let type_dom = domain_of_term_option ~loc ~context typ in
713 ~context:(CicNotationUtil.cic_name_of_name var :: context) body in
715 | `Exists -> [ Node ([loc], Symbol ("exists", 0), (type_dom @ body_dom)) ]
716 | _ -> type_dom @ body_dom)
717 | Ast.Case (term, indty_ident, outtype, branches) ->
718 let term_dom = domain_of_term ~loc ~context term in
719 let outtype_dom = domain_of_term_option ~loc ~context outtype in
720 let rec get_first_constructor = function
722 | (Ast.Pattern (head, _, _), _) :: _ -> [ Node ([loc], Id head, []) ]
723 | _ :: tl -> get_first_constructor tl in
726 Ast.Pattern (head, _, args), term ->
727 let (term_context, args_domain) =
729 (fun (cont, dom) (name, typ) ->
730 (CicNotationUtil.cic_name_of_name name :: cont,
733 | Some typ -> dom @ domain_of_term ~loc ~context:cont typ)))
736 domain_of_term ~loc ~context:term_context term @ args_domain
737 | Ast.Wildcard, term ->
738 domain_of_term ~loc ~context term
741 List.fold_left (fun dom branch -> dom @ do_branch branch) [] branches in
742 (match indty_ident with
743 | None -> get_first_constructor branches
744 | Some (ident, _) -> [ Node ([loc], Id ident, []) ])
745 @ term_dom @ outtype_dom @ branches_dom
746 | Ast.Cast (term, ty) ->
747 let term_dom = domain_of_term ~loc ~context term in
748 let ty_dom = domain_of_term ~loc ~context ty in
750 | Ast.LetIn ((var, typ), body, where) ->
751 let body_dom = domain_of_term ~loc ~context body in
752 let type_dom = domain_of_term_option ~loc ~context typ in
755 ~context:(CicNotationUtil.cic_name_of_name var :: context) where in
756 body_dom @ type_dom @ where_dom
757 | Ast.LetRec (kind, defs, where) ->
758 let add_defs context =
760 (fun acc (_, (var, _), _, _) ->
761 CicNotationUtil.cic_name_of_name var :: acc
763 let where_dom = domain_of_term ~loc ~context:(add_defs context) where in
766 (fun dom (params, (_, typ), body, _) ->
770 (fun acc (var,_) -> CicNotationUtil.cic_name_of_name var :: acc)
776 (fun (context,res) (var,ty) ->
777 CicNotationUtil.cic_name_of_name var :: context,
778 domain_of_term_option ~loc ~context ty @ res)
779 (add_defs context,[]) params))
780 @ domain_of_term_option ~loc ~context:context' typ
781 @ domain_of_term ~loc ~context:context' body
785 | Ast.Ident (name, subst) ->
787 (* the next line can raise Not_found *)
788 ignore(find_in_context name context);
789 if subst <> None then
790 Ast.fail loc "Explicit substitutions not allowed here"
795 | None -> [ Node ([loc], Id name, []) ]
799 (fun dom (_, term) ->
800 let dom' = domain_of_term ~loc ~context term in
803 [ Node ([loc], Id name, terms) ]))
806 | Ast.Num (num, i) -> [ Node ([loc], Num i, []) ]
807 | Ast.Meta (index, local_context) ->
809 (fun dom term -> dom @ domain_of_term_option ~loc ~context term)
816 | Ast.Variable _ -> assert false
818 and domain_of_term_option ~loc ~context = function
820 | Some t -> domain_of_term ~loc ~context t
822 let domain_of_term ~context term =
823 uniq_domain (domain_of_term ~context term)
825 let domain_of_obj ~context ast =
826 assert (context = []);
828 | Ast.Theorem (_,_,ty,bo) ->
832 | Some bo -> domain_of_term [] bo)
833 | Ast.Inductive (params,tyl) ->
836 (fun (context, dom) (var, ty) ->
837 let context' = CicNotationUtil.cic_name_of_name var :: context in
839 None -> context', dom
840 | Some ty -> context', dom @ domain_of_term context ty
842 let context_w_types =
844 (fun (var, _, _, _) -> Cic.Name var) tyl
850 domain_of_term context ty
853 (fun (_,ty) -> domain_of_term context_w_types ty) cl))
855 | CicNotationPt.Record (params,var,ty,fields) ->
858 (fun (context, dom) (var, ty) ->
859 let context' = CicNotationUtil.cic_name_of_name var :: context in
861 None -> context', dom
862 | Some ty -> context', dom @ domain_of_term context ty
864 let context_w_types = Cic.Name var :: context in
866 @ domain_of_term context ty
869 (fun (context,res) (name,ty,_,_) ->
870 Cic.Name name::context, res @ domain_of_term context ty
871 ) (context_w_types,[]) fields)
873 let domain_of_obj ~context obj =
874 uniq_domain (domain_of_obj ~context obj)
877 let domain_diff dom1 dom2 =
878 (* let domain_diff = Domain.diff *)
882 | Symbol (symb, 0) ->
884 Symbol (symb',_) when symb = symb' -> true
896 | Node (_,elt,l)::tl when is_in_dom2 elt -> aux (l @ tl)
897 | Node (loc,elt,l)::tl -> Node (loc,elt,aux l)::(aux tl)
901 module type Disambiguator =
903 val disambiguate_term :
904 ?fresh_instances:bool ->
906 context:Cic.context ->
907 metasenv:Cic.metasenv ->
908 ?initial_ugraph:CicUniv.universe_graph ->
909 aliases:DisambiguateTypes.environment ->(* previous interpretation status *)
910 universe:DisambiguateTypes.multiple_environment option ->
911 CicNotationPt.term disambiguator_input ->
912 ((DisambiguateTypes.domain_item * DisambiguateTypes.codomain_item) list *
913 Cic.metasenv * (* new metasenv *)
915 CicUniv.universe_graph) list * (* disambiguated term *)
918 val disambiguate_obj :
919 ?fresh_instances:bool ->
921 aliases:DisambiguateTypes.environment ->(* previous interpretation status *)
922 universe:DisambiguateTypes.multiple_environment option ->
923 uri:UriManager.uri option -> (* required only for inductive types *)
924 CicNotationPt.term CicNotationPt.obj disambiguator_input ->
925 ((DisambiguateTypes.domain_item * DisambiguateTypes.codomain_item) list *
926 Cic.metasenv * (* new metasenv *)
928 CicUniv.universe_graph) list * (* disambiguated obj *)
932 module Make (C: Callbacks) =
934 let choices_of_id dbd id =
935 let uris = Whelp.locate ~dbd id in
940 (C.input_or_locate_uri
941 ~title:("URI matching \"" ^ id ^ "\" unknown.") ~id ())
947 C.interactive_user_uri_choice ~selection_mode:`MULTIPLE
948 ~ok:"Try selected." ~enable_button_for_non_vars:true
949 ~title:"Ambiguous input." ~id
950 ~msg: ("Ambiguous input \"" ^ id ^
951 "\". Please, choose one or more interpretations:")
956 (UriManager.string_of_uri uri,
959 CicUtil.term_of_uri uri
961 debug_print (lazy (UriManager.string_of_uri uri));
962 debug_print (lazy (Printexc.to_string exn));
968 let refine_profiler = HExtlib.profile "disambiguate_thing.refine_thing"
970 let disambiguate_thing ~dbd ~context ~metasenv
971 ?(initial_ugraph = CicUniv.empty_ugraph) ~aliases ~universe
972 ~uri ~pp_thing ~domain_of_thing ~interpretate_thing ~refine_thing
973 (thing_txt,thing_txt_prefix_len,thing)
975 debug_print (lazy "DISAMBIGUATE INPUT");
976 let disambiguate_context = (* cic context -> disambiguate context *)
978 (function None -> Cic.Anonymous | Some (name, _) -> name)
981 debug_print (lazy ("TERM IS: " ^ (pp_thing thing)));
982 let thing_dom = domain_of_thing ~context:disambiguate_context thing in
984 (lazy (sprintf "DISAMBIGUATION DOMAIN: %s"(string_of_domain thing_dom)));
986 debug_print (lazy (sprintf "DISAMBIGUATION ENVIRONMENT: %s"
987 (DisambiguatePp.pp_environment aliases)));
988 debug_print (lazy (sprintf "DISAMBIGUATION UNIVERSE: %s"
989 (match universe with None -> "None" | Some _ -> "Some _")));
992 Environment.fold (fun item _ dom -> item :: dom) aliases [] in
993 let todo_dom = domain_diff thing_dom current_dom in
995 (lazy (sprintf "DISAMBIGUATION DOMAIN AFTER DIFF: %s"(string_of_domain todo_dom)));
996 (* (2) lookup function for any item (Id/Symbol/Num) *)
1000 let lookup_in_library () =
1002 | Id id -> choices_of_id dbd id
1003 | Symbol (symb, _) ->
1005 List.map DisambiguateChoices.mk_choice
1006 (TermAcicContent.lookup_interpretations symb)
1008 TermAcicContent.Interpretation_not_found -> [])
1010 DisambiguateChoices.lookup_num_choices ()
1013 | None -> lookup_in_library ()
1018 | Symbol (symb, _) -> Symbol (symb, 0)
1021 Environment.find item e
1022 with Not_found -> lookup_in_library ())
1029 if benchmark then begin
1030 let per_item_choices =
1034 let len = List.length (lookup_choices dom_item) in
1035 debug_print (lazy (sprintf "BENCHMARK %s: %d"
1036 (string_of_domain_item dom_item) len));
1038 with No_choices _ -> 0)
1041 max_refinements := List.fold_left ( * ) 1 per_item_choices;
1042 actual_refinements := 0;
1043 domain_size := List.length thing_dom;
1045 (float_of_int !max_refinements) ** (1. /. float_of_int !domain_size)
1051 (* (3) test an interpretation filling with meta uninterpreted identifiers
1053 let test_env aliases todo_dom ugraph =
1054 let rec aux env = function
1056 | Node (_, item, l) :: tl ->
1058 Environment.add item
1062 (fun _ _ _ -> Cic.Implicit (Some `Closed))
1063 | Symbol _ -> (fun _ _ _ -> Cic.Implicit None)))
1065 aux (aux env l) tl in
1066 let filled_env = aux aliases todo_dom in
1068 let localization_tbl = Cic.CicHash.create 503 in
1070 interpretate_thing ~context:disambiguate_context ~env:filled_env
1071 ~uri ~is_path:false thing ~localization_tbl
1075 refine_thing metasenv context uri cic_thing ugraph ~localization_tbl
1078 in refine_profiler.HExtlib.profile foo ()
1080 | Try_again msg -> Uncertain (None,msg), ugraph
1081 | Invalid_choice (loc,msg) -> Ko (loc,msg), ugraph
1083 (* (4) build all possible interpretations *)
1084 let (@@) (l1,l2,l3) (l1',l2',l3') = l1@l1', l2@l2', l3@l3' in
1085 (* aux returns triples Ok/Uncertain/Ko *)
1086 (* rem_dom is the concatenation of all the remainin domains *)
1087 let rec aux aliases diff lookup_in_todo_dom todo_dom rem_dom base_univ =
1088 debug_print (lazy ("ZZZ: " ^ string_of_domain todo_dom));
1091 assert (lookup_in_todo_dom = None);
1092 (match test_env aliases rem_dom base_univ with
1093 | Ok (thing, metasenv),new_univ ->
1094 [ aliases, diff, metasenv, thing, new_univ ], [], []
1095 | Ko (loc,msg),_ -> [],[],[aliases,diff,loc,msg,true]
1096 | Uncertain (loc,msg),new_univ ->
1097 [],[aliases,diff,loc,msg,new_univ],[])
1098 | Node (locs,item,inner_dom) :: remaining_dom ->
1099 debug_print (lazy (sprintf "CHOOSED ITEM: %s"
1100 (string_of_domain_item item)));
1102 match lookup_in_todo_dom with
1103 None -> lookup_choices item
1104 | Some choices -> choices in
1108 [aliases, diff, Some (List.hd locs),
1109 lazy ("No choices for " ^ string_of_domain_item item),
1112 | [codomain_item] ->
1113 (* just one choice. We perform a one-step look-up and
1114 if the next set of choices is also a singleton we
1115 skip this refinement step *)
1116 debug_print(lazy (sprintf "%s CHOSEN" (fst codomain_item)));
1117 let new_env = Environment.add item codomain_item aliases in
1118 let new_diff = (item,codomain_item)::diff in
1119 let lookup_in_todo_dom,next_choice_is_single =
1120 match remaining_dom with
1123 let choices = lookup_choices he in
1124 Some choices,List.length choices = 1
1126 if next_choice_is_single then
1127 aux new_env new_diff lookup_in_todo_dom remaining_dom
1130 (match test_env new_env remaining_dom base_univ with
1131 | Ok (thing, metasenv),new_univ ->
1132 (match remaining_dom with
1134 [ new_env, new_diff, metasenv, thing, new_univ ], []
1136 aux new_env new_diff lookup_in_todo_dom
1137 remaining_dom new_univ)
1138 | Uncertain (loc,msg),new_univ ->
1139 (match remaining_dom with
1140 | [] -> [], [new_env,new_diff,loc,msg,true]
1142 aux new_env new_diff lookup_in_todo_dom
1143 remaining_dom new_univ)
1144 | Ko (loc,msg),_ -> [], [new_env,new_diff,loc,msg,true])
1147 let mark_not_significant failures =
1149 (fun (env, diff, loc, msg, _b) ->
1150 env, diff, loc, msg, false)
1152 let classify_errors ((ok_l,uncertain_l,error_l) as outcome) =
1153 if ok_l <> [] || uncertain_l <> [] then
1154 ok_l,uncertain_l,mark_not_significant error_l
1157 let rec filter univ = function
1159 | codomain_item :: tl ->
1160 debug_print(lazy (sprintf "%s CHOSEN" (fst codomain_item)));
1161 let new_env = Environment.add item codomain_item aliases in
1162 let new_diff = (item,codomain_item)::diff in
1164 test_env new_env (inner_dom@remaining_dom@rem_dom) univ
1166 | Ok (thing, metasenv),new_univ ->
1168 (match inner_dom with
1170 [new_env,new_diff,metasenv,thing,new_univ], [], []
1172 aux new_env new_diff None inner_dom
1173 (remaining_dom@rem_dom) new_univ
1176 res @@ filter univ tl
1177 | Uncertain (loc,msg),new_univ ->
1179 (match inner_dom with
1180 | [] -> [],[new_env,new_diff,loc,msg,new_univ],[]
1182 aux new_env new_diff None inner_dom
1183 (remaining_dom@rem_dom) new_univ
1186 res @@ filter univ tl
1188 let res = [],[],[new_env,new_diff,loc,msg,true] in
1189 res @@ filter univ tl)
1191 let ok_l,uncertain_l,error_l =
1192 classify_errors (filter base_univ choices)
1194 let res_after_ok_l =
1196 (fun (env,diff,_,_,univ) res ->
1197 aux env diff None remaining_dom rem_dom univ @@ res
1198 ) ok_l ([],[],error_l)
1201 (fun (env,diff,_,_,univ) res ->
1202 aux env diff None remaining_dom rem_dom univ @@ res
1203 ) uncertain_l res_after_ok_l
1205 let aux' aliases diff lookup_in_todo_dom todo_dom base_univ =
1206 match test_env aliases todo_dom base_univ with
1209 aux aliases diff lookup_in_todo_dom todo_dom [] base_univ
1210 | Ko (loc,msg),_ -> [],[],[aliases,diff,loc,msg,true] in
1211 let base_univ = initial_ugraph in
1214 match aux' aliases [] None todo_dom base_univ with
1215 | [],uncertain,errors ->
1218 (fun (env,diff,loc,msg,_) -> (env,diff,loc,msg,true)
1219 ) uncertain @ errors
1223 (fun (env,diff,loc,msg,significant) ->
1226 (fun locs domain_item ->
1229 fst (Environment.find domain_item env)
1231 Some (locs,descr_of_domain_item domain_item,description)
1236 env',diff,loc,msg,significant
1239 raise (NoWellTypedInterpretation (0,errors))
1240 | [_,diff,metasenv,t,ugraph],_,_ ->
1241 debug_print (lazy "SINGLE INTERPRETATION");
1242 [diff,metasenv,t,ugraph], false
1245 (lazy (sprintf "MANY INTERPRETATIONS (%d)" (List.length l)));
1248 (fun (env, _, _, _, _) ->
1250 (fun locs domain_item ->
1252 fst (Environment.find domain_item env)
1254 locs,descr_of_domain_item domain_item, description)
1259 C.interactive_interpretation_choice
1260 thing_txt thing_txt_prefix_len choices
1262 (List.map (fun n->let _,d,m,t,u= List.nth l n in d,m,t,u) choosed),
1267 CicEnvironment.CircularDependency s ->
1268 failwith "Disambiguate: circular dependency"
1270 let disambiguate_term ?(fresh_instances=false) ~dbd ~context ~metasenv
1271 ?(initial_ugraph = CicUniv.empty_ugraph) ~aliases ~universe
1272 (text,prefix_len,term)
1275 if fresh_instances then CicNotationUtil.freshen_term term else term
1277 disambiguate_thing ~dbd ~context ~metasenv ~initial_ugraph ~aliases
1278 ~universe ~uri:None ~pp_thing:CicNotationPp.pp_term
1279 ~domain_of_thing:domain_of_term
1280 ~interpretate_thing:(interpretate_term (?create_dummy_ids:None))
1281 ~refine_thing:refine_term (text,prefix_len,term)
1283 let disambiguate_obj ?(fresh_instances=false) ~dbd ~aliases ~universe ~uri
1284 (text,prefix_len,obj)
1287 if fresh_instances then CicNotationUtil.freshen_obj obj else obj
1289 disambiguate_thing ~dbd ~context:[] ~metasenv:[] ~aliases ~universe ~uri
1290 ~pp_thing:(CicNotationPp.pp_obj CicNotationPp.pp_term) ~domain_of_thing:domain_of_obj
1291 ~interpretate_thing:interpretate_obj ~refine_thing:refine_obj
1292 (text,prefix_len,obj)