123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282(************************************************************************)(* * 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) *)(************************************************************************)openUtilopenPpopenCErrorsopenVernactypestypevernac_keep_as=VtKeepAxiom|VtKeepDefined|VtKeepOpaquetypevernac_qed_type=VtKeepofvernac_keep_as|VtDroptypevernac_when=|VtNow|VtLatertypevernac_classification=(* Start of a proof *)|VtStartProofofvernac_start(* Command altering the global state, bad for parallel
processing. *)|VtSideffofvernac_sideff_type(* End of a proof *)|VtQedofvernac_qed_type(* A proof step *)|VtProofStepof{proof_block_detection:proof_block_nameoption}(* Queries are commands assumed to be "pure", that is to say, they
don't modify the interpretation state. *)|VtQuery(* Commands that change the current proof mode *)|VtProofModeofPvernac.proof_mode(* To be removed *)|VtMetaandvernac_start=opacity_guarantee*Names.Id.tlistandvernac_sideff_type=Names.Id.tlist*vernac_whenandopacity_guarantee=|GuaranteesOpacity(** Only generates opaque terms at [Qed] *)|Doesn'tGuaranteeOpacity(** May generate transparent terms even with [Qed].*)andsolving_tac=bool(** a terminator *)andanon_abstracting_tac=bool(** abstracting anonymously its result *)andproof_block_name=string(** open type of delimiters *)typevernac_command=?loc:Loc.t->atts:Attributes.vernac_flags->unit->typed_vernactypeplugin_args=Genarg.raw_generic_argumentlist(* Table of vernac entries *)letvernac_tab=(Hashtbl.create211:(Vernacexpr.extend_name,bool*(plugin_args->vernac_command))Hashtbl.t)letvinterp_adddeprsf=Hashtbl.replacevernac_tabs(depr,f)letvinterp_maps=tryHashtbl.findvernac_tabswithNot_found->user_err(str"Cannot find vernac command "++strs.ext_entry++str".")letwarn_deprecated_command=letopenCWarningsincreate~name:"deprecated-command"~category:CWarnings.CoreCategories.deprecated(funpr->str"Deprecated vernacular command: "++pr)(* Interpretation of a vernac command *)lettype_vernacopnconverted_args?loc~atts=letdepr,callback=vinterp_mapopninlet()=ifdeprthenletrules=Egramml.get_extend_vernac_ruleopninletpr_gram=function|Egramml.GramTerminals->strs|Egramml.GramNonTerminal_->str"_"inletpr=pr_sequencepr_gramrulesinwarn_deprecated_commandpr;incallbackconverted_args?loc~atts(** VERNAC EXTEND registering *)typeclassifier=Genarg.raw_generic_argumentlist->vernac_classification(** Classifiers *)moduleStringPair=structtypet=string*stringletcompare(s1,s2)(t1,t2)=letc=String.compares1t1inifInt.equalc0thenString.compares2t2elsecendmoduleStringPairMap=Map.Make(StringPair)letclassifiers:classifierarrayStringPairMap.tref=refStringPairMap.emptyletget_vernac_classifiereargs=letopenVernacexprin(StringPairMap.find(e.ext_plugin,e.ext_entry)!classifiers).(e.ext_index)argsletdeclare_vernac_classifiernamef=classifiers:=StringPairMap.addnamef!classifiersletclassify_as_query=VtQueryletclassify_as_sideeff=VtSideff([],VtLater)letclassify_as_proofstep=VtProofStep{proof_block_detection=None}type(_,_)ty_sig=|TyNil:(vernac_command,vernac_classification)ty_sig|TyTerminal:string*('r,'s)ty_sig->('r,'s)ty_sig|TyNonTerminal:('a,'b,'c)Extend.ty_user_symbol*('r,'s)ty_sig->('a->'r,'a->'s)ty_sigtypety_ml=TyML:bool*('r,'s)ty_sig*'r*'soption->ty_mllettype_error()=CErrors.anomaly(Pp.str"Ill-typed VERNAC EXTEND")letrecuntype_classifier:typers.(r,s)ty_sig->s->classifier=function|TyNil->funfargs->beginmatchargswith|[]->f|_::_->type_error()end|TyTerminal(_,ty)->funfargs->untype_classifiertyfargs|TyNonTerminal(tu,ty)->funfargs->letopenGenarginbeginmatchargswith|[]->type_error()|GenArg(Rawwittag,v)::args->matchGenarg.genarg_type_eqtag(Egramml.proj_symboltu)with|None->type_error()|SomeRefl->untype_classifierty(fv)argsend(** Stupid GADTs forces us to duplicate the definition just for typing *)letrecuntype_command:typers.(r,s)ty_sig->r->plugin_args->vernac_command=function|TyNil->funfargs->beginmatchargswith|[]->f|_::_->type_error()end|TyTerminal(_,ty)->funfargs->untype_commandtyfargs|TyNonTerminal(tu,ty)->funfargs->letopenGenarginbeginmatchargswith|[]->type_error()|GenArg(Rawwittag,v)::args->matchgenarg_type_eqtag(Egramml.proj_symboltu)with|None->type_error()|SomeRefl->untype_commandty(fv)argsendletrecuntype_user_symbol:typesabc.(a,b,c)Extend.ty_user_symbol->(s,Gramlib.Grammar.norec,a)Pcoq.Symbol.t=letopenExtendinfunction|TUlist1l->Pcoq.Symbol.list1(untype_user_symboll)|TUlist1sep(l,s)->Pcoq.Symbol.list1sep(untype_user_symboll)(Pcoq.Symbol.tokens[Pcoq.TPattern(Pcoq.terminals)])false|TUlist0l->Pcoq.Symbol.list0(untype_user_symboll)|TUlist0sep(l,s)->Pcoq.Symbol.list0sep(untype_user_symboll)(Pcoq.Symbol.tokens[Pcoq.TPattern(Pcoq.terminals)])false|TUopto->Pcoq.Symbol.opt(untype_user_symbolo)|TUentrya->Pcoq.Symbol.nterm(Pcoq.genarg_grammar(Genarg.ExtraArga))|TUentryl(a,i)->Pcoq.Symbol.nterml(Pcoq.genarg_grammar(Genarg.ExtraArga))(string_of_inti)letrecuntype_grammar:typers.(r,s)ty_sig->'aEgramml.grammar_prod_itemlist=function|TyNil->[]|TyTerminal(tok,ty)->Egramml.GramTerminaltok::untype_grammarty|TyNonTerminal(tu,ty)->lett=Genarg.rawwit(Egramml.proj_symboltu)inletsymb=untype_user_symboltuinEgramml.GramNonTerminal(Loc.tag(t,symb))::untype_grammartyletdeclare_dynamic_vernac_extend~command?entry~deprcltyf=letcl=untype_classifiertyclinletf=untype_commandtyfinletr=untype_grammartyinletext={commandwithVernacexpr.ext_index=0}invinterp_adddeprextf;Egramml.declare_vernac_command_grammar~allow_override:trueextentryr;declare_vernac_classifier(ext.ext_plugin,ext.ext_entry)[|cl|];extletis_static_linking_done=reffalseletstatic_linking_done()=is_static_linking_done:=trueletstatic_vernac_extend~plugin~command?classifier?entryext=letget_classifier(TyML(_,ty,_,cl))=matchclwith|Somecl->untype_classifiertycl|None->matchclassifierwith|Somecl->fun_->clcommand|None->lete=matchentrywith|None->"COMMAND"|Somee->Pcoq.Entry.nameeinletmsg=Printf.sprintf"\
Vernac entry \"%s\" misses a classifier. \
A classifier is a function that returns an expression \
of type vernac_classification (see Vernacexpr). You can: \n\
- Use '... EXTEND %s CLASSIFIED AS QUERY ...' if the \
new vernacular command does not alter the system state;\n\
- Use '... EXTEND %s CLASSIFIED AS SIDEFF ...' if the \
new vernacular command alters the system state but not the \
parser nor it starts a proof or ends one;\n\
- Use '... EXTEND %s CLASSIFIED BY f ...' to specify \
a global function f. The function f will be called passing\
\"%s\" as the only argument;\n\
- Add a specific classifier in each clause using the syntax:\n\
'[...] => [ f ] -> [...]'.\n\
Specific classifiers have precedence over global \
classifiers. Only one classifier is called."commandeeecommandinCErrors.user_err(Pp.strbrkmsg)inletcl=Array.map_of_listget_classifierextinletext_plugin=Option.default"__"plugininletiteri(TyML(depr,ty,f,_))=letf=untype_commandtyfinletr=untype_grammartyinletext=Vernacexpr.{ext_plugin;ext_entry=command;ext_index=i}inlet()=vinterp_adddeprextfinlet()=Egramml.declare_vernac_command_grammar~allow_override:falseextentryrinlet()=matchpluginwith|None->let()=if!is_static_linking_donethenCErrors.anomalyPp.(str"static_vernac_extend in dynlinked code must pass non-None plugin.")inEgramml.extend_vernac_command_grammar~undoable:falseext|Someplugin->Mltop.add_init_functionplugin(fun()->Egramml.extend_vernac_command_grammar~undoable:trueext)in()inlet()=declare_vernac_classifier(ext_plugin,command)clinlet()=List.iteriiterextin()(** VERNAC ARGUMENT EXTEND registering *)type'aargument_rule=|Arg_aliasof'aPcoq.Entry.t|Arg_rulesof'aPcoq.Production.tlisttype'avernac_argument={arg_printer:Environ.env->Evd.evar_map->'a->Pp.t;arg_parsing:'aargument_rule;}letvernac_argument_extend~plugin~namearg=letwit=Genarg.create_argnameinletentry=matcharg.arg_parsingwith|Arg_aliase->let()=Pcoq.register_grammarwiteine|Arg_rulesrules->lete=Pcoq.create_generic_entry2name(Genarg.rawwitwit)inletplugin_uid=(plugin,"vernacargextend:"^name)inlet()=Egramml.grammar_extend~plugin_uide(Pcoq.Fresh(Gramlib.Gramext.First,[None,None,rules]))ineinletpr=arg.arg_printerinletprx=Genprint.PrinterBasic(funenvsigma->prenvsigmax)inlet()=Genprint.register_vernac_print0witprin(wit,entry)