123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129(*
Ensure unique identifiers that don't conflict with predefined Python
identifiers or prefixes reserved by atdpy.
*)openPrintftypet={reserved_identifiers:(string,unit)Hashtbl.t;reserved_prefixes:stringlist;safe_prefix:string;(* Translations are used to look up the translation of an already-registered
identifier. *)translations:(string,string)Hashtbl.t;(* Reverse translations are needed when creating a new translation.
They're for checking that the new translation doesn't conflict with
an existing translation. *)reverse_translations:(string,string)Hashtbl.t;}lethas_prefix~prefixsrc=letlen=String.lengthprefixinifString.lengthsrc<lenthenfalseelsetryfori=0tolen-1doifprefix.[i]<>src.[i]thenraiseExitdone;truewithExit->falseletinit~reserved_identifiers~reserved_prefixes~safe_prefix=letreserved_identifiers=lettbl=Hashtbl.create100inList.iter(funid->Hashtbl.replacetblid())reserved_identifiers;tblinList.iter(funprefix->ifhas_prefix~prefixsafe_prefixtheninvalid_arg(sprintf"Unique_name.init: safe_prefix %S is not safe as it \
conflicts with reserved prefix %S"safe_prefixprefix))reserved_prefixes;{reserved_identifiers;reserved_prefixes;safe_prefix;translations=Hashtbl.create100;reverse_translations=Hashtbl.create100;}letis_reservedenvsrc_or_dst=Hashtbl.memenv.reserved_identifierssrc_or_dstletconflicts_with_existing_translationenvdst=Hashtbl.memenv.reverse_translationsdstlethas_reserved_prefixenvsrc=List.exists(funprefix->has_prefix~prefixsrc)env.reserved_prefixesletenumerate_suffixes()=letcounter=ref0inletget_suffix()=letsuf=match!counterwith|0->""|1->"_"|n->string_of_intninincrcounter;sufinget_suffixletregisterenvsrc=letget_suffix=enumerate_suffixes()inletrecfind_available_suffix()=letsuffix=get_suffix()inletdst=src^suffixinletdst=(* assume that safe_prefix is not a prefix of a reserved prefix *)ifhas_reserved_prefixenvdstthenenv.safe_prefix^dstelsedstinifis_reservedenvdst||conflicts_with_existing_translationenvdstthenfind_available_suffix()elsedstinletdst=find_available_suffix()inHashtbl.addenv.translationssrcdst;Hashtbl.addenv.reverse_translationsdstsrc;dstlettranslate_onlyenvsrc=Hashtbl.find_optenv.translationssrclettranslateenvsrc=matchtranslate_onlyenvsrcwith|Somedst->dst|None->registerenvsrcletreverse_translateenvdst=Hashtbl.find_optenv.reverse_translationsdstletcreateenvsrc=letget_suffix=enumerate_suffixes()inletrecfind_available_suffix()=letsuffix=get_suffix()inletsrc=src^suffixinifHashtbl.memenv.translationssrcthenfind_available_suffix()elsesrcinletsrc=find_available_suffix()inignore(registerenvsrc);srcletallenv=Hashtbl.fold(funsrcdstacc->(src,dst)::acc)env.translations[]|>List.sort(fun(a,_)(b,_)->String.compareab)