123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584(************************************************************************)(* * 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) *)(************************************************************************)openUtilopenNames(* Utilities *)moduleSubscript=structtypet={ss_zero:int;(** Number of leading zeros of the subscript *)ss_subs:int;(** Digital value of the subscript, zero meaning empty *)}letrecoverflown=Int.equal(nmod10)9&&(Int.equal(n/10)0||overflow(n/10))letzero={ss_subs=0;ss_zero=0}letsuccs=ifInt.equals.ss_subs0thenifInt.equals.ss_zero0then(* [] -> [0] *){ss_zero=1;ss_subs=0}else(* [0...00] -> [0..01] *){ss_zero=s.ss_zero-1;ss_subs=1}elseifoverflows.ss_substhenifInt.equals.ss_zero0then(* [9...9] -> [10...0] *){ss_zero=0;ss_subs=1+s.ss_subs}else(* [0...009...9] -> [0...010...0] *){ss_zero=s.ss_zero-1;ss_subs=1+s.ss_subs}else(* [0...0n] -> [0...0{n+1}] *){ss_zero=s.ss_zero;ss_subs=s.ss_subs+1}letequals1s2=Int.equals1.ss_zeros2.ss_zero&&Int.equals1.ss_subss2.ss_subsletcompares1s2=(* Lexicographic order is reversed in order to ensure that [succ] is strictly
increasing. *)letc=Int.compares1.ss_subss2.ss_subsinifInt.equalc0thenInt.compares1.ss_zeros2.ss_zeroelsecendletcode_of_0=Char.code'0'letcode_of_9=Char.code'9'letcut_identskip_quotes=lets=Id.to_stringsinletslen=String.lengthsin(* [n'] is the position of the first non nullary digit *)letrecnumpartnn'=ifInt.equaln0then(* ident made of _ and digits only [and ' if skip_quote]: don't cut it *)slenelseletc=Char.code(String.gets(n-1))inifInt.equalccode_of_0&¬(Int.equalnslen)thennumpart(n-1)n'elseifcode_of_0<=c&&c<=code_of_9thennumpart(n-1)(n-1)elseifskip_quote&&(Int.equalc(Char.code'\'')||Int.equalc(Char.code'_'))thennumpart(n-1)(n-1)elsen'innumpartslenslenletrepr_idents=letnumstart=cut_identfalsesinlets=Id.to_stringsinletslen=String.lengthsinifInt.equalnumstartslenthen(s,None)else(String.subs0numstart,Some(int_of_string(String.subsnumstart(slen-numstart))))letmake_identsa=function|Somen->letc=Char.code(String.getsa(String.lengthsa-1))inlets=ifc<code_of_0||c>code_of_9thensa^(string_of_intn)elsesa^"_"^(string_of_intn)inId.of_strings|None->Id.of_stringsaletroot_of_idid=letsuffixstart=cut_identtrueidinId.of_string(String.sub(Id.to_stringid)0suffixstart)(* Return the same identifier as the original one but whose {i subscript} is incremented.
If the original identifier does not have a suffix, [0] is appended to it.
Example mappings:
[bar] ↦ [bar0]
[bar0] ↦ [bar1]
[bar00] ↦ [bar01]
[bar1] ↦ [bar2]
[bar01] ↦ [bar02]
[bar9] ↦ [bar10]
[bar09] ↦ [bar10]
[bar99] ↦ [bar100]
*)letincrement_subscriptid=letid=Id.to_stringidinletlen=String.lengthidinletrecaddcarrypos=letc=id.[carrypos]inifis_digitcthenifInt.equal(Char.codec)(Char.code'9')thenbeginassert(carrypos>0);add(carrypos-1)endelsebeginletnewid=Bytes.of_stringidinBytes.fillnewid(carrypos+1)(len-1-carrypos)'0';Bytes.setnewidcarrypos(Char.chr(Char.codec+1));newidendelsebeginletnewid=Bytes.of_string(id^"0")inifcarrypos<len-1thenbeginBytes.fillnewid(carrypos+1)(len-1-carrypos)'0';Bytes.setnewid(carrypos+1)'1'end;newidendinId.of_bytes(add(len-1))lethas_subscriptid=letid=Id.to_stringidinis_digit(id.[String.lengthid-1])letget_subscriptid=letid0=idinletid=Id.to_stringidinletlen=String.lengthidinletrecget_sufaccupos=ifpos<0then(pos,accu)elseletc=id.[pos]inifis_digitcthenget_suf(Char.codec-Char.code'0'::accu)(pos-1)else(pos,accu)inlet(pos,suf)=get_suf[](len-1)inifInt.equalpos(len-1)then(id0,Subscript.zero)elseletid=String.subid0(pos+1)inletreccompute_zerosaccu=function|[]->(accu,[])|0::l->compute_zeros(succaccu)l|_::_asl->(accu,l)inlet(ss_zero,suf)=compute_zeros0sufinletreccompute_sufaccu=function|[]->accu|n::l->compute_suf(10*accu+n)linletss_subs=compute_suf0sufin(Id.of_stringid,{Subscript.ss_subs;ss_zero;})letadd_subscriptidss=ifSubscript.equalSubscript.zerossthenidelseifInt.equalss.Subscript.ss_subs0thenletid=Id.to_stringidinletpad=String.makess.Subscript.ss_zero'0'inId.of_string(Printf.sprintf"%s%s"idpad)elseletid=Id.to_stringidinletpad=String.makess.Subscript.ss_zero'0'inletsuf=ss.Subscript.ss_subsinId.of_string(Printf.sprintf"%s%s%i"idpadsuf)letforget_subscriptid=letnumstart=cut_identfalseidinletnewid=Bytes.make(numstart+1)'0'inString.blit(Id.to_stringid)0newid0numstart;(Id.of_bytesnewid)letadd_suffixids=Id.of_string(Id.to_stringid^s)letadd_prefixsid=Id.of_string(s^Id.to_stringid)letatompart_of_idid=fst(repr_identid)(** Segment trees: efficient lookup of the next free integer *)moduleSegTree:sigtypetvalempty:tvalmem:int->t->boolvaladd:int->t->tvalremove:int->t->tvalnext:int->t->int(** [next n s] returns the smallest integer [k] not in [s] s.t. [n <= k] *)valfresh:int->t->int*t(** Efficient composition of [next] and [add] *)end=structmoduleSegment=structtypet=int*int(* segment [p, q[, in particular p < q *)letcompare(p,_)(q,_)=Int.comparepqendmoduleSegSet=Set.Make(Segment)typet=SegSet.t(* Invariants: forall [p1, q1[, [p2, q2[ in such a set, either:
- p1 = p2 and q1 = q2
- p1 < q1 < p2 < q2
- p2 < q2 < p1 < q1 *)letempty=SegSet.emptyletmemns=letfind(_p,q)=n<qinmatchSegSet.find_first_optfindswith|None->false|Some(p,_q)->p<=nletaddns=letfind_min(_p,q)=n<qinletfind_max(_p,q)=q<=ninmatchSegSet.find_first_optfind_minswith|None->(* n larger than all elements *)beginmatchSegSet.max_elt_optswith|None->SegSet.add(n,n+1)s|Some(pl,ql)->ifInt.equalnqlthenSegSet.add(pl,n+1)(SegSet.remove(pl,ql)s)elseSegSet.add(n,n+1)send|Some(pr,qr)->ifpr<=nthens(* already present *)elsematchSegSet.find_last_optfind_maxswith|None->(* n smaller than all elements *)ifInt.equalpr(n+1)thenSegSet.add(n,qr)(SegSet.remove(pr,qr)s)elseSegSet.add(n,n+1)s|Some(pl,ql)->(* pl < ql <= n < pr < qr *)ifInt.equalqln&&Int.equalpr(n+1)thenSegSet.add(pl,qr)(SegSet.remove(pl,ql)(SegSet.remove(pr,qr)s))elseifInt.equalqlnthenSegSet.add(pl,n+1)(SegSet.remove(pl,ql)s)elseifInt.equalpr(n+1)thenSegSet.add(n,qr)(SegSet.remove(pr,qr)s)elseSegSet.add(n,n+1)sletremovens=letfind_min(_p,q)=n<qinmatchSegSet.find_first_optfind_minswith|None->s|Some(pr,qr)->ifpr<=nthenlets=SegSet.remove(pr,qr)sinifInt.equal(pr+1)qrthenselseifInt.equalprnthenSegSet.add(n+1,qr)selseifInt.equal(n+1)qrthenSegSet.add(pr,n)selseSegSet.add(pr,n)(SegSet.add(n+1,qr)s)elsesletnextns=letfind(_p,q)=n<qinmatchSegSet.find_first_optfindswith|None->n|Some(p,q)->ifp<=nthenqelsenletfreshns=letfind_min(_p,q)=n<qinletfind_max(_p,q)=q<=ninmatchSegSet.find_first_optfind_minswith|None->lets=matchSegSet.max_elt_optswith|None->SegSet.add(n,n+1)s|Some(pl,ql)->ifInt.equalnqlthenSegSet.add(pl,n+1)(SegSet.remove(pl,ql)s)elseSegSet.add(n,n+1)sinn,s|Some(pr,qr)->ifpr<=nthen(* equivalent to adding qr *)letnext=SegSet.find_first_opt(fun(p,_q)->qr<p)sinlets=matchnextwith|None->SegSet.add(pr,qr+1)(SegSet.remove(pr,qr)s)|Some(pk,qk)->ifInt.equal(qr+1)pkthenSegSet.add(pr,qk)(SegSet.remove(pk,qk)(SegSet.remove(pr,qr)s))elseSegSet.add(pr,qr+1)(SegSet.remove(pr,qr)s)inqr,selselets=matchSegSet.find_last_optfind_maxswith|None->ifInt.equalpr(n+1)thenSegSet.add(n,qr)(SegSet.remove(pr,qr)s)elseSegSet.add(n,n+1)s|Some(pl,ql)->ifInt.equalqln&&Int.equalpr(n+1)thenSegSet.add(pl,qr)(SegSet.remove(pl,ql)(SegSet.remove(pr,qr)s))elseifInt.equalqlnthenSegSet.add(pl,n+1)(SegSet.remove(pl,ql)s)elseifInt.equalpr(n+1)thenSegSet.add(n,qr)(SegSet.remove(pr,qr)s)elseSegSet.add(n,n+1)sinn,sendmoduleSubSet=structtypet={num:SegTree.t;pre:SegTree.tlist;(* lists are OK because we are already logarithmic *)}(* We represent sets of subscripts by case-splitting on ss_zero.
If it is zero, we store the number in the [num] set. Otherwise, we know
the set of possible values is finite. At position k, [pre] contains a set
of maximum size 10^k representing k-digit numbers with at least one leading
zero. *)letempty={num=SegTree.empty;pre=[];}letrecpow10kaccu=ifk<=0thenaccuelsepow10(k-1)(10*accu)letreclog10naccu=ifn<=0thenaccuelselog10(n/10)(accu+1)letmax_subscriptss=letexp=log10ss.Subscript.ss_subs0+ss.Subscript.ss_zero-1inpow10exp1letaddsss=letopenSubscriptinifInt.equalss.ss_zero0then{swithnum=SegTree.addss.ss_subss.num}elseletpre=letlen=List.lengths.preiniflen<ss.ss_zerothens.pre@List.make(ss.ss_zero-len)SegTree.emptyelses.preinletset=matchList.nth_optpre(ss.ss_zero-1)with|None->assertfalse|Somem->SegTree.addss.ss_subsmin{swithpre=List.assignpre(ss.ss_zero-1)set}letremovesss=letopenSubscriptinifInt.equalss.ss_zero0then{swithnum=SegTree.removess.ss_subss.num}elsematchList.nth_opts.pre(ss.ss_zero-1)with|None->s|Somem->letm=SegTree.removess.ss_subsmin{swithpre=List.assigns.pre(ss.ss_zero-1)m}letmemsss=letopenSubscriptinifInt.equalss.ss_zero0thenSegTree.memss.ss_subss.numelsematchList.nth_opts.pre(ss.ss_zero-1)with|None->false|Somem->SegTree.memss.ss_subsmletss_O={Subscript.ss_zero=1;ss_subs=0}(* [0] *)letnextsss=letopenSubscriptinifss.ss_zero>0thenmatchList.nth_opts.pre(ss.ss_zero-1)with|None->ss|Somem->letnext=SegTree.nextss.ss_subsminletmax=max_subscriptssinifmax<=nextthen(* overflow *){ss_zero=0;ss_subs=SegTree.nextmaxs.num}else{ss_zero=ss.ss_zero;ss_subs=next}elseifInt.equalss.ss_subs0then(* Handle specially [] *)ifnot@@SegTree.mem0s.numthenSubscript.zeroelsematchs.prewith|[]->ss_O|m::_->ifSegTree.mem0mthen{ss_zero=0;ss_subs=SegTree.next1s.num}elsess_Oelse{ss_zero=0;ss_subs=SegTree.nextss.ss_subss.num}letfreshsss=letopenSubscriptinifss.ss_zero>0thenmatchList.nth_opts.pre(ss.ss_zero-1)with|None->ss,addsss|Somem->letsubs,m=SegTree.freshss.ss_subsminletmax=max_subscriptssinifmax<=substhenletsubs,num=SegTree.freshmaxs.numin{ss_zero=0;ss_subs=subs},{swithnum}elselets={swithpre=List.assigns.pre(ss.ss_zero-1)m}in{ss_zero=ss.ss_zero;ss_subs=subs},selseifInt.equalss.ss_subs0thenifnot@@SegTree.mem0s.numthenSubscript.zero,{num=SegTree.add0s.num;pre=s.pre}elsematchs.prewith|[]->ss_O,{num=s.num;pre=[SegTree.add0SegTree.empty]}|m::rem->ifSegTree.mem0mthenletsubs,num=SegTree.fresh1s.numin{ss_zero=0;ss_subs=subs},{num;pre=s.pre}elsess_O,{num=s.num;pre=SegTree.add0SegTree.empty::rem}elseletsubs,num=SegTree.freshss.ss_subss.numin{ss_zero=0;ss_subs=subs},{swithnum}endmoduleFresh=structtypet=SubSet.tId.Map.tletempty=Id.Map.emptyletaddidm=let(id,s)=get_subscriptidinletold=tryId.Map.findidmwithNot_found->SubSet.emptyinId.Map.addid(SubSet.addsold)mletremoveidm=let(id,s)=get_subscriptidinmatchId.Map.findidmwith|old->Id.Map.addid(SubSet.removesold)m|exceptionNot_found->mletmemidm=let(id,s)=get_subscriptidintrySubSet.mems(Id.Map.findidm)withNot_found->falseletnextid0m=let(id,s)=get_subscriptid0inmatchId.Map.find_optidmwith|None->id0|Someold->letss=SubSet.nextsoldinadd_subscriptidssletfreshid0m=let(id,s)=get_subscriptid0inmatchId.Map.find_optidmwith|None->id0,Id.Map.addid(SubSet.addsSubSet.empty)m|Someold->letss,n=SubSet.freshsoldinadd_subscriptidss,Id.Map.addidnmletof_listl=List.fold_left(funaccuid->addidaccu)emptylletof_sets=Id.Set.foldaddsemptyletof_named_context_vals=of_set@@Environ.ids_of_named_context_valsend(* Names *)moduletypeExtName=sigincludemoduletypeofstructincludeNames.NameendexceptionIsAnonymousvalfold_left:('a->Id.t->'a)->'a->t->'avalfold_right:(Id.t->'a->'a)->t->'a->'avaliter:(Id.t->unit)->t->unitvalmap:(Id.t->Id.t)->t->tvalfold_left_map:('a->Id.t->'a*Id.t)->'a->t->'a*tvalfold_right_map:(Id.t->'a->Id.t*'a)->Name.t->'a->Name.t*'avalget_id:t->Id.tvalpick:t->t->tvalpick_annot:(t,'r)Context.pbinder_annot->(t,'r)Context.pbinder_annot->(t,'r)Context.pbinder_annotvalcons:t->Id.tlist->Id.tlistvalto_option:Name.t->Id.toptionendmoduleName:ExtName=structincludeNames.NameexceptionIsAnonymousletfold_leftfa=function|Nameid->faid|Anonymous->aletfold_rightfnaa=matchnawith|Nameid->fida|Anonymous->aletiterfna=fold_right(funx()->fx)na()letmapf=function|Nameid->Name(fid)|Anonymous->Anonymousletfold_left_mapfa=function|Nameid->let(a,id)=faidin(a,Nameid)|Anonymous->a,Anonymousletfold_right_mapfnaa=matchnawith|Nameid->let(id,a)=fidain(Nameid,a)|Anonymous->Anonymous,aletget_id=function|Nameid->id|Anonymous->raiseIsAnonymousletpickna1na2=matchna1with|Name_->na1|Anonymous->na2letpick_annotna1na2=letopenContextinmatchna1.binder_namewith|Name_->na1|Anonymous->na2letconsnal=matchnawith|Anonymous->l|Nameid->id::lletto_option=function|Anonymous->None|Nameid->Someidend(* Metavariables *)letpr_meta=Pp.intletstring_of_meta=string_of_int