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/
26 (* $Id: disambiguate.ml 9178 2008-11-12 12:09:52Z tassi $ *)
30 open DisambiguateTypes
33 module Ast = CicNotationPt
35 let debug_print _ = ();;
37 let cic_name_of_name = function
38 | Ast.Ident (n, None) -> n
42 let refine_term metasenv subst context uri term _ ~localization_tbl =
44 debug_print (lazy (sprintf "TEST_INTERPRETATION: %s"
45 (NCicPp.ppterm ~metasenv ~subst ~context term)));
48 try NCicUntrusted.NCicHash.find localization_tbl t
49 with Not_found -> assert false
51 let metasenv, subst, term, _ =
52 NCicRefiner.typeof metasenv subst context term None ~localise
54 Disambiguate.Ok (term, metasenv, subst, ())
56 | NCicRefiner.Uncertain loc_msg ->
57 debug_print (lazy ("UNCERTAIN: [" ^ snd (Lazy.force loc_msg) ^ "] " ^
58 NCicPp.ppterm ~metasenv ~subst ~context term)) ;
59 Disambiguate.Uncertain loc_msg
60 | NCicRefiner.RefineFailure loc_msg ->
61 debug_print (lazy (sprintf "PRUNED:\nterm%s\nmessage:%s"
62 (NCicPp.ppterm ~metasenv ~subst ~context term) (snd(Lazy.force loc_msg))));
63 Disambiguate.Ko loc_msg
66 let resolve (env: codomain_item Environment.t) (item: domain_item) ?(num = "") ?(args = []) () =
70 snd (Environment.find item env) env num args
72 failwith ("Domain item not found: " ^
73 (DisambiguateTypes.string_of_domain_item item))
76 (* TODO move it to Cic *)
77 let find_in_context name context =
78 let rec aux acc = function
79 | [] -> raise Not_found
80 | Cic.Name hd :: _ when hd = name -> acc
81 | _ :: tl -> aux (acc + 1) tl
86 ?(create_dummy_ids=false) ~context ~env ~uri ~is_path ast ~localization_tbl
88 (* create_dummy_ids shouldbe used only for interpretating patterns *)
91 let rec aux ~localize loc context = function
92 | CicNotationPt.AttributedTerm (`Loc loc, term) ->
93 let res = aux ~localize loc context term in
94 if localize then NCicUntrusted.NCicHash.add localization_tbl res loc;
96 | CicNotationPt.AttributedTerm (_, term) -> aux ~localize loc context term
97 | CicNotationPt.Appl (CicNotationPt.Symbol (symb, i) :: args) ->
98 let cic_args = List.map (aux ~localize loc context) args in
99 resolve env (Symbol (symb, i)) ~args:cic_args ()
100 | CicNotationPt.Appl terms ->
101 NCic.Appl (List.map (aux ~localize loc context) terms)
102 | CicNotationPt.Binder (binder_kind, (var, typ), body) ->
103 let cic_type = aux_option ~localize loc context (Some `Type) typ in
104 let cic_name = cic_name_of_name var in
105 let cic_body = aux ~localize loc (cic_name :: context) body in
106 (match binder_kind with
107 | `Lambda -> NCic.Lambda (cic_name, cic_type, cic_body)
109 | `Forall -> NCic.Prod (cic_name, cic_type, cic_body)
111 resolve env (Symbol ("exists", 0))
112 ~args:[ cic_type; NCic.Lambda (cic_name, cic_type, cic_body) ] ())
113 | CicNotationPt.Case (term, indty_ident, outtype, branches) ->
114 let cic_term = aux ~localize loc context term in
115 let cic_outtype = aux_option ~localize loc context None outtype in
116 let do_branch ((_, _, args), term) =
117 let rec do_branch' context = function
118 | [] -> aux ~localize loc context term
119 | (name, typ) :: tl ->
120 let cic_name = cic_name_of_name name in
121 let cic_body = do_branch' (cic_name :: context) tl in
124 | None -> NCic.Implicit `Type
125 | Some typ -> aux ~localize loc context typ
127 NCic.Lambda (cic_name, typ, cic_body)
129 do_branch' context args
131 let indtype_uri, indtype_no =
132 if create_dummy_ids then
133 (UriManager.uri_of_string "cic:/fake_indty.con", 0)
135 match indty_ident with
136 | Some (indty_ident, _) ->
137 (match resolve env (Id indty_ident) () with
138 | NCic.Const (NRef.Ref (uri, NRef.Ind (_, tyno))) -> (uri, tyno)
140 raise (Disambiguate.Try_again
141 (lazy "The type of the term to be matched is still unknown"))
143 raise (DisambiguateTypes.Invalid_choice
145 lazy "The type of the term to be matched is not (co)inductive!")))
147 let rec fst_constructor =
149 (Ast.Pattern (head, _, _), _) :: _ -> head
150 | (Ast.Wildcard, _) :: tl -> fst_constructor tl
151 | [] -> 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"))
153 (match resolve env (Id (fst_constructor branches)) () with
154 | NCic.MutConstruct (indtype_uri, indtype_no, _, _) ->
155 (indtype_uri, indtype_no)
157 raise (Disambiguate.Try_again (lazy "The type of the term to be matched
160 raise (DisambiguateTypes.Invalid_choice (Some loc, lazy "The type of the term to be matched is not (co)inductive!")))
163 if create_dummy_ids then
166 Ast.Wildcard,term -> ("wildcard",None,[]), term
168 raise (DisambiguateTypes.Invalid_choice (Some loc, lazy "Syntax error: the left hand side of a branch patterns must be \"_\""))
171 match fst(CicEnvironment.get_obj CicUniv.oblivion_ugraph indtype_uri) with
172 NCic.InductiveDefinition (il,_,leftsno,_) ->
175 List.nth il indtype_no
176 with _ -> assert false
178 let rec count_prod t =
179 match CicReduction.whd [] t with
180 NCic.Prod (_, _, t) -> 1 + (count_prod t)
183 let rec sort branches cl =
186 let rec analyze unused unrecognized useless =
189 if unrecognized != [] then
190 raise (DisambiguateTypes.Invalid_choice
193 ("Unrecognized constructors: " ^
194 String.concat " " unrecognized)))
195 else if useless > 0 then
196 raise (DisambiguateTypes.Invalid_choice
199 ("The last " ^ string_of_int useless ^
200 "case" ^ if useless > 1 then "s are" else " is" ^
204 | (Ast.Wildcard,_)::tl when not unused ->
205 analyze true unrecognized useless tl
206 | (Ast.Pattern (head,_,_),_)::tl when not unused ->
207 analyze unused (head::unrecognized) useless tl
208 | _::tl -> analyze unused unrecognized (useless + 1) tl
210 analyze false [] 0 branches
212 let rec find_and_remove =
216 (DisambiguateTypes.Invalid_choice
217 (Some loc, lazy ("Missing case: " ^ name)))
218 | ((Ast.Wildcard, _) as branch :: _) as branches ->
220 | (Ast.Pattern (name',_,_),_) as branch :: tl
224 let found,rest = find_and_remove tl in
227 let branch,tl = find_and_remove branches in
229 Ast.Pattern (name,y,args),term ->
230 if List.length args = count_prod ty - leftsno then
231 ((name,y,args),term)::sort tl cltl
234 (DisambiguateTypes.Invalid_choice
236 lazy ("Wrong number of arguments for " ^ name)))
237 | Ast.Wildcard,term ->
243 (`Lambda, (CicNotationPt.Ident ("_", None), None),
246 (("wildcard",None,[]),
247 mk_lambdas (count_prod ty - leftsno)) :: sort tl cltl
252 NCic.MutCase (indtype_uri, indtype_no, cic_outtype, cic_term,
253 (List.map do_branch branches))
254 | CicNotationPt.Cast (t1, t2) ->
255 let cic_t1 = aux ~localize loc context t1 in
256 let cic_t2 = aux ~localize loc context t2 in
257 NCic.Cast (cic_t1, cic_t2)
258 | CicNotationPt.LetIn ((name, typ), def, body) ->
259 let cic_def = aux ~localize loc context def in
260 let cic_name = cic_name_of_name name in
263 | None -> NCic.Implicit (Some `Type)
264 | Some t -> aux ~localize loc context t
266 let cic_body = aux ~localize loc (cic_name :: context) body in
267 NCic.LetIn (cic_name, cic_def, cic_typ, cic_body)
268 | CicNotationPt.LetRec (kind, defs, body) ->
271 (fun acc (_, (name, _), _, _) ->
272 cic_name_of_name name :: acc)
276 let unlocalized_body = aux ~localize:false loc context' body in
277 match unlocalized_body with
278 NCic.Rel n when n <= List.length defs -> `AvoidLetInNoAppl n
279 | NCic.Appl (NCic.Rel n::l) when n <= List.length defs ->
284 let t',subst,metasenv =
285 CicMetaSubst.delift_rels [] [] (List.length defs) t
288 assert (metasenv=[]);
291 (* We can avoid the LetIn. But maybe we need to recompute l'
292 so that it is localized *)
295 CicNotationPt.AttributedTerm (_,CicNotationPt.Appl(_::l)) ->
296 (* since we avoid the letin, the context has no
298 let l' = List.map (aux ~localize loc context) l in
304 CicMetaSubst.DeliftingARelWouldCaptureAFreeVariable ->
306 `AddLetIn (aux ~localize loc context' body)
308 `AddLetIn unlocalized_body)
311 `AddLetIn (aux ~localize loc context' body)
313 `AddLetIn unlocalized_body
317 (fun (params, (name, typ), body, decr_idx) ->
318 let add_binders kind t =
320 (fun var t -> CicNotationPt.Binder (kind, var, t)) params t
323 aux ~localize loc context' (add_binders `Lambda body) in
325 aux_option ~localize loc context (Some `Type)
326 (HExtlib.map_option (add_binders `Pi) typ) in
328 match cic_name_of_name name with
330 CicNotationPt.fail loc
331 "Recursive functions cannot be anonymous"
332 | NCic.Name name -> name
334 (name, decr_idx, cic_type, cic_body))
339 `Inductive -> NCic.Fix (n,inductiveFuns)
341 let coinductiveFuns =
343 (fun (name, _, typ, body) -> name, typ, body)
346 NCic.CoFix (n,coinductiveFuns)
348 let counter = ref ~-1 in
349 let build_term _ (var,_,ty,_) t =
351 NCic.LetIn (NCic.Name var, fix_or_cofix !counter, ty, t)
354 `AvoidLetInNoAppl n ->
355 let n' = List.length inductiveFuns - n in
357 | `AvoidLetIn (n,l) ->
358 let n' = List.length inductiveFuns - n in
359 NCic.Appl (fix_or_cofix n'::l)
360 | `AddLetIn cic_body ->
361 List.fold_right (build_term inductiveFuns) inductiveFuns
363 | CicNotationPt.Ident _
364 | CicNotationPt.Uri _ when is_path -> raise Disambiguate.PathNotWellFormed
365 | CicNotationPt.Ident (name, subst)
366 | CicNotationPt.Uri (name, subst) as ast ->
367 let is_uri = function CicNotationPt.Uri _ -> true | _ -> false in
369 if is_uri ast then raise Not_found;(* don't search the env for URIs *)
370 let index = find_in_context name context in
371 if subst <> None then
372 CicNotationPt.fail loc "Explicit substitutions not allowed here";
376 if is_uri ast then (* we have the URI, build the term out of it *)
378 CicUtil.term_of_uri (UriManager.uri_of_string name)
379 with UriManager.IllFormedUri _ ->
380 CicNotationPt.fail loc "Ill formed URI"
382 resolve env (Id name) ()
386 List.map (fun uri -> UriManager.name_of_uri uri, uri) uris
393 List.assoc s ids_to_uris, aux ~localize loc context term
395 raise (Invalid_choice (Some loc, lazy "The provided explicit named substitution is trying to instantiate a named variable the object is not abstracted on"))))
397 | None -> List.map (fun uri -> uri, NCic.Implicit None) uris)
401 | NCic.Const (uri, []) ->
402 let o,_ = CicEnvironment.get_obj CicUniv.oblivion_ugraph uri in
403 let uris = CicUtil.params_of_obj o in
404 NCic.Const (uri, mk_subst uris)
405 | NCic.Var (uri, []) ->
406 let o,_ = CicEnvironment.get_obj CicUniv.oblivion_ugraph uri in
407 let uris = CicUtil.params_of_obj o in
408 NCic.Var (uri, mk_subst uris)
409 | NCic.MutInd (uri, i, []) ->
411 let o,_ = CicEnvironment.get_obj CicUniv.oblivion_ugraph uri in
412 let uris = CicUtil.params_of_obj o in
413 NCic.MutInd (uri, i, mk_subst uris)
415 CicEnvironment.Object_not_found _ ->
416 (* if we are here it is probably the case that during the
417 definition of a mutual inductive type we have met an
418 occurrence of the type in one of its constructors.
419 However, the inductive type is not yet in the environment
421 (*here the explicit_named_substituion is assumed to be of length 0 *)
422 NCic.MutInd (uri,i,[]))
423 | NCic.MutConstruct (uri, i, j, []) ->
424 let o,_ = CicEnvironment.get_obj CicUniv.oblivion_ugraph uri in
425 let uris = CicUtil.params_of_obj o in
426 NCic.MutConstruct (uri, i, j, mk_subst uris)
427 | NCic.Meta _ | NCic.Implicit _ as t ->
429 debug_print (lazy (sprintf
430 "Warning: %s must be instantiated with _[%s] but we do not enforce it"
434 (fun (s, term) -> s ^ " := " ^ CicNotationPtPp.pp_term term)
439 raise (Invalid_choice (Some loc, lazy "??? Can this happen?"))
441 CicEnvironment.CircularDependency _ ->
442 raise (Invalid_choice (None, lazy "Circular dependency in the environment"))))
443 | CicNotationPt.Implicit -> NCic.Implicit None
444 | CicNotationPt.UserInput -> NCic.Implicit (Some `Hole)
445 | CicNotationPt.Num (num, i) -> resolve env (Num i) ~num ()
446 | CicNotationPt.Meta (index, subst) ->
451 | Some term -> Some (aux ~localize loc context term))
454 NCic.Meta (index, cic_subst)
455 | CicNotationPt.Sort `Prop -> NCic.Sort NCic.Prop
456 | CicNotationPt.Sort `Set -> NCic.Sort NCic.Set
457 | CicNotationPt.Sort (`Type u) -> NCic.Sort (NCic.Type u)
458 | CicNotationPt.Sort (`CProp u) -> NCic.Sort (NCic.CProp u)
459 | CicNotationPt.Symbol (symbol, instance) ->
460 resolve env (Symbol (symbol, instance)) ()
461 | _ -> assert false (* god bless Bologna *)
462 and aux_option ~localize loc context annotation = function
463 | None -> NCic.Implicit annotation
464 | Some term -> aux ~localize loc context term
466 aux ~localize:true HExtlib.dummy_floc context ast
468 let interpretate_term ?(create_dummy_ids=false) ~context ~env ~uri ~is_path ast
471 let context = List.map (function None -> NCic.Anonymous | Some (n,_) -> n) context in
472 interpretate_term ~create_dummy_ids ~context ~env ~uri ~is_path ast
476 let domain_of_term ~context =
477 let context = List.map (fun x -> NCic.Name (fst x)) context in
478 Disambiguate.domain_of_ast_term ~context
481 module Make (C : DisambiguateTypes.Callbacks) = struct
482 module Disambiguator = Disambiguate.Make(C)
484 let disambiguate_term ?(fresh_instances=false) ~dbd ~context ~metasenv
485 ?(initial_ugraph = ()) ~aliases ~universe
486 (text,prefix_len,term)
489 if fresh_instances then CicNotationUtil.freshen_term term else term
491 let localization_tbl = NCic.NCicHash.create 503 in
492 Disambiguator.disambiguate_thing
493 ~dbd ~context ~metasenv ~initial_ugraph ~aliases
494 ~universe ~uri:None ~pp_thing:CicNotationPp.pp_term
495 ~domain_of_thing:domain_of_term
496 ~interpretate_thing:(interpretate_term (?create_dummy_ids:None))
497 ~refine_thing:refine_term (text,prefix_len,term)