123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367(**************************************************************************)(* *)(* OCaml *)(* *)(* Xavier Leroy, projet Cristal, INRIA Rocquencourt *)(* *)(* Copyright 1996 Institut National de Recherche en Informatique et *)(* en Automatique. *)(* *)(* All rights reserved. This file is distributed under the terms of *)(* the GNU Lesser General Public License version 2.1, with the *)(* special exception on linking described in the file LICENSE. *)(* *)(**************************************************************************)openLocal_storeletlowest_scope=0lethighest_scope=100000000typet=|Localof{name:string;stamp:int}|Scopedof{name:string;stamp:int;scope:int}|Globalofstring|Predefof{name:string;stamp:int}(* the stamp is here only for fast comparison, but the name of
predefined identifiers is always unique. *)(* A stamp of 0 denotes a persistent identifier *)letcurrentstamp=s_ref0letpredefstamp=s_ref0letcreate_scoped~scopes=incrcurrentstamp;Scoped{name=s;stamp=!currentstamp;scope}letcreate_locals=incrcurrentstamp;Local{name=s;stamp=!currentstamp}letcreate_predefs=incrpredefstamp;Predef{name=s;stamp=!predefstamp}letcreate_persistents=Globalsletname=function|Local{name;_}|Scoped{name;_}|Globalname|Predef{name;_}->nameletrename=function|Local{name;stamp=_}|Scoped{name;stamp=_;scope=_}->incrcurrentstamp;Local{name;stamp=!currentstamp}|id->Misc.fatal_errorf"Ident.rename %s"(nameid)letunique_name=function|Local{name;stamp}|Scoped{name;stamp}->name^"_"^Int.to_stringstamp|Globalname->(* we're adding a fake stamp, because someone could have named his unit
[Foo_123] and since we're using unique_name to produce symbol names,
we might clash with an ident [Local { "Foo"; 123 }]. *)name^"_0"|Predef{name;_}->(* we know that none of the predef names (currently) finishes in
"_<some number>", and that their name is unique. *)nameletunique_toplevel_name=function|Local{name;stamp}|Scoped{name;stamp}->name^"/"^Int.to_stringstamp|Globalname|Predef{name;_}->nameletpersistent=function|Global_->true|_->falseletequali1i2=matchi1,i2with|Local{name=name1;_},Local{name=name2;_}|Scoped{name=name1;_},Scoped{name=name2;_}|Globalname1,Globalname2->name1=name2|Predef{stamp=s1;_},Predef{stamp=s2}->(* if they don't have the same stamp, they don't have the same name *)s1=s2|_->falseletsamei1i2=matchi1,i2with|Local{stamp=s1;_},Local{stamp=s2;_}|Scoped{stamp=s1;_},Scoped{stamp=s2;_}|Predef{stamp=s1;_},Predef{stamp=s2}->s1=s2|Globalname1,Globalname2->name1=name2|_->falseletstamp=function|Local{stamp;_}|Scoped{stamp;_}->stamp|_->0letscope=function|Scoped{scope;_}->scope|Local_->highest_scope|Global_|Predef_->lowest_scopeletreinit_level=ref(-1)letreinit()=if!reinit_level<0thenreinit_level:=!currentstampelsecurrentstamp:=!reinit_levelletglobal=function|Local_|Scoped_->false|Global_|Predef_->trueletis_predef=function|Predef_->true|_->falseletprint~with_scopeppf=letopenFormatinfunction|Globalname->fprintfppf"%s!"name|Predef{name;stamp=n}->fprintfppf"%s/%i!"namen|Local{name;stamp=n}->fprintfppf"%s/%i"namen|Scoped{name;stamp=n;scope}->fprintfppf"%s/%i%s"namen(ifwith_scopethensprintf"[%i]"scopeelse"")letprint_with_scopeppfid=print~with_scope:trueppfidletprintppfid=print~with_scope:falseppfidtype'atbl=Empty|Nodeof'atbl*'adata*'atbl*intand'adata={ident:t;data:'a;previous:'adataoption}letempty=Empty(* Inline expansion of height for better speed
* let height = function
* Empty -> 0
* | Node(_,_,_,h) -> h
*)letmknodeldr=lethl=matchlwithEmpty->0|Node(_,_,_,h)->handhr=matchrwithEmpty->0|Node(_,_,_,h)->hinNode(l,d,r,(ifhl>=hrthenhl+1elsehr+1))letbalanceldr=lethl=matchlwithEmpty->0|Node(_,_,_,h)->handhr=matchrwithEmpty->0|Node(_,_,_,h)->hinifhl>hr+1thenmatchlwith|Node(ll,ld,lr,_)when(matchllwithEmpty->0|Node(_,_,_,h)->h)>=(matchlrwithEmpty->0|Node(_,_,_,h)->h)->mknodellld(mknodelrdr)|Node(ll,ld,Node(lrl,lrd,lrr,_),_)->mknode(mknodellldlrl)lrd(mknodelrrdr)|_->assertfalseelseifhr>hl+1thenmatchrwith|Node(rl,rd,rr,_)when(matchrrwithEmpty->0|Node(_,_,_,h)->h)>=(matchrlwithEmpty->0|Node(_,_,_,h)->h)->mknode(mknodeldrl)rdrr|Node(Node(rll,rld,rlr,_),rd,rr,_)->mknode(mknodeldrll)rld(mknoderlrrdrr)|_->assertfalseelsemknodeldrletrecaddiddata=functionEmpty->Node(Empty,{ident=id;data=data;previous=None},Empty,1)|Node(l,k,r,h)->letc=String.compare(nameid)(namek.ident)inifc=0thenNode(l,{ident=id;data=data;previous=Somek},r,h)elseifc<0thenbalance(addiddatal)krelsebalancelk(addiddatar)letrecmin_binding=functionEmpty->raiseNot_found|Node(Empty,d,_,_)->d|Node(l,_,_,_)->min_bindinglletrecremove_min_binding=functionEmpty->invalid_arg"Map.remove_min_elt"|Node(Empty,_,r,_)->r|Node(l,d,r,_)->balance(remove_min_bindingl)drletmerget1t2=match(t1,t2)with(Empty,t)->t|(t,Empty)->t|(_,_)->letd=min_bindingt2inbalancet1d(remove_min_bindingt2)letrecremoveid=functionEmpty->Empty|(Node(l,k,r,h)asm)->letc=String.compare(nameid)(namek.ident)inifc=0thenmatchk.previouswith|None->mergelr|Somek->Node(l,k,r,h)elseifc<0thenletll=removeidlinifl==llthenmelsebalancellkrelseletrr=removeidrinifr==rrthenmelsebalancelkrrletrecfind_previousid=functionNone->raiseNot_found|Somek->ifsameidk.identthenk.dataelsefind_previousidk.previousletrecfind_sameid=functionEmpty->raiseNot_found|Node(l,k,r,_)->letc=String.compare(nameid)(namek.ident)inifc=0thenifsameidk.identthenk.dataelsefind_previousidk.previouselsefind_sameid(ifc<0thenlelser)letrecfind_namen=functionEmpty->raiseNot_found|Node(l,k,r,_)->letc=String.comparen(namek.ident)inifc=0thenk.ident,k.dataelsefind_namen(ifc<0thenlelser)letrecget_all=function|None->[]|Somek->(k.ident,k.data)::get_allk.previousletrecfind_alln=functionEmpty->[]|Node(l,k,r,_)->letc=String.comparen(namek.ident)inifc=0then(k.ident,k.data)::get_allk.previouselsefind_alln(ifc<0thenlelser)letrecfold_auxfstackaccu=functionEmpty->beginmatchstackwith[]->accu|a::l->fold_auxflaccuaend|Node(l,k,r,_)->fold_auxf(l::stack)(fkaccu)rletfold_nameftblaccu=fold_aux(funk->fk.identk.data)[]accutblletrecfold_datafdaccu=matchdwithNone->accu|Somek->fk.identk.data(fold_datafk.previousaccu)letfold_allftblaccu=fold_aux(funk->fold_dataf(Somek))[]accutbl(* let keys tbl = fold_name (fun k _ accu -> k::accu) tbl [] *)letreciterf=functionEmpty->()|Node(l,k,r,_)->iterfl;fk.identk.data;iterfr(* Idents for sharing keys *)(* They should be 'totally fresh' -> neg numbers *)letkey_name=""letmake_key_generator()=letc=ref1infunction|Local_|Scoped_->letstamp=!cindecrc;Local{name=key_name;stamp=stamp}|global_id->Misc.fatal_errorf"Ident.make_key_generator () %s"(nameglobal_id)letcomparexy=matchx,ywith|Localx,Localy->letc=x.stamp-y.stampinifc<>0thencelsecomparex.namey.name|Local_,_->1|_,Local_->(-1)|Scopedx,Scopedy->letc=x.stamp-y.stampinifc<>0thencelsecomparex.namey.name|Scoped_,_->1|_,Scoped_->(-1)|Globalx,Globaly->comparexy|Global_,_->1|_,Global_->(-1)|Predef{stamp=s1;_},Predef{stamp=s2;_}->compares1s2letoutputocid=output_stringoc(unique_nameid)lethashi=(Char.code(namei).[0])lxor(stampi)letoriginal_equal=equalincludeIdentifiable.Make(structtypenonrect=tletcompare=compareletoutput=outputletprint=printlethash=hashletequal=sameend)letequal=original_equalletrename_no_exn=function|Local{name;stamp=_}|Scoped{name;stamp=_;scope=_}->incrcurrentstamp;Local{name;stamp=!currentstamp}|id->idletget_currentstamp()=!currentstamp