123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565(************************************************************************)(* * 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) *)(************************************************************************)openCErrorsopenUtilopenGenargopenGramlib(** The parser of Coq *)includeGrammar.GMake(CLexer.Lexer)letkeyword_state=refCLexer.empty_keyword_stateletget_keyword_state()=!keyword_stateletset_keyword_states=keyword_state:=s(** Not marshallable! *)letestate=refEState.emptyletgstate()={GState.estate=!estate;kwstate=!keyword_state;}moduleParsable=structincludeParsableletconsumexlen=consumexlen!keyword_stateendmoduleEntry=structincludeEntryletmakena=letestate',e=makena!estateinestate:=estate';eletparseep=parseep(gstate())letof_parsernap=letestate',e=of_parsernap!estateinestate:=estate';eletparse_token_streamestrm=parse_token_streamestrm(gstate())letprintfmte=printfmte!estateletis_emptye=is_emptye!estateletaccumulate_ine=accumulate_ine!estateendmoduleLookahead=structleterr()=raiseStream.Failuretypet=int->CLexer.keyword_state->(CLexer.keyword_state,Tok.t)LStream.t->intoptionletreccontiguousnmstrm=n==m||let(_,ep)=Loc.unloc(LStream.get_locnstrm)inlet(bp,_)=Loc.unloc(LStream.get_loc(n+1)strm)inInt.equalepbp&&contiguous(succn)mstrmletcheck_no_spacem_kwstatestrm=letn=LStream.countstrminifcontiguousn(n+m-1)strmthenSomemelseNoneletto_entrys(lk:t)=letrunkwstatestrm=matchlk0kwstatestrmwithNone->err()|Some_->()inEntry.(of_parsers{parser_fun=run})let(>>)(lk1:t)lk2nkwstatestrm=matchlk1nkwstatestrmwith|None->None|Somen->lk2nkwstatestrmlet(<+>)(lk1:t)lk2nkwstatestrm=matchlk1nkwstatestrmwith|None->lk2nkwstatestrm|Somen->Somenletlk_emptynkwstatestrm=Somenletlk_kwkwnkwstatestrm=matchLStream.peek_nthkwstatenstrmwith|Tok.KEYWORDkw'|Tok.IDENTkw'->ifString.equalkwkw'thenSome(n+1)elseNone|_->Noneletlk_kwskwsnkwstatestrm=matchLStream.peek_nthkwstatenstrmwith|Tok.KEYWORDkw|Tok.IDENTkw->ifList.mem_fString.equalkwkwsthenSome(n+1)elseNone|_->Noneletlk_identnkwstatestrm=matchLStream.peek_nthkwstatenstrmwith|Tok.IDENT_->Some(n+1)|_->Noneletlk_name=lk_ident<+>lk_kw"_"letlk_ident_exceptidentsnkwstatestrm=matchLStream.peek_nthkwstatenstrmwith|Tok.IDENTidentwhennot(List.mem_fString.equalidentidents)->Some(n+1)|_->Noneletlk_natnkwstatestrm=matchLStream.peek_nthkwstatenstrmwith|Tok.NUMBERpwhenNumTok.Unsigned.is_natp->Some(n+1)|_->Noneletreclk_listlk_elemnkwstatestrm=((lk_elem>>lk_listlk_elem)<+>lk_empty)nkwstatestrmletlk_ident_list=lk_listlk_identletlk_fieldnkwstatestrm=matchLStream.peek_nthkwstatenstrmwith|Tok.FIELD_->Some(n+1)|_->Noneletlk_qualid=lk_ident>>lk_listlk_fieldend(** Grammar extensions *)(** NB: [extend_statement =
gram_position option * single_extend_statement list]
and [single_extend_statement =
string option * gram_assoc option * production_rule list]
and [production_rule = symbol list * action]
In [single_extend_statement], first two parameters are name and
assoc iff a level is created *)(** Type of reinitialization data *)typegram_reinit=Gramlib.Gramext.g_assoc*Gramlib.Gramext.positiontypeextend_rule=|ExtendRule:'aEntry.t*'aextend_statement->extend_rule|ExtendRuleReinit:'aEntry.t*gram_reinit*'aextend_statement->extend_rulemoduleEntryCommand=Dyn.Make()moduleEntryData=structtype_t=Ex:'bEntry.tString.Map.t->('a*'b)tendmoduleEntryDataMap=EntryCommand.Map(EntryData)typeext_kind=|ByGrammarofextend_rule|ByEXTENDofstring*(unit->unit)*(unit->unit)|ByEntry:('a*'b)EntryCommand.tag*string*'bEntry.t->ext_kind(** The list of extensions *)letterminals=CLexer.terminal!keyword_statesletcamlp5_state=ref[]letcamlp5_entries=refEntryDataMap.empty(** Deletion *)letgrammar_deleteer=letdata=matchrwith|Fresh(_,r)->List.map(fun(_,_,r)->r)r|Reuse(_,r)->[r]inList.iter(funlev->List.iter(funpil->estate:=safe_delete_rule!estateepil)(List.revlev))(List.revdata)letno_add_kw={add_kw=fun()_->()}(* TODO use this for ssr instead of messing with set_keyword_state
(needs some API design) *)let_safe_extend_no_kweext=letestate',()=safe_extendno_add_kw!estate()eextinestate:=estate'letadd_kw={add_kw=CLexer.add_keyword_tok}letsafe_extendeext=letestate',kwstate'=safe_extendadd_kw!estate!keyword_stateeextinestate:=estate';keyword_state:=kwstate'letgrammar_delete_reinitereinitd=grammar_deleteed;leta,ext=reinitinletlev=matchdwith|Reuse(Somen,_)->n|_->assertfalseinletext=Fresh(ext,[Somelev,Somea,[]])insafe_extendeext(** Extension *)letgrammar_extendeext=letundo()=grammar_deleteeextinletredo()=safe_extendeextincamlp5_state:=ByEXTEND(Entry.namee,undo,redo)::!camlp5_state;redo()letgrammar_extend_synceext=camlp5_state:=ByGrammar(ExtendRule(e,ext))::!camlp5_state;safe_extendeextletgrammar_extend_sync_reinitereinitext=camlp5_state:=ByGrammar(ExtendRuleReinit(e,reinit,ext))::!camlp5_state;safe_extendeext(** Remove extensions
[n] is the number of extended entries (not the number of Grammar commands!)
to remove. *)letrecremove_grammarsn=ifn>0thenmatch!camlp5_statewith|[]->anomaly~label:"Pcoq.remove_grammars"(Pp.str"too many rules to remove.")|ByGrammar(ExtendRuleReinit(g,reinit,ext))::t->grammar_delete_reinitgreinitext;camlp5_state:=t;remove_grammars(n-1)|ByGrammar(ExtendRule(g,ext))::t->(trygrammar_deletegextwithNot_found->Feedback.msg_infoPp.(str"failed on "++str(Entry.nameg));raiseNot_found);camlp5_state:=t;remove_grammars(n-1)|ByEXTEND(name,undo,redo)::t->undo();camlp5_state:=t;remove_grammarsn;redo();camlp5_state:=ByEXTEND(name,undo,redo)::!camlp5_state|ByEntry(tag,name,e)::t->estate:=Unsafe.clear_entry!estatee;camlp5_state:=t;letEntryData.Exentries=tryEntryDataMap.findtag!camlp5_entrieswithNot_found->EntryData.ExString.Map.emptyinletentries=String.Map.removenameentriesincamlp5_entries:=EntryDataMap.addtag(EntryData.Exentries)!camlp5_entries;remove_grammars(n-1)letmake_ruler=[None,None,r](** An entry that checks we reached the end of the input. *)(* used by the Tactician plugin *)leteoi_entryen=lete=Entry.make((Entry.nameen)^"_eoi")inletsymbs=Rule.next(Rule.nextRule.stop(Symbol.ntermen))(Symbol.tokenTok.PEOI)inletact=fun_xloc->xinletext=Fresh(Gramlib.Gramext.First,make_rule[Production.makesymbsact])insafe_extendeext;e(* Parse a string, does NOT check if the entire string was read
(use eoi_entry) *)letparse_stringf?locx=letstrm=Stream.of_stringxinEntry.parsef(Parsable.make?locstrm)moduleGrammarObj=structtype('r,_,_)obj='rEntry.tletname="grammar"letdefault_=NoneendmoduleGrammar=Register(GrammarObj)letwarn_deprecated_intropattern=CWarnings.create~name:"deprecated-intropattern-entry"~category:Deprecation.Version.v8_11(fun()->Pp.strbrk"Entry name intropattern has been renamed in order \
to be consistent with the documented grammar of tactics. Use \
\"simple_intropattern\" instead.")letcheck_compatibility=function|Genarg.ExtraArgswhenArgT.reprs="intropattern"->warn_deprecated_intropattern()|_->()letregister_grammar=Grammar.register0letgenarg_grammarx=check_compatibilityx;Grammar.objxletcreate_generic_entry2(typea)s(etyp:araw_abstract_argument_type):aEntry.t=lete=Entry.makesinletRawwitt=etypinlet()=Grammar.register0teine(* Initial grammar entries *)modulePrim=struct(* Entries that can be referred via the string -> Entry.t table *)(* Typically for tactic or vernac extensions *)letpreident=Entry.make"preident"letident=Entry.make"ident"letnatural=Entry.make"natural"letinteger=Entry.make"integer"letbignat=Entry.make"bignat"letbigint=Entry.make"bigint"letstring=Entry.make"string"letlstring=Entry.make"lstring"letreference=Entry.make"reference"letfields=Entry.make"fields"letby_notation=Entry.make"by_notation"letsmart_global=Entry.make"smart_global"letstrategy_level=Entry.make"strategy_level"(* parsed like ident but interpreted as a term *)lethyp=Entry.make"hyp"letvar=hypletname=Entry.make"name"letidentref=Entry.make"identref"letuniv_decl=Entry.make"univ_decl"letident_decl=Entry.make"ident_decl"letpattern_ident=Entry.make"pattern_ident"(* A synonym of ident - maybe ident will be located one day *)letbase_ident=Entry.make"base_ident"letqualid=Entry.make"qualid"letfullyqualid=Entry.make"fullyqualid"letdirpath=Entry.make"dirpath"letne_string=Entry.make"ne_string"letne_lstring=Entry.make"ne_lstring"letbar_cbrace=Entry.make"'|}'"endmoduleConstr=struct(* Entries that can be referred via the string -> Entry.t table *)letconstr=Entry.make"constr"letterm=Entry.make"term"letconstr_eoi=eoi_entryconstrletlconstr=Entry.make"lconstr"letbinder_constr=Entry.make"binder_constr"letident=Entry.make"ident"letglobal=Entry.make"global"letuniverse_name=Entry.make"universe_name"letsort=Entry.make"sort"letsort_family=Entry.make"sort_family"letpattern=Entry.make"pattern"letconstr_pattern=Entry.make"constr_pattern"letcpattern=Entry.make"cpattern"letclosed_binder=Entry.make"closed_binder"letbinder=Entry.make"binder"letbinders=Entry.make"binders"letopen_binders=Entry.make"open_binders"letone_open_binder=Entry.make"one_open_binder"letone_closed_binder=Entry.make"one_closed_binder"letbinders_fixannot=Entry.make"binders_fixannot"lettypeclass_constraint=Entry.make"typeclass_constraint"letrecord_declaration=Entry.make"record_declaration"letarg=Entry.make"arg"lettype_cstr=Entry.make"type_cstr"endmoduleModule=structletmodule_expr=Entry.make"module_expr"letmodule_type=Entry.make"module_type"endletepsilon_value(typestra)f(e:(s,tr,a)Symbol.t)=letr=Production.make(Rule.nextRule.stope)(funx_->fx)inletentry=Entry.make"epsilon"inletext=Fresh(Gramlib.Gramext.First,[None,None,[r]])insafe_extendentryext;trySome(parse_stringentry"")withewhenCErrors.noncriticale->None(** Synchronized grammar extensions *)moduleGramState=Store.Make()type'agrammar_extension={gext_fun:'a->GramState.t->extend_rulelist*GramState.t;gext_eq:'a->'a->bool;}moduleGrammarCommand=Dyn.Make()moduleGrammarInterp=structtype'at='agrammar_extensionendmoduleGrammarInterpMap=GrammarCommand.Map(GrammarInterp)letgrammar_interp=refGrammarInterpMap.emptytype('a,'b)entry_extension={eext_fun:'a->GramState.t->stringlist*GramState.t;eext_eq:'a->'a->bool;}moduleEntryInterp=structtype_t=Ex:('a,'b)entry_extension->('a*'b)tendmoduleEntryInterpMap=EntryCommand.Map(EntryInterp)letentry_interp=refEntryInterpMap.emptytypegrammar_entry=|GramExtofint*GrammarCommand.t|EntryExt:int*('a*'b)EntryCommand.tag*'a->grammar_entrylet(grammar_stack:(grammar_entry*GramState.t)listref)=ref[]type'agrammar_command='aGrammarCommand.tagtype('a,'b)entry_command=('a*'b)EntryCommand.tagletcreate_grammar_commandnameinterp:_grammar_command=letobj=GrammarCommand.createnameinlet()=grammar_interp:=GrammarInterpMap.addobjinterp!grammar_interpinobjletcreate_entry_commandname(interp:('a,'b)entry_extension):('a,'b)entry_command=letobj=EntryCommand.createnameinlet()=entry_interp:=EntryInterpMap.addobj(EntryInterp.Exinterp)!entry_interpinobjletiter_extend_sync=function|ExtendRule(e,ext)->grammar_extend_synceext|ExtendRuleReinit(e,reinit,ext)->grammar_extend_sync_reinitereinitextletextend_grammar_commandtagg=letmodify=GrammarInterpMap.findtag!grammar_interpinletgrammar_state=match!grammar_stackwith|[]->GramState.empty|(_,st)::_->stinlet(rules,st)=modify.gext_funggrammar_stateinlet()=List.iteriter_extend_syncrulesinletnb=List.lengthrulesingrammar_stack:=(GramExt(nb,GrammarCommand.Dyn(tag,g)),st)::!grammar_stackletextend_entry_command(typea)(typeb)(tag:(a,b)entry_command)(g:a):bEntry.tlist=letEntryInterp.Exmodify=EntryInterpMap.findtag!entry_interpinletgrammar_state=match!grammar_stackwith|[]->GramState.empty|(_,st)::_->stinlet(names,st)=modify.eext_funggrammar_stateinletentries=List.map(funname->Entry.makename)namesinletiternamee=camlp5_state:=ByEntry(tag,name,e)::!camlp5_state;letEntryData.Exold=tryEntryDataMap.findtag!camlp5_entrieswithNot_found->EntryData.ExString.Map.emptyinlet()=assert(not@@String.Map.memnameold)inletentries=String.Map.addnameeoldincamlp5_entries:=EntryDataMap.addtag(EntryData.Exentries)!camlp5_entriesinlet()=List.iter2iternamesentriesinletnb=List.lengthentriesinlet()=grammar_stack:=(EntryExt(nb,tag,g),st)::!grammar_stackinentriesletfind_custom_entrytagname=letEntryData.Exmap=EntryDataMap.findtag!camlp5_entriesinString.Map.findnamemapletextend_dyn_grammar(e,_)=matchewith|GramExt(_,(GrammarCommand.Dyn(tag,g)))->extend_grammar_commandtagg|EntryExt(_,tag,g)->ignore(extend_entry_commandtagg)(** Registering extra grammar *)letgrammar_names:Entry.any_tlistString.Map.tref=refString.Map.emptyletregister_grammars_by_namenamegrams=grammar_names:=String.Map.addnamegrams!grammar_namesletfind_grammars_by_namename=tryString.Map.findname!grammar_nameswithNot_found->letfold(EntryDataMap.Any(tag,EntryData.Exmap))accu=tryEntry.Any(String.Map.findnamemap)::accuwithNot_found->accuinEntryDataMap.foldfold!camlp5_entries[](** Summary functions: the state of the lexer is included in that of the parser.
Because the grammar affects the set of keywords when adding or removing
grammar rules. *)typefrozen_t=(grammar_entry*GramState.t)list*CLexer.keyword_stateletfreeze():frozen_t=(!grammar_stack,!keyword_state)leteq_grams(g1,_)(g2,_)=matchg1,g2with|GramExt(_,GrammarCommand.Dyn(t1,v1)),GramExt(_,GrammarCommand.Dyn(t2,v2))->beginmatchGrammarCommand.eqt1t2with|None->false|SomeRefl->letdata=GrammarInterpMap.findt1!grammar_interpindata.gext_eqv1v2end|EntryExt(_,t1,v1),EntryExt(_,t2,v2)->beginmatchEntryCommand.eqt1t2with|None->false|SomeRefl->letEntryInterp.Exdata=EntryInterpMap.findt1!entry_interpindata.eext_eqv1v2end|(GramExt_,EntryExt_)|(EntryExt_,GramExt_)->false(* We compare the current state of the grammar and the state to unfreeze,
by computing the longest common suffixes *)letfactorize_gramsl1l2=ifl1==l2then([],[],l1)elseList.share_tailseq_gramsl1l2letrecnumber_of_entriesaccu=function|[]->accu|((GramExt(p,_)|EntryExt(p,_,_)),_)::rem->number_of_entries(p+accu)remletunfreeze(grams,lex)=let(undo,redo,common)=factorize_grams!grammar_stackgramsinletn=number_of_entries0undoinremove_grammarsn;grammar_stack:=common;keyword_state:=lex;List.iterextend_dyn_grammar(List.revredo)(** No need to provide an init function : the grammar state is
statically available, and already empty initially, while
the lexer state should not be reset, since it contains
keywords declared in g_*.mlg *)letparser_summary_tag=Summary.declare_summary_tag"GRAMMAR_LEXER"{stage=Summary.Stage.Synterp;Summary.freeze_function=freeze;Summary.unfreeze_function=unfreeze;Summary.init_function=Summary.nop}letwith_grammar_rule_protectionfx=letfs=freeze()intryleta=fxinunfreezefs;awithreraise->letreraise=Exninfo.capturereraiseinlet()=unfreezefsinExninfo.iraisereraise(** Registering grammar of generic arguments *)let()=letopenStdarginGrammar.register0wit_nat(Prim.natural);Grammar.register0wit_int(Prim.integer);Grammar.register0wit_string(Prim.string);Grammar.register0wit_pre_ident(Prim.preident);Grammar.register0wit_identref(Prim.identref);Grammar.register0wit_ident(Prim.ident);Grammar.register0wit_hyp(Prim.hyp);Grammar.register0wit_ref(Prim.reference);Grammar.register0wit_smart_global(Prim.smart_global);Grammar.register0wit_sort_family(Constr.sort_family);Grammar.register0wit_constr(Constr.constr);()