123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574(************************************************************************)(* * 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) *)(************************************************************************)(* This module manages customization parameters at the vernacular level *)openUtilopenSummary.Stagetypeoption_name=stringlisttypeoption_value=|BoolValueofbool|IntValueofintoption|StringValueofstring|StringOptValueofstringoptiontypetable_value=|StringRefValueofstring|QualidRefValueofLibnames.qualid(** Summary of an option status *)typeoption_state={opt_depr:Deprecation.toption;opt_value:option_value;}(****************************************************************************)(* 0- Common things *)letnicknametable=String.concat" "tableleterror_no_table_of_this_type~kindkey=CErrors.user_errPp.(str("There is no "^kind^"-valued table with this name: \""^nicknamekey^"\"."))leterror_undeclared_keykey=CErrors.user_errPp.(str("There is no flag, option or table with this name: \""^nicknamekey^"\"."))(****************************************************************************)(* 1- Tables *)type'atable_of_A={add:Environ.env->'a->unit;remove:Environ.env->'a->unit;mem:Environ.env->'a->unit;print:unit->unit;}letopts_cat=Libobject.create_category"options"moduleMakeTable=functor(A:sigtypettypekeymoduleSet:CSig.USetSwithtypeelt=tvaltable:(string*keytable_of_A)listrefvalencode:Environ.env->key->tvalsubst:Mod_subst.substitution->t->tvalprinter:t->Pp.tvalkey:option_namevaltitle:stringvalmember_message:t->bool->Pp.tend)->structtypeoption_mark=|GOadd|GOrmvletnick=nicknameA.keylet()=ifString.List.mem_assocnick!A.tablethenCErrors.user_errPp.(strbrk"Sorry, this table name ("++strnick++strbrk") is already used.")moduleMySet=A.Setlett=Summary.ref~stage:Summary.Stage.SynterpMySet.empty~name:nicklet(add_option,remove_option)=letcache_options(f,p)=matchfwith|GOadd->t:=MySet.addp!t|GOrmv->t:=MySet.removep!tinletload_optionsio=ifInt.equali1thencache_optionsoinletsubst_options(subst,(f,pasobj))=letp'=A.substsubstpinifp'==pthenobjelse(f,p')inletinGo:option_mark*A.t->Libobject.obj=Libobject.declare_object{(Libobject.default_objectnick)withLibobject.object_stage=Summary.Stage.Synterp;Libobject.load_function=load_options;Libobject.open_function=Libobject.simple_open~cat:opts_catload_options;Libobject.cache_function=cache_options;Libobject.subst_function=subst_options;Libobject.classify_function=(funx->Substitute)}in((func->Lib.add_leaf(inGo(GOadd,c))),(func->Lib.add_leaf(inGo(GOrmv,c))))letprint_tabletable_nameprintertable=letopenPpinletpp=ifMySet.is_emptytablethenstrtable_name++str" is empty."elsestrtable_name++str":"++spc()++(hov0(prlist_with_sepspcprinter(MySet.elementstable)))++str"."inFeedback.msg_noticepplettable_of_A={add=(funenvx->add_option(A.encodeenvx));remove=(funenvx->remove_option(A.encodeenvx));mem=(funenvx->lety=A.encodeenvxinletanswer=MySet.memy!tinFeedback.msg_info(A.member_messageyanswer));print=(fun()->print_tableA.titleA.printer!t);}let_=A.table:=(nick,table_of_A)::!A.tableletv()=!tletactivex=A.Set.memx!tletsetxb=ifbthenadd_optionxelseremove_optionxendletstring_table=ref[]letget_string_tablek=String.List.assoc(nicknamek)!string_tablemoduletypeStringConvertArg=sigvalkey:option_namevaltitle:stringvalmember_message:string->bool->Pp.tendmoduleStringConvert=functor(A:StringConvertArg)->structtypet=stringtypekey=stringmoduleSet=CString.Setlettable=string_tableletencode_envx=xletsubst_x=xletprinter=Pp.strletkey=A.keylettitle=A.titleletmember_message=A.member_messageendmoduleMakeStringTable=functor(A:StringConvertArg)->MakeTable(StringConvert(A))letref_table=ref[]letget_ref_tablek=String.List.assoc(nicknamek)!ref_tablemoduletypeRefConvertArg=sigtypetmoduleSet:CSig.USetSwithtypeelt=tvalencode:Environ.env->Libnames.qualid->tvalsubst:Mod_subst.substitution->t->tvalprinter:t->Pp.tvalkey:option_namevaltitle:stringvalmember_message:t->bool->Pp.tendmoduleRefConvert=functor(A:RefConvertArg)->structtypet=A.ttypekey=Libnames.qualidmoduleSet=A.Setlettable=ref_tableletencode=A.encodeletsubst=A.substletprinter=A.printerletkey=A.keylettitle=A.titleletmember_message=A.member_messageendmoduleMakeRefTable=functor(A:RefConvertArg)->MakeTable(RefConvert(A))typeiter_table_aux={aux:'a.'atable_of_A->Environ.env->'a->unit}letiter_tableenvfkeylv=letaux=function|StringRefValues->begintryf.aux(get_string_tablekey)envswithNot_found->error_no_table_of_this_type~kind:"string"keyend|QualidRefValuelocqid->begintryf.aux(get_ref_tablekey)envlocqidwithNot_found->error_no_table_of_this_type~kind:"qualid"keyendinList.iterauxlv(****************************************************************************)(* 2- Flags. *)type'aoption_sig={optstage:Summary.Stage.t;optdepr:Deprecation.toption;optkey:option_name;optread:unit->'a;optwrite:'a->unit}typeoption_locality=OptDefault|OptLocal|OptExport|OptGlobaltypeoption_mod=OptSet|OptAppendmoduleOptionOrd=structtypet=option_nameletcompareopt1opt2=List.compareString.compareopt1opt2endmoduleOptionMap=Map.Make(OptionOrd)letvalue_tab=refOptionMap.empty(* This raises Not_found if option of key [key] is unknown *)letget_optionkey=OptionMap.findkey!value_tabletcheck_keykey=trylet_=get_optionkeyinCErrors.user_errPp.(str"Sorry, this option name ("++str(nicknamekey)++str") is already used.")withNot_found->ifString.List.mem_assoc(nicknamekey)!string_table||String.List.mem_assoc(nicknamekey)!ref_tablethenCErrors.user_errPp.(str"Sorry, this option name ("++str(nicknamekey)++str") is already used.")openLibobjectletwarn_deprecated_option=Deprecation.create_warning~object_name:"Option"~warning_name_if_no_since:"deprecated-option"(funkey->Pp.str(nicknamekey))letdeclare_optioncastuncastappend?(preprocess=funx->x){optstage=stage;optdepr=depr;optkey=key;optread=read;optwrite=write}=check_keykey;letdefault=read()inletchange=let()=Summary.declare_summary(nicknamekey){stage;Summary.freeze_function=read;Summary.unfreeze_function=write;Summary.init_function=(fun()->writedefault)}inletcache_options(l,m,v)=matchmwith|OptSet->writev|OptAppend->write(append(read())v)inletload_optionsi(l,_,_aso)=matchlwith|OptGlobal->cache_optionso|OptExport->()|OptLocal|OptDefault->(* Ruled out by classify_function *)assertfalseinletopen_optionsi(l,_,_aso)=matchlwith|OptExport->ifInt.equali1thencache_optionso|OptGlobal->()|OptLocal|OptDefault->(* Ruled out by classify_function *)assertfalseinletsubst_options(subst,obj)=objinletdischarge_options(l,_,_aso)=matchlwithOptLocal->None|(OptExport|OptGlobal|OptDefault)->Someoinletclassify_options(l,_,_)=matchlwith(OptExport|OptGlobal)->Substitute|(OptLocal|OptDefault)->Disposeinletoptions:option_locality*option_mod*_->obj=declare_object{(default_object(nicknamekey))withobject_stage=stage;load_function=load_options;open_function=simple_open~cat:opts_catopen_options;cache_function=cache_options;subst_function=subst_options;discharge_function=discharge_options;classify_function=classify_options}in(funlmv->letv=preprocessvinLib.add_leaf(options(l,m,v)))inletwarn()=depr|>Option.iter(fundepr->warn_deprecated_option(key,depr))inletcread()=cast(read())inletcwritelv=warn();changelOptSet(uncastv)inletcappendlv=warn();changelOptAppend(uncastv)invalue_tab:=OptionMap.addkey(depr,stage,(cread,cwrite,cappend))!value_tabletdeclare_int_option=declare_option(funv->IntValuev)(functionIntValuev->v|_->CErrors.anomaly(Pp.str"async_option."))(fun__->CErrors.anomaly(Pp.str"async_option."))letdeclare_bool_option=declare_option(funv->BoolValuev)(functionBoolValuev->v|_->CErrors.anomaly(Pp.str"async_option."))(fun__->CErrors.anomaly(Pp.str"async_option."))letdeclare_string_option=declare_option(funv->StringValuev)(functionStringValuev->v|_->CErrors.anomaly(Pp.str"async_option."))(funxy->x^","^y)letdeclare_stringopt_option=declare_option(funv->StringOptValuev)(functionStringOptValuev->v|_->CErrors.anomaly(Pp.str"async_option."))(fun__->CErrors.anomaly(Pp.str"async_option."))type'agetter={get:unit->'a}type'aopt_decl=?stage:Summary.Stage.t->?depr:Deprecation.t->key:option_name->value:'a->unit->'agetterletdeclare_int_option_and_ref?(stage=Interp)?depr~key~(value:int)()=letr_opt=refvalueinletoptwritev=r_opt:=Option.defaultvaluevinletoptread()=Some!r_optinlet()=declare_int_option{optstage=stage;optdepr=depr;optkey=key;optread;optwrite;}in{get=fun()->!r_opt}letdeclare_intopt_option_and_ref?(stage=Interp)?depr~key~value()=letr_opt=refvalueinletoptwritev=r_opt:=vinletoptread()=!r_optinlet()=declare_int_option{optstage=stage;optdepr=depr;optkey=key;optread;optwrite}in{get=optread}letdeclare_nat_option_and_ref?(stage=Interp)?depr~key~(value:int)()=assert(value>=0);letr_opt=refvalueinletoptwritev=letv=Option.defaultvaluevinifv<0thenCErrors.user_errPp.(str"This option expects a non-negative value.");r_opt:=vinletoptread()=Some!r_optinlet()=declare_int_option{optstage=stage;optdepr=depr;optkey=key;optread;optwrite}in{get=fun()->!r_opt}letdeclare_bool_option_and_ref?(stage=Interp)?depr~key~(value:bool)()=letr_opt=refvalueinletoptwritev=r_opt:=vinletoptread()=!r_optinlet()=declare_bool_option{optstage=stage;optdepr=depr;optkey=key;optread;optwrite}in{get=optread}letdeclare_string_option_and_ref?(stage=Interp)?depr~key~(value:string)()=letr_opt=refvalueinletoptwritev=r_opt:=Option.defaultvaluevinletoptread()=Some!r_optinlet()=declare_stringopt_option{optstage=stage;optdepr=depr;optkey=key;optread;optwrite}in{get=fun()->!r_opt}letdeclare_stringopt_option_and_ref?(stage=Interp)?depr~key~value()=letr_opt=refvalueinletoptwritev=r_opt:=vinletoptread()=!r_optinlet()=declare_stringopt_option{optstage=stage;optdepr=depr;optkey=key;optread;optwrite}in{get=optread}letdeclare_interpreted_string_option_and_reffrom_stringto_string?(stage=Interp)?depr~key~(value:'a)()=letr_opt=refvalueinletoptwritev=r_opt:=Option.defaultvalue@@Option.mapfrom_stringvinletoptread()=Some(to_string!r_opt)inlet()=declare_stringopt_option{optstage=stage;optdepr=depr;optkey=key;optread;optwrite}in{get=fun()->!r_opt}(* 3- User accessible commands *)(* Setting values of options *)letwarn_unknown_option=CWarnings.create~name:"unknown-option"Pp.(funkey->strbrk"There is no flag or option with this name: \""++str(nicknamekey)++str"\".")letget_option_valuekey=trylet(_,_,(read,write,append))=get_optionkeyinSomereadwithNot_found->None(** Sets the option only if [stage] matches the option declaration or if [stage]
is omitted. If the option is not found, a warning is emitted only if the stage
is [Interp] or omitted. *)letset_option_value?(locality=OptDefault)?stagecheck_and_castkeyv=letopt=trySome(get_optionkey)withNot_found->Noneinmatchoptwith|None->beginmatchstagewithNone|SomeSummary.Stage.Interp->warn_unknown_optionkey|_->()end|Some(depr,option_stage,(read,write,append))->ifOption.cata(funs->s=option_stage)truestagethenwritelocality(check_and_castv(read()))letbad_type_error~expected~got=CErrors.user_errPp.(strbrk"Bad type of value for this option:"++spc()++str"expected "++strexpected++str", got "++strgot++str".")leterror_flag()=CErrors.user_errPp.(str"This is a flag. It does not take a value.")letcheck_int_valuev=function|BoolValue_->error_flag()|IntValue_->IntValuev|StringValue_|StringOptValue_->bad_type_error~expected:"string"~got:"int"letcheck_bool_valuev=function|BoolValue_->BoolValuev|_->CErrors.user_errPp.(str"This is an option. A value must be provided.")letcheck_string_valuev=function|BoolValue_->error_flag()|IntValue_->bad_type_error~expected:"int"~got:"string"|StringValue_->StringValuev|StringOptValue_->StringOptValue(Somev)letcheck_unset_valuev=function|BoolValue_->BoolValuefalse|IntValue_->IntValueNone|StringOptValue_->StringOptValueNone|StringValue_->CErrors.user_errPp.(str"This option does not support the \"Unset\" command.")(* Nota: For compatibility reasons, some errors are treated as
warnings. This allows a script to refer to an option that doesn't
exist anymore *)letset_int_option_value_gen?locality?stage=set_option_value?locality?stagecheck_int_valueletset_bool_option_value_gen?locality?stagekeyv=set_option_value?locality?stagecheck_bool_valuekeyvletset_string_option_value_gen?locality?stage=set_option_value?locality?stagecheck_string_valueletunset_option_value_gen?locality?stagekey=set_option_value?locality?stagecheck_unset_valuekey()letset_string_option_append_value_gen?(locality=OptDefault)?stagekeyv=letopt=trySome(get_optionkey)withNot_found->Noneinmatchoptwith|None->warn_unknown_optionkey|Some(depr,option_stage,(read,write,append))->ifOption.cata(funs->s=option_stage)truestagethenappendlocality(check_string_valuev(read()))letset_int_option_value?stageoptv=set_int_option_value_gen?stageoptvletset_bool_option_value?stageoptv=set_bool_option_value_gen?stageoptvletset_string_option_value?stageoptv=set_string_option_value_gen?stageoptv(* Printing options/tables *)letmsg_option_value=Pp.(function|BoolValuetrue->str"on"|BoolValuefalse->str"off"|IntValue(Somen)->intn|IntValueNone->str"undefined"|StringValues->quote(strs)|StringOptValueNone->str"undefined"|StringOptValue(Somes)->quote(strs))letprint_option_valuekey=let(depr,_stage,(read,_,_))=get_optionkeyinlets=read()inmatchswith|BoolValueb->Feedback.msg_noticePp.(prlist_with_sepspcstrkey++str" is "++str(ifbthen"on"else"off"))|_->Feedback.msg_noticePp.(str"Current value of "++prlist_with_sepspcstrkey++str" is "++msg_option_values)letget_tables()=lettables=!value_tabinletfoldkey(depr,_stage,(read,_,_))accu=letstate={opt_depr=depr;opt_value=read();}inOptionMap.addkeystateaccuinOptionMap.foldfoldtablesOptionMap.emptyletprint_tables()=letopenPpinletprint_optionkeyvaluedepr=letmsg=str" "++str(nicknamekey)++str": "++msg_option_valuevalueinletdepr=pr_opt(fundepr->hov2(str"[DEPRECATED"++pr_opt(funsince->str"since "++strsince)depr.Deprecation.since++pr_optstrdepr.Deprecation.note++str"]"))deprinmsg++depr++fnl()instr"Options:"++fnl()++OptionMap.fold(funkey(depr,_stage,(read,_,_))p->p++print_optionkey(read())depr)!value_tab(mt())++str"Tables:"++fnl()++List.fold_right(fun(nickkey,_)p->p++str" "++strnickkey++fnl())!string_table(mt())++List.fold_right(fun(nickkey,_)p->p++str" "++strnickkey++fnl())!ref_table(mt())++fnl()