123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405(************************************************************************)(* * 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) *)(************************************************************************)openUtilopenPpopenCErrorstypevernac_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 *)moduleInProg=structtype_t=|Ignore:unitt|Use:Declare.OblState.ttletcast(typea)(x:Declare.OblState.t)(ty:at):a=matchtywith|Ignore->()|Use->xendmoduleOutProg=structtype_t=|No:unitt|Yes:Declare.OblState.tt|Push|Popletcast(typea)(x:a)(ty:at)(orig:Declare.OblState.tNeList.t):Declare.OblState.tNeList.t=matchtywith|No->orig|Yes->NeList.map_head(fun_->x)orig|Push->NeList.pushDeclare.OblState.empty(Someorig)|Pop->(matchNeList.tailorigwithSometl->tl|None->assertfalse)endmoduleInProof=structtype_t=|Ignore:unitt|Reject:unitt|Use:Declare.Proof.tt|UseOpt:Declare.Proof.toptiontletcast(typea)(x:Declare.Proof.toption)(ty:at):a=matchx,tywith|_,Ignore->()|None,Reject->()|Some_,Reject->CErrors.user_err(Pp.str"Command not supported (Open proofs remain).")|Somex,Use->x|None,Use->CErrors.user_err(Pp.str"Command not supported (No proof-editing in progress).")|_,UseOpt->xendmoduleOutProof=structtype_t=|No:unitt|Close:unitt|Update:Declare.Proof.tt|New:Declare.Proof.ttendtype('inprog,'outprog,'inproof,'outproof)vernac_type={inprog:'inprogInProg.t;outprog:'outprogInProg.t;inproof:'inproofInProof.t;outproof:'outproofOutProof.t;}typetyped_vernac=TypedVernac:{inprog:'inprogInProg.t;outprog:'outprogOutProg.t;inproof:'inproofInProof.t;outproof:'outproofOutProof.t;run:pm:'inprog->proof:'inproof->'outprog*'outproof;}->typed_vernacletvtdefaultf=TypedVernac{inprog=Ignore;outprog=No;inproof=Ignore;outproof=No;run=(fun~pm:()~proof:()->let()=f()in(),())}letvtnoprooff=TypedVernac{inprog=Ignore;outprog=No;inproof=Ignore;outproof=No;run=(fun~pm:()~proof:()->let()=f()in(),())}letvtcloseprooff=TypedVernac{inprog=Use;outprog=Yes;inproof=Use;outproof=Close;run=(fun~pm~proof->letpm=f~lemma:proof~pminpm,())}letvtopenprooff=TypedVernac{inprog=Ignore;outprog=No;inproof=Ignore;outproof=New;run=(fun~pm:()~proof:()->letproof=f()in(),proof)}letvtmodifyprooff=TypedVernac{inprog=Ignore;outprog=No;inproof=Use;outproof=Update;run=(fun~pm:()~proof->letproof=f~pstate:proofin(),proof)}letvtreadproofoptf=TypedVernac{inprog=Ignore;outprog=No;inproof=UseOpt;outproof=No;run=(fun~pm:()~proof->let()=f~pstate:proofin(),())}letvtreadprooff=TypedVernac{inprog=Ignore;outprog=No;inproof=Use;outproof=No;run=(fun~pm:()~proof->let()=f~pstate:proofin(),())}letvtreadprogramf=TypedVernac{inprog=Use;outprog=No;inproof=Ignore;outproof=No;run=(fun~pm~proof:()->let()=f~pmin(),())}letvtmodifyprogramf=TypedVernac{inprog=Use;outprog=Yes;inproof=Ignore;outproof=No;run=(fun~pm~proof:()->letpm=f~pminpm,())}letvtdeclareprogramf=TypedVernac{inprog=Use;outprog=No;inproof=Ignore;outproof=New;run=(fun~pm~proof:()->letproof=f~pmin(),proof)}letvtopenproofprogramf=TypedVernac{inprog=Use;outprog=Yes;inproof=Ignore;outproof=New;run=(fun~pm~proof:()->letpm,proof=f~pminpm,proof)}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=tryHashtbl.addvernac_tabs(depr,f)withFailure_->user_err(str"Cannot add the vernac command "++str(fsts)++str" twice.")letvinterp_maps=tryHashtbl.findvernac_tabswithFailure_|Not_found->user_err(str"Cannot find vernac command "++str(fsts)++str".")letwarn_deprecated_command=letopenCWarningsincreate~name:"deprecated-command"~category:"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;inlethunk=callbackconverted_argsinhunk?loc~atts()(** VERNAC EXTEND registering *)typeclassifier=Genarg.raw_generic_argumentlist->vernac_classification(** Classifiers *)letclassifiers:classifierarrayString.Map.tref=refString.Map.emptyletget_vernac_classifier(name,i)args=(String.Map.findname!classifiers).(i)argsletdeclare_vernac_classifiernamef=classifiers:=String.Map.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(CLexer.terminals)])false|TUlist0l->Pcoq.Symbol.list0(untype_user_symboll)|TUlist0sep(l,s)->Pcoq.Symbol.list0sep(untype_user_symboll)(Pcoq.Symbol.tokens[Pcoq.TPattern(CLexer.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_grammartyletvernac_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_classifierextinletiteri(TyML(depr,ty,f,_))=letf=untype_commandtyfinletr=untype_grammartyinlet()=vinterp_adddepr(command,i)finlet()=(* allow_override is a hack for Elpi Command, since it takes
effect at Import time it gets called multiple times.
Eventually we will need a better API to support this and also
to support backtracking over it. *)Egramml.declare_vernac_command_grammar~allow_override:(Option.is_emptyplugin)(command,i)entryrinlet()=matchpluginwith|None->Egramml.extend_vernac_command_grammar~undoable:false(command,i)|Someplugin->Mltop.add_init_functionplugin(fun()->Egramml.extend_vernac_command_grammar~undoable:true(command,i))in()inlet()=declare_vernac_classifiercommandclinlet()=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)