123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674(************************************************************************)(* * 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) *)(************************************************************************)openUtilopenNamestypeis_type=bool(* Module Type or just Module *)typeexport_flag=Export|Importtypeexport=(export_flag*Libobject.open_filter)option(* None for a Module Type *)letmake_onameLibobject.{obj_path;obj_mp}id=Names.(Libnames.add_path_suffixobj_pathid,KerName.makeobj_mp(Label.of_idid))type'summarynode=|CompilingLibraryofLibobject.object_prefix|OpenedModuleofis_type*export*Libobject.object_prefix*'summary|OpenedSectionofLibobject.object_prefix*'summaryletnode_prefix=function|CompilingLibraryprefix|OpenedModule(_,_,prefix,_)|OpenedSection(prefix,_)->prefixletprefix_idprefix=Libnames.basenameprefix.Libobject.obj_pathtype'summarylibrary_segment=('summarynode*Libobject.tlist)listletmodule_kindis_type=ifis_typethen"module type"else"module"typeclassified_objects={substobjs:Libobject.tlist;keepobjs:Libobject.keep_objects;escapeobjs:Libobject.escape_objects;anticipateobjs:Libobject.tlist;}letempty_classified={substobjs=[];keepobjs={keep_objects=[]};escapeobjs={escape_objects=[]};anticipateobjs=[];}letclassify_object:Libobject.t->Libobject.substitutivity=function|ModuleObject_|ModuleTypeObject_|IncludeObject_|ExportObject_->Substitute|KeepObject_->Keep|EscapeObject_->Escape|AtomicObjecto->Libobject.classify_objectoletclassify_segmentseg=letreccleanacc=function|[]->acc|o::stk->beginmatchclassify_objectowith|Dispose->cleanaccstk|Substitute->clean{accwithsubstobjs=o::acc.substobjs}stk|Keep->clean{accwithkeepobjs={keep_objects=o::acc.keepobjs.keep_objects}}stk|Escape->clean{accwithescapeobjs={escape_objects=o::acc.escapeobjs.escape_objects}}stk|Anticipate->clean{accwithanticipateobjs=o::acc.anticipateobjs}stkendincleanempty_classified(List.revseg)letfind_entries_ppstk=letrecfind=function|[]->[]|(ent,_)::l->ifpentthenent::findlelsefindlinfindstkletsplit_lib_at_openingstk=matchstkwith|[]->assertfalse|(node,leaves)::rest->List.revleaves,node,restletis_opening_node=function|OpenedSection_|OpenedModule_->true|CompilingLibrary_->falseletopen_blocks_messagees=letopenPpinletopen_block_name=function|OpenedSection(prefix,_)->str"section "++Id.print(prefix_idprefix)|OpenedModule(ty,_,prefix,_)->str(module_kindty)++spc()++Id.print(prefix_idprefix)|_->assertfalseinstr"The "++pr_enumopen_block_namees++spc()++str"need"++str(ifList.lengthes==1then"s"else"")++str" to be closed."(* We keep trace of operations in the stack [lib_stk].
[path_prefix] is the current path of sections, where sections are stored in
``correct'' order, the oldest coming first in the list. It may seems
costly, but in practice there is not so many openings and closings of
sections, but on the contrary there are many constructions of section
paths based on the library path. *)letdummy_prefix=Libobject.{obj_path=Libnames.dummy_full_path;obj_mp=ModPath.dummy;}typesynterp_state={comp_name:DirPath.toption;lib_stk:Summary.Synterp.frozenlibrary_segment;path_prefix:Libobject.object_prefix;}letdummy={comp_name=None;lib_stk=[];path_prefix=dummy_prefix;}(** The lib state is split in two components:
- The synterp stage state which manages a recording of syntax-related objects and naming-related data (compilation unit name, current prefix).
- The interp stage state which manages a recording of regular objects.
*)letsynterp_state=refdummyletinterp_state=ref([]:Summary.Interp.frozenlibrary_segment)letlibrary_info=refUserWarn.emptyletcontents()=!interp_stateletstart_compilationsmp=if!synterp_state.comp_name!=NonethenCErrors.user_errPp.(str"compilation unit is already started");assert(List.is_empty!synterp_state.lib_stk);assert(List.is_empty!interp_state);letpath=tryletprefix,id=Libnames.split_dirpathsinLibnames.make_pathprefixidwithFailure_->CErrors.anomalyPp.(str"Cannot start compilation with empty dirpath")inletprefix=Libobject.{obj_path=path;obj_mp=mp}inletinitial_stk=[CompilingLibraryprefix,[]]inletst={comp_name=Somes;path_prefix=prefix;lib_stk=initial_stk;}insynterp_state:=st;interp_state:=initial_stk;Nametab.OpenMods.push(Until1)path(DirOpenModulemp)letend_compilation_checksdir=let()=matchfind_entries_pis_opening_node!interp_statewith|[]->()|es->CErrors.user_err(open_blocks_messagees)inlet()=match!synterp_state.comp_namewith|None->CErrors.anomaly(Pp.str"There should be a module name...")|Somem->ifnot(Names.DirPath.equalmdir)thenCErrors.anomalyPp.(str"The current open module has name"++spc()++DirPath.printm++spc()++str"and not"++spc()++DirPath.printdir++str".");in()letlibrary_dp()=match!synterp_state.comp_namewithSomem->m|None->DirPath.dummy(* [path_prefix] is a pair of absolute dirpath and a pair of current
module path and relative section path *)letprefix()=!synterp_state.path_prefixletcwd()=!synterp_state.path_prefix.Libobject.obj_pathletcurrent_mp()=!synterp_state.path_prefix.Libobject.obj_mpletsections_depth()=!synterp_state.lib_stk|>List.count(function|(OpenedSection_,_)->true|((OpenedModule_|CompilingLibrary_),_)->false)letsections_are_opened()=matchsplit_lib_at_opening!synterp_state.lib_stkwith|(_,OpenedSection_,_)->true|_->falseletcwd_except_section()=Libnames.path_pop_n_suffixes(sections_depth())(cwd())letcurrent_dirpathsec=Libnames.drop_dirpath_prefix(library_dp())(Libnames.dirpath_of_path(ifsecthencwd()elsecwd_except_section()))letmake_pathid=Libnames.add_path_suffix(cwd())idletmake_path_except_sectionid=Libnames.add_path_suffix(cwd_except_section())idletmake_knid=letmp=current_mp()inNames.KerName.makemp(Names.Label.of_idid)letmake_fonameid=make_oname!synterp_state.path_prefixid(* Adding operations. *)letdummylib=CompilingLibrarydummy_prefixleterror_still_openedsoname=CErrors.user_errPp.(str"The "++strs++str" "++Id.print(prefix_idoname)++str" is still opened.")letrecalc_path_prefix()=letpath_prefix=matchpi2(split_lib_at_opening!synterp_state.lib_stk)with|CompilingLibrarydir|OpenedModule(_,_,dir,_)|OpenedSection(dir,_)->dirinsynterp_state:={!synterp_statewithpath_prefix}letpop_path_prefix()=letop=!synterp_state.path_prefixinsynterp_state:={!synterp_statewithpath_prefix=Libobject.{opwithobj_path=Libnames.path_pop_suffixop.obj_path;}}(* Modules. *)(* Returns true if we are inside an opened module or module type *)letis_module_or_modtype()=letrecaux=function|[]->assertfalse|(OpenedSection_,_)::rest->auxrest|(OpenedModule_,_)::_->true|(CompilingLibrary_,_)::_->falseinaux(!synterp_state).lib_stkletis_modtype()=List.exists(functionOpenedModule(istyp,_,_,_),_->istyp|_->false)(!synterp_state).lib_stkletis_modtype_strict()=letrecaux=function|[]->assertfalse|(OpenedSection_,_)::rest->auxrest|(OpenedModule(istyp,_,_,_),_)::_->istyp|(CompilingLibrary_,_)::_->falseinaux(!synterp_state).lib_stkletis_module()=List.exists(functionOpenedModule(istyp,_,_,_),_->notistyp|_->false)(!synterp_state).lib_stk(* Discharge tables *)(* At each level of section, we remember
- the list of variables in this section
- the list of variables on which each constant depends in this section
- the list of variables on which each inductive depends in this section
- the list of substitution to do at section closing
*)typedischarged_item=|DischargedExportofLibobject.ExportObj.t|DischargedLeafofLibobject.discharged_objletdischarge_item=Libobject.(function|ModuleObject_|ModuleTypeObject_|IncludeObject_|KeepObject_|EscapeObject_->assertfalse|ExportObjecto->Some(DischargedExporto)|AtomicObjectobj->letobj=discharge_objectobjinOption.map(funo->DischargedLeafo)obj)(* Misc *)letmp_of_global=letopenGlobRefinfunction|VarRefid->!synterp_state.path_prefix.Libobject.obj_mp|ConstRefcst->Names.Constant.modpathcst|IndRefind->Names.Ind.modpathind|ConstructRefconstr->Names.Construct.modpathconstrletrecsplit_modpath=function|Names.MPfiledp->dp,[]|Names.MPboundmbid->library_dp(),[Names.MBId.to_idmbid]|Names.MPdot(mp,l)->let(dp,ids)=split_modpathmpin(dp,Names.Label.to_idl::ids)letlibrary_part=function|GlobRef.VarRefid->library_dp()|ref->ModPath.dp(mp_of_globalref)letdebug_object_name=function|Libobject.ModuleObject_->"ModuleObject"|ModuleTypeObject_->"ModuleTypeObject"|IncludeObject_->"IncludeObject"|KeepObject_->"KeepObject"|EscapeObject_->"EscapeObject"|ExportObject_->"ExportObject"|AtomicObject(Dyn(tag,_))->Libobject.Dyn.reprtagletanomaly_unitialized_add_leafstageo=CErrors.anomalyPp.(str"cannot add object ("++str(debug_object_nameo)++pr_comma()++str"in "++strstage++str"): not initialized")(** The [LibActions] abstraction represent the set of operations on the Lib
structure that is specific to a given stage. Two instances are defined below,
for Synterp and Interp. *)moduletypeLibActions=sigtypesummaryvalstage:Summary.Stage.tvalopen_section:Id.t->unitvalclose_section:summary->unitvaladd_entry:summarynode->unitvaladd_leaf_entry:Libobject.t->unitvalstart_mod:is_type:is_type->export->Id.t->ModPath.t->summary->Libobject.object_prefixvalget_lib_stk:unit->summarylibrary_segmentvalset_lib_stk:summarylibrary_segment->unitvalpop_path_prefix:unit->unitvalrecalc_path_prefix:unit->unittypefrozenvalfreeze:unit->frozenvalunfreeze:frozen->unitvalinit:unit->unitvaldrop_objects:frozen->frozenvaldeclare_info:Library_info.t->unitendmoduleSynterpActions:LibActionswithtypesummary=Summary.Synterp.frozen=structtypesummary=Summary.Synterp.frozenletstage=Summary.Stage.Synterpletcheck_section_freshobj_pathid=ifNametab.exists_dirobj_paththenCErrors.user_errPp.(Id.printid++str" already exists.")letpush_section_nameobj_path=Nametab.(push_dir(Until1)obj_path(GlobDirRef.DirOpenSectionobj_path))letclose_sectionfs=Summary.Synterp.unfreeze_summariesfsletadd_entrynode=synterp_state:={!synterp_statewithlib_stk=(node,[])::!synterp_state.lib_stk}letadd_leaf_entryleaf=letlib_stk=match!synterp_state.lib_stkwith|[]->(* top_printers does set_bool_option_value which adds a leaf *)if!Flags.in_debuggerthen[dummylib,[leaf]]elseanomaly_unitialized_add_leaf"synterp"leaf|(node,leaves)::rest->(node,leaf::leaves)::restinsynterp_state:={!synterp_statewithlib_stk}(* Returns the opening node of a given name *)letstart_mod~is_typeexportidmpfs=letdir=Libnames.add_path_suffix!synterp_state.path_prefix.Libobject.obj_pathidinletprefix=Libobject.{obj_path=dir;obj_mp=mp;}inassert(not(sections_are_opened()));add_entry(OpenedModule(is_type,export,prefix,fs));synterp_state:={!synterp_statewithpath_prefix=prefix};prefixletget_lib_stk()=!synterp_state.lib_stkletset_lib_stkstk=synterp_state:={!synterp_statewithlib_stk=stk}letopen_sectionid=letopp=!synterp_state.path_prefixinletobj_path=Libnames.add_path_suffixopp.Libobject.obj_pathidinletprefix=Libobject.{obj_path;obj_mp=opp.obj_mp;}incheck_section_freshobj_pathid;letfs=Summary.Synterp.freeze_summaries()inadd_entry(OpenedSection(prefix,fs));(*Pushed for the lifetime of the section: removed by unfreezing the summary*)push_section_nameobj_path;synterp_state:={!synterp_statewithpath_prefix=prefix}letpop_path_prefix()=pop_path_prefix()letrecalc_path_prefix()=recalc_path_prefix()typefrozen=synterp_stateletfreeze()=!synterp_stateletunfreezest=synterp_state:=stletinit()=synterp_state:=dummyletdrop_objectsst=letdrop_node=function|CompilingLibrary_asx->x|OpenedModule(it,e,op,_)->OpenedModule(it,e,op,Summary.Synterp.empty_frozen)|OpenedSection(op,_)->OpenedSection(op,Summary.Synterp.empty_frozen)inletlib_synterp_stk=List.map(fun(node,_)->drop_nodenode,[])st.lib_stkin{stwithlib_stk=lib_synterp_stk}letdeclare_infoinfo=letopenUserWarninletdepr=match!library_info.depr,info.deprwith|None,depr|depr,None->depr|Some_,Some_->CErrors.user_errPp.(str"Library file is already deprecated.")inletwarn=!library_info.warn@info.warninlibrary_info:={depr;warn}endmoduleInterpActions:LibActionswithtypesummary=Summary.Interp.frozen=structtypesummary=Summary.Interp.frozenletstage=Summary.Stage.Interpletclose_sectionfs=Global.close_sectionfsletadd_entrynode=interp_state:=(node,[])::!interp_stateletadd_leaf_entryleaf=letlib_stk=match!interp_statewith|[]->(* top_printers does set_bool_option_value which adds a leaf *)if!Flags.in_debuggerthen[dummylib,[leaf]]elseanomaly_unitialized_add_leaf"interp"leaf|(node,leaves)::rest->(node,leaf::leaves)::restininterp_state:=lib_stk(* Returns the opening node of a given name *)letstart_mod~is_typeexportidmpfs=letprefix=!synterp_state.path_prefixinadd_entry(OpenedModule(is_type,export,prefix,fs));prefixletget_lib_stk()=!interp_stateletset_lib_stkstk=interp_state:=stkletopen_sectionid=Global.open_section();letprefix=!synterp_state.path_prefixinletfs=Summary.Interp.freeze_summaries()inadd_entry(OpenedSection(prefix,fs))letpop_path_prefix()=()letrecalc_path_prefix()=()typefrozen=summarylibrary_segmentletfreeze()=!interp_stateletunfreezest=interp_state:=stletinit()=interp_state:=[]letdrop_objectsinterp_state=letdrop_node=function|CompilingLibrary_asx->x|OpenedModule(it,e,op,_)->OpenedModule(it,e,op,Summary.Interp.empty_frozen)|OpenedSection(op,_)->OpenedSection(op,Summary.Interp.empty_frozen)inList.map(fun(node,_)->drop_nodenode,[])interp_stateletdeclare_info_=()endletadd_discharged_leafobj=letnewobj=Libobject.rebuild_objectobjinLibobject.cache_object(prefix(),newobj);matchLibobject.object_stagenewobjwith|Summary.Stage.Synterp->SynterpActions.add_leaf_entry(AtomicObjectnewobj)|Summary.Stage.Interp->InterpActions.add_leaf_entry(AtomicObjectnewobj)letadd_leafobj=Libobject.cache_object(prefix(),obj);matchLibobject.object_stageobjwith|Summary.Stage.Synterp->SynterpActions.add_leaf_entry(AtomicObjectobj)|Summary.Stage.Interp->InterpActions.add_leaf_entry(AtomicObjectobj)moduletypeStagedLibS=sigtypesummaryvalfind_opening_node:?loc:Loc.t->Id.t->summarynodevaladd_entry:summarynode->unitvaladd_leaf_entry:Libobject.t->unit(** {6 Sections } *)valopen_section:Id.t->unitvalclose_section:unit->discharged_itemlist(** {6 Modules and module types } *)valstart_module:export->Id.t->ModPath.t->summary->Libobject.object_prefixvalstart_modtype:Id.t->ModPath.t->summary->Libobject.object_prefixvalend_module:unit->Libobject.object_prefix*summary*classified_objectsvalend_modtype:unit->Libobject.object_prefix*summary*classified_objectstypefrozenvalfreeze:unit->frozenvalunfreeze:frozen->unitvalinit:unit->unitvaldrop_objects:frozen->frozenvaldeclare_info:Library_info.t->unitend(** The [StagedLib] abstraction factors out the code dealing with Lib structure
that is common to all stages. *)moduleStagedLib(Actions:LibActions):StagedLibSwithtypesummary=Actions.summary=structtypesummary=Actions.summaryletadd_entrynode=Actions.add_entrynodeletadd_leaf_entryobj=Actions.add_leaf_entryobjletopen_sectionid=Actions.open_sectionidexceptionWrongClosingBlockNameofId.t*Loc.toptionlet()=CErrors.register_handler(function|WrongClosingBlockName(id,_)->SomePp.(str"Last block to end has name "++Id.printid++str".")|_->None)let()=Quickfix.register(function|WrongClosingBlockName(id,Someloc)->[Quickfix.make~loc(Id.printid)]|_->[])letfind_opening_node?locid=letentry=matchActions.get_lib_stk()with|[]->assertfalse|(CompilingLibrary_,_)::_->CErrors.user_errPp.(str"There is nothing to end.")|(entry,_)::_->entryinletid'=prefix_id(node_prefixentry)inifnot(Names.Id.equalidid')thenLoc.raise?loc(WrongClosingBlockName(id',loc));entryletstart_module=Actions.start_mod~is_type:falseletstart_modtype=Actions.start_mod~is_type:trueNoneletend_mod~is_type=let(after,mark,before)=split_lib_at_opening(Actions.get_lib_stk())in(* The errors here should not happen because we checked in the upper layers *)letprefix,fs=matchmarkwith|OpenedModule(ty,_,prefix,fs)->ifty==is_typethenprefix,fselseerror_still_opened(module_kindty)prefix|OpenedSection(prefix,_)->error_still_opened"section"prefix|CompilingLibrary_->CErrors.user_err(Pp.str"No opened modules.")inActions.set_lib_stkbefore;Actions.recalc_path_prefix();letafter=classify_segmentafterin(prefix,fs,after)letend_module()=end_mod~is_type:falseletend_modtype()=end_mod~is_type:true(* Restore lib_stk and summaries as before the section opening, and
add a ClosedSection object. *)letclose_section()=let(secdecls,mark,before)=split_lib_at_opening(Actions.get_lib_stk())inletfs=matchmarkwith|OpenedSection(_,fs)->fs|_->CErrors.user_errPp.(str"No opened section.")inActions.set_lib_stkbefore;Actions.pop_path_prefix();letnewdecls=List.filter_mapdischarge_itemsecdeclsinActions.close_sectionfs;newdeclstypefrozen=Actions.frozenletfreeze()=Actions.freeze()letunfreezest=Actions.unfreezestletinit()=Actions.init()letdrop_objectsst=Actions.drop_objectsstletdeclare_infoinfo=Actions.declare_infoinfoendmoduleSynterp:StagedLibSwithtypesummary=Summary.Synterp.frozen=StagedLib(SynterpActions)moduleInterp:StagedLibSwithtypesummary=Summary.Interp.frozen=StagedLib(InterpActions)typecompilation_result={info:Library_info.t;synterp_objects:classified_objects;interp_objects:classified_objects;}letend_compilationdir=end_compilation_checksdir;let(syntax_after,_,syntax_before)=split_lib_at_opening!synterp_state.lib_stkinlet(after,_,before)=split_lib_at_opening!interp_stateinassert(List.is_emptysyntax_before);assert(List.is_emptybefore);synterp_state:={!synterp_statewithcomp_name=None};letsyntax_after=classify_segmentsyntax_afterinletafter=classify_segmentafterin{info=!library_info;interp_objects=after;synterp_objects=syntax_after;}(** Compatibility layer *)letinit()=Synterp.init();Interp.init();Summary.Synterp.init_summaries();Summary.Interp.init_summaries()