123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365(************************************************************************)(* * The Coq Proof Assistant / The Coq Development Team *)(* v * Copyright INRIA, CNRS and contributors *)(* <O___,, * (see version control and CREDITS file for authors & dates) *)(* \VV/ **************************************************************)(* // * This file is distributed under the terms of the *)(* * GNU Lesser General Public License Version 2.1 *)(* * (see LICENSE file for the text of the license) *)(************************************************************************)openPpopenUtilopenNamesopenConstropenDeclarationsopenLibobjectopenEnvironopenPatternopenLibnamesopenVernacexprmoduleNamedDecl=Context.Named.Declarationtypefilter_function=GlobRef.t->Decls.logical_kindoption->env->Evd.evar_map->constr->booltypedisplay_function=GlobRef.t->Decls.logical_kindoption->env->Evd.evar_map->constr->unit(* This option restricts the output of [SearchPattern ...], etc.
to the names of the symbols matching the
query, separated by a newline. This type of output is useful for
editors (like emacs), to generate a list of completion candidates
without having to parse through the types of all symbols. *)typeglob_search_item=|GlobSearchSubPatternofglob_search_where*bool*constr_pattern|GlobSearchStringofstring|GlobSearchKindofDecls.logical_kind|GlobSearchFilterof(GlobRef.t->bool)typeglob_search_request=|GlobSearchLiteralofglob_search_item|GlobSearchDisjConjof(bool*glob_search_request)listlistmoduleSearchBlacklist=Goptions.MakeStringTable(structletkey=["Search";"Blacklist"]lettitle="Current search blacklist : "letmember_messagesb=str"Search blacklist does "++(ifbthenmt()elsestr"not ")++str"include "++strsend)(* The functions iter_constructors and iter_declarations implement the behavior
needed for the Coq searching commands.
These functions take as first argument the procedure
that will be called to treat each entry. This procedure receives the name
of the object, the assumptions that will make it possible to print its type,
and the constr term that represent its type. *)letiter_constructorsindspufnenvsigmanconstr=fori=1tonconstrdolettyp=Inductive.type_of_constructor((indsp,i),u)(Inductive.lookup_mind_specifenvindsp)infn(GlobRef.ConstructRef(indsp,i))Noneenvsigmatypdone(* FIXME: this is a Libobject hack that should be replaced with a proper
registration mechanism. *)moduleDynHandle=Libobject.Dyn.Map(structtype'at='a->unitend)lethandleh(Libobject.Dyn.Dyn(tag,o))=matchDynHandle.findtaghwith|f->fo|exceptionNot_found->()(* General search over declarations *)letgeneric_searchenvsigma(fn:GlobRef.t->Decls.logical_kindoption->env->Evd.evar_map->constr->unit)=List.iter(fund->fn(GlobRef.VarRef(NamedDecl.get_idd))Noneenvsigma(NamedDecl.get_typed))(Environ.named_contextenv);letiter_objprefixlobj=matchlobjwith|AtomicObjecto->lethandler=DynHandle.addDeclare.Internal.Constant.tagbeginfun(id,obj)->letkn=KerName.makeprefix.Nametab.obj_mp(Label.of_idid)inletcst=Global.constant_of_delta_knkninletgr=GlobRef.ConstRefcstinlet(typ,_)=Typeops.type_of_global_in_context(Global.env())grinletkind=Declare.Internal.Constant.kindobjinfngr(Somekind)envsigmatypend@@DynHandle.addDeclareInd.Internal.objInductivebeginfun(id,_)->letkn=KerName.makeprefix.Nametab.obj_mp(Label.of_idid)inletmind=Global.mind_of_delta_knkninletmib=Global.lookup_mindmindinletiter_packetimip=letind=(mind,i)inletu=UVars.make_abstract_instance(Declareops.inductive_polymorphic_contextmib)inlettyp=Inductive.type_of_inductive(Inductive.lookup_mind_specifenvind,u)inlet()=fn(GlobRef.IndRefind)Noneenvsigmatypinletlen=Array.lengthmip.mind_user_lciniter_constructorsindufnenvsigmaleninArray.iteriiter_packetmib.mind_packetsend@@DynHandle.emptyinhandlehandlero|_->()intryDeclaremods.iter_all_interp_segmentsiter_objwithNot_found->()(** This module defines a preference on constrs in the form of a
[compare] function (preferred constr must be big for this
functions, so preferences such as small constr must use a reversed
order). This priority will be used to order search results and
propose first results which are more likely to be relevant to the
query, this is why the type [t] contains the other elements
required of a search. *)moduleConstrPriority=struct(* The priority is memoised here. Because of the very localised use
of this module, it is not worth it making a convenient interface. *)typet=GlobRef.t*Decls.logical_kindoption*Environ.env*Evd.evar_map*Constr.t*priorityandpriority=intmoduleConstrSet=CSet.Make(Constr)(** A measure of the size of a term *)letrecsizet=Constr.fold(funst->1+s+sizet)0t(** Set of the "symbols" (definitions, inductives, constructors)
which appear in a term. *)letrecsymbolsacct=letopenConstrinmatchkindtwith|Const_|Ind_|Construct_->ConstrSet.addtacc|_->Constr.foldsymbolsacct(** The number of distinct "symbols" (see {!symbols}) which appear
in a term. *)letnum_symbolst=ConstrSet.(cardinal(symbolsemptyt))letprioritygreft:priority=-(3*(num_symbolst)+sizet)letcompare(_,_,_,_,_,p1)(_,_,_,_,_,p2)=Stdlib.comparep1p2endmodulePriorityQueue=Heap.Functional(ConstrPriority)letreciter_priority_queueqfn=(* Tail-rec! *)matchPriorityQueue.maximumqwith|(gref,kind,env,sigma,t,_)->fngrefkindenvsigmat;iter_priority_queue(PriorityQueue.removeq)fn|exceptionHeap.EmptyHeap->()letprioritize_searchseqfn=letacc=refPriorityQueue.emptyinletitergrefkindenvsigmat=letp=ConstrPriority.prioritygreftinacc:=PriorityQueue.add(gref,kind,env,sigma,t,p)!accinlet()=seqiteriniter_priority_queue!accfn(** Filters *)(** This function tries to see whether the conclusion matches a pattern.
FIXME: this is quite dummy, we may find a more efficient algorithm. *)letrecpattern_filterpatrefenvsigmatyp=lettyp=Termops.strip_outer_castsigmatypinifConstr_matching.is_matchingenvsigmapattypthentrueelsematchEConstr.kindsigmatypwith|Prod(_,_,typ)|LetIn(_,_,_,typ)->pattern_filterpatrefenvsigmatyp|_->falseletfull_name_of_referenceref=let(dir,id)=repr_path(Nametab.path_of_globalref)inDirPath.to_stringdir^"."^Id.to_stringid(** Whether a reference is blacklisted *)letblacklist_filterrefkindenvsigmatyp=letname=full_name_of_referencerefinletis_not_blstr=not(String.string_contains~where:name~what:str)inCString.Set.for_allis_not_bl(SearchBlacklist.v())letmodule_filtermodsrefkindenvsigmatyp=letsp=Nametab.path_of_globalrefinletsl=dirpathspinmatchmodswith|SearchOutsidemods->letis_outsidemd=not(is_dirpath_prefix_ofmdsl)inList.for_allis_outsidemods|SearchInsidemods->letis_insidemd=is_dirpath_prefix_ofmdslinList.is_emptymods||List.existsis_insidemodsletname_of_referenceref=Id.to_string(Nametab.basename_of_globalref)letsearch_filterquerygrkindenvsigmatyp=matchquerywith|GlobSearchSubPattern(where,head,pat)->letopenContext.Rel.Declarationinletreccollectenvhypstyp=matchConstr.kindtypwith|LetIn(na,b,t,c)->collect(push_rel(LocalDef(na,b,t))env)((env,b)::(env,t)::hyps)c|Prod(na,t,c)->collect(push_rel(LocalAssum(na,t))env)((env,t)::hyps)c|_->(hyps,(env,typ))inlettypl=matchwherewith|InHyp->fst(collectenv[]typ)|InConcl->[snd(collectenv[]typ)]|Anywhere->ifheadthenlethyps,ccl=collectenv[]typinccl::hypselse[env,typ]inList.exists(fun(env,typ)->letf=ifheadthenConstr_matching.is_matching_headelseConstr_matching.is_matching_appsubterm~closed:falseinfenvsigmapat(EConstr.of_constrtyp))typl|GlobSearchStrings->String.string_contains~where:(name_of_referencegr)~what:s|GlobSearchKindk->(matchkindwithNone->false|Somek'->k=k')|GlobSearchFilterf->fgr(** SearchPattern *)letsearch_patternenvsigmapatmodspr_search=letfilterrefkindenvsigmatyp=module_filtermodsrefkindenvsigmatyp&&pattern_filterpatrefenvsigma(EConstr.of_constrtyp)&&blacklist_filterrefkindenvsigmatypinletiterrefkindenvsigmatyp=iffilterrefkindenvsigmatypthenpr_searchrefkindenvsigmatypingeneric_searchenvsigmaiter(** SearchRewrite *)leteq()=Coqlib.(lib_ref"core.eq.type")letrewrite_pat1pat=PApp(PRef(eq()),[|PMetaNone;pat;PMetaNone|])letrewrite_pat2pat=PApp(PRef(eq()),[|PMetaNone;PMetaNone;pat|])letsearch_rewriteenvsigmapatmodspr_search=letpat1=rewrite_pat1patinletpat2=rewrite_pat2patinletfilterrefkindenvsigmatyp=module_filtermodsrefkindenvsigmatyp&&(pattern_filterpat1refenvsigma(EConstr.of_constrtyp)||pattern_filterpat2refenvsigma(EConstr.of_constrtyp))&&blacklist_filterrefkindenvsigmatypinletiterrefkindenvsigmatyp=iffilterrefkindenvsigmatypthenpr_searchrefkindenvsigmatypingeneric_searchenvsigmaiter(** Search *)letsearchenvsigmaitemsmodspr_search=letfilterrefkindenvsigmatyp=leteqbb1b2=ifb1thenb2elsenotb2inmodule_filtermodsrefkindenvsigmatyp&&letrecaux=function|GlobSearchLiterali->search_filterirefkindenvsigmatyp|GlobSearchDisjConjl->List.exists(List.for_allaux')landaux'(b,s)=eqbb(auxs)inList.for_allaux'items&&blacklist_filterrefkindenvsigmatypinletiterrefkindenvsigmatyp=iffilterrefkindenvsigmatypthenpr_searchrefkindenvsigmatypingeneric_searchenvsigmaitertypesearch_constraint=|Name_PatternofStr.regexp|Type_PatternofPattern.constr_pattern|SubType_PatternofPattern.constr_pattern|In_ModuleofNames.DirPath.t|Include_Blacklisttype'acoq_object={coq_object_prefix:stringlist;coq_object_qualid:stringlist;coq_object_object:'a;}letinterface_searchenvsigma=letrecextract_flagsnametpesubtpemodsblacklist=function|[]->(name,tpe,subtpe,mods,blacklist)|(Name_Patternregexp,b)::l->extract_flags((regexp,b)::name)tpesubtpemodsblacklistl|(Type_Patternpat,b)::l->extract_flagsname((pat,b)::tpe)subtpemodsblacklistl|(SubType_Patternpat,b)::l->extract_flagsnametpe((pat,b)::subtpe)modsblacklistl|(In_Moduleid,b)::l->extract_flagsnametpesubtpe((id,b)::mods)blacklistl|(Include_Blacklist,b)::l->extract_flagsnametpesubtpemodsblinfunflags->let(name,tpe,subtpe,mods,blacklist)=extract_flags[][][][]falseflagsinletfilter_functionrefenvsigmaconstr=letid=Names.Id.to_string(Nametab.basename_of_globalref)inletpath=Libnames.dirpath(Nametab.path_of_globalref)inlettogglexb=ifxthenbelsenotbinletmatch_name(regexp,flag)=toggle(Str.string_matchregexpid0)flaginletmatch_type(pat,flag)=toggle(Constr_matching.is_matchingenvsigmapat(EConstr.of_constrconstr))flaginletmatch_subtype(pat,flag)=toggle(Constr_matching.is_matching_appsubterm~closed:falseenvsigmapat(EConstr.of_constrconstr))flaginletmatch_module(mdl,flag)=toggle(Libnames.is_dirpath_prefix_ofmdlpath)flaginList.for_allmatch_namename&&List.for_allmatch_typetpe&&List.for_allmatch_subtypesubtpe&&List.for_allmatch_modulemods&&(blacklist||blacklist_filterrefkindenvsigmaconstr)inletans=ref[]inletprint_functionrefenvsigmaconstr=letfullpath=DirPath.repr(Nametab.dirpath_of_globalref)inletqualid=Nametab.shortest_qualid_of_globalId.Set.emptyrefinlet(shortpath,basename)=Libnames.repr_qualidqualidinletshortpath=DirPath.reprshortpathin(* [shortpath] is a suffix of [fullpath] and we're looking for the missing
prefix *)letrecprefixfullshortaccu=matchfull,shortwith|_,[]->letfull=List.rev_mapId.to_stringfullin(full,accu)|_::full,m::short->prefixfullshort(Id.to_stringm::accu)|_->assertfalseinlet(prefix,qualid)=prefixfullpathshortpath[Id.to_stringbasename]inletanswer={coq_object_prefix=prefix;coq_object_qualid=qualid;coq_object_object=constr;}inans:=answer::!ans;inletiterrefkindenvsigmatyp=iffilter_functionrefenvsigmatypthenprint_functionrefenvsigmatypinlet()=generic_searchenvsigmaiterin!ans