123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321(************************************************************************)(* * The Rocq Prover / The Rocq 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) *)(************************************************************************)openUtil(* Dump of globalization (to be used by coqdoc) *)typeglob_file={vfile:string;vofile:string}typeglob_output=|NoGlob|Feedback|MultFilesofglob_file|FileofstringmoduleCache:sigtypetvalmake:unit->tvalwith_cache:t->string->(string->unit)->unitend=structtypet=String.Set.trefletmake()=refString.Set.emptyletwith_cachecachedataf=ifString.Set.memdata!cachethen()elselet()=cache:=String.Set.adddata!cacheinfdataendtypeglob_state=|StNoGlob|StFeedback|StChannelof{chan:out_channel;cache:Cache.t}letglob_output=ref[]letget_output()=match!glob_outputwith|[]->StNoGlob|g::_->gletpush_outputg=letg=matchgwith|NoGlob->StNoGlob|Feedback->StFeedback|MultFiles{vofile;vfile}->letch=open_out(Filename.chop_extensionvofile^".glob")inlet()=output_stringch"DIGEST "inlet()=output_stringch(Digest.to_hex(Digest.filevfile))inlet()=output_charch'\n'inStChannel{chan=ch;cache=Cache.make()}|Filef->letch=open_outfinlet()=output_stringch"DIGEST NO\n"inStChannel{chan=ch;cache=Cache.make()}inglob_output:=g::!glob_outputletpop_output()=match!glob_outputwith|[]->CErrors.anomaly(Pp.str"No output left to pop")|hd::ds->let()=matchhdwith|StNoGlob|StFeedback->()|StChannelch->close_outch.chaninglob_output:=dsletpause()=push_outputNoGlobletcontinue=pop_outputletwith_glob_outputgf()=push_outputg;tryletres=f()inpop_output();reswithreraise->letreraise=Exninfo.capturereraiseinpop_output();Exninfo.iraisereraiseletdump()=get_output()<>StNoGlobletdump_strings=matchget_output()with|StNoGlob|StFeedback->()|StChannelch->output_stringch.chansopenDeclsopenDeclarationslettype_of_logical_kind=function|IsDefinitiondef->(matchdefwith|Definition|Let|LetContext->"def"|Coercion->"coe"|SubClass->"subclass"|CanonicalStructure->"canonstruc"|Example->"ex"|Fixpoint->"def"|CoFixpoint->"def"|Scheme->"scheme"|StructureComponent->"proj"|IdentityCoercion->"coe"|Instance->"inst"|Method->"meth")|IsAssumptiona->(matchawith|Definitional->"defax"|Logical->"prfax"|Conjectural->"prfax"|Context->"prfax")|IsProofth->(matchthwith|Theorem|Lemma|Fact|Remark|Property|Proposition|Corollary->"thm")|IsPrimitive->"prim"|IsSymbol->"symb"(** Data associated to global parameters and constants *)letcsttab=Summary.ref(Names.Cmap.empty:logical_kindNames.Cmap.t)~name:"CONSTANT"letadd_constant_kindknk=csttab:=Names.Cmap.addknk!csttabletconstant_kindkn=Names.Cmap.findkn!csttablettype_of_global_refgr=ifTypeclasses.is_class(Global.env())grthen"class"elseletopenNames.GlobRefinmatchgrwith|ConstRefcst->letknd=tryconstant_kindcstwithNot_found->IsDefinitionDefinitionintype_of_logical_kindknd|VarRefv->letknd=tryDecls.variable_kindvwithNot_found->IsDefinitionDefinitionin"var"^type_of_logical_kindknd|IndRefind->let(mib,oib)=Inductive.lookup_mind_specif(Global.env())indinifoib.Declarations.mind_record<>Declarations.NotRecordthenbeginmatchmib.Declarations.mind_finitewith|Finite->"indrec"|BiFinite->"rec"|CoFinite->"corec"endelsebeginmatchmib.Declarations.mind_finitewith|Finite->"ind"|BiFinite->"variant"|CoFinite->"coind"end|ConstructRef_->"constr"letremove_sectionsdir=letcwd=Libnames.dirpath_of_path@@Lib.cwd_except_section()inifLibnames.is_dirpath_prefix_ofcwddirthen(* Not yet (fully) discharged *)cwdelse(* Theorem/Lemma outside its outer section of definition *)dirletintervalloc=letloc1,loc2=Loc.unloclocinloc1,loc2-1letdump_ref?locfilepathmodpathidentty=matchget_output()with|StFeedback->Option.iter(funloc->Feedback.feedback(Feedback.GlobRef(loc,filepath,modpath,ident,ty)))loc|StNoGlob->()|StChannelch->Option.iter(funloc->letbl,el=intervallocinletpayload=Printf.sprintf"R%d:%d %s %s %s %s\n"blelfilepathmodpathidenttyinCache.with_cachech.cachepayloaddump_string)locletdump_reference?locmodpathidentty=letfilepath=Names.DirPath.to_string(Lib.library_dp())indump_ref?locfilepathmodpathidenttyletdump_secvar?locid=dump_reference?loc"<>"(Libnames.string_of_qualid(Decls.variable_secpathid))"var"letdump_modref?locmpty=let(dp,l)=Lib.split_modpathmpinletfilepath=Names.DirPath.to_stringdpinletmodpath=Names.DirPath.to_string(Names.DirPath.makel)inletident="<>"indump_ref?locfilepathmodpathidenttyletdump_libref?locdpty=dump_ref?loc(Names.DirPath.to_stringdp)"<>""<>"tyletcook_notation(from,df)sc=(* We encode notations so that they are space-free and still human-readable *)(* - all spaces are replaced by _ *)(* - all _ denoting a non-terminal symbol are replaced by x *)(* - all terminal tokens are surrounded by single quotes, including '_' *)(* which already denotes terminal _ *)(* - all single quotes in terminal tokens are doubled *)(* - characters < 32 are represented by '^A, '^B, '^C, etc *)(* The output is decoded in function Index.prepare_entry of coqdoc *)letntn=Bytes.make(String.lengthdf*5)'_'inletj=ref0inletl=String.lengthdf-1inleti=ref0inletopenBytesin(* Bytes.set *)while!i<=ldoassert(df.[!i]!=' ');ifdf.[!i]=='_'&&(Int.equal!il||df.[!i+1]==' ')then(* Next token is a non-terminal *)(setntn!j'x';incrj;incri)elsebegin(* Next token is a terminal *)setntn!j'\'';incrj;while!i<=l&&df.[!i]!=' 'doifdf.[!i]<' 'thenletc=char_of_int(int_of_char'A'+int_of_chardf.[!i]-1)in(String.blit("'^"^String.make1c)0ntn!j3;j:=!j+3;incri)elsebeginifdf.[!i]=='\''then(setntn!j'\'';incrj);setntn!jdf.[!i];incrj;incrienddone;setntn!j'\'';incrjend;if!i<=lthen(setntn!j'_';incrj;incri)done;letdf=Bytes.sub_stringntn0!jinletdf_sc=matchscwithSomesc->":"^sc^":"^df|_->"::"^dfinletfrom_df_sc=matchfromwith|Constrexpr.InCustomEntryfrom->letsp=Nametab.CustomEntries.to_pathfromin":"^Libnames.string_of_pathsp^df_sc|Constrexpr.InConstrEntry->":"^df_scinfrom_df_scletdump_notation_locationposldf(((path,secpath),_),sc)=ifdump()thenletpath=Names.DirPath.to_stringpathinletsecpath=Names.DirPath.to_stringsecpathinletdf=cook_notationdfscinList.iter(funl->dump_ref~loc:(Loc.make_locl)pathsecpathdf"not")poslletadd_glob_gen?locsplib_dpty=ifdump()thenletmod_dp,id=Libnames.repr_pathspinletmod_dp=remove_sectionsmod_dpinletmod_dp_trunc=Libnames.drop_dirpath_prefixlib_dpmod_dpinletfilepath=Names.DirPath.to_stringlib_dpinletmodpath=Names.DirPath.to_stringmod_dp_truncinletident=Names.Id.to_stringidindump_ref?locfilepathmodpathidenttyletadd_glob?locref=ifdump()thenletsp=Nametab.path_of_globalrefinletlib_dp=Lib.library_partrefinletty=type_of_global_refrefinadd_glob_gen?locsplib_dptyletmp_of_knkn=letmp,l=Names.KerName.reprkninNames.MPdot(mp,l)letadd_glob_kn?lockn=ifdump()thenletsp=Nametab.path_of_abbreviationkninletlib_dp=Names.ModPath.dp(mp_of_knkn)inadd_glob_gen?locsplib_dp"abbrev"letdump_def?loctysecpathid=Option.iter(funloc->ifget_output()=StFeedbackthenFeedback.feedback(Feedback.GlobDef(loc,id,secpath,ty))elseletbl,el=intervallocindump_string(Printf.sprintf"%s %d:%d %s %s\n"tyblelsecpathid))locletdump_definition{CAst.loc;v=id}secs=dump_def?locs(Names.DirPath.to_string(Lib.current_dirpathsec))(Names.Id.to_stringid)letdump_constraint{CAst.loc;v=n}secty=matchnwith|Names.Nameid->dump_definitionCAst.(make?locid)secty|Names.Anonymous->()letdump_moddef?locmpty=let(dp,l)=Lib.split_modpathmpinletmp=Names.DirPath.to_string(Names.DirPath.makel)indump_def?locty"<>"mpletdump_notation{CAst.loc;v=df}scsec=Option.iter(funloc->(* We dump the location of the opening '"' *)leti=fst(Loc.unlocloc)inletlocation=(Loc.make_loc(i,i+1))indump_def~loc:location"not"(Names.DirPath.to_string(Lib.current_dirpathsec))(cook_notationdfsc))locletdump_binding?locuid=dump_def?loc"binder""<>"uid