1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980(*---------------------------------------------------------------------------
Copyright (c) 2011 The cmdliner programmers. All rights reserved.
SPDX-License-Identifier: ISC
---------------------------------------------------------------------------*)moduleCmap=Map.Make(Char)(* character maps. *)type'avalue=(* type for holding a bound value. *)|Preof'a(* value is bound by the prefix of a key. *)|Keyof'a(* value is bound by an entire key. *)|Amb(* no value bound because of ambiguous prefix. *)|Nil(* not bound (only for the empty trie). *)type'at={v:'avalue;succs:'atCmap.t}letempty={v=Nil;succs=Cmap.empty}letis_emptyt=t=empty(* N.B. If we replace a non-ambiguous key, it becomes ambiguous but it's
not important for our use. Also the following is not tail recursive but
the stack is bounded by key length. *)letaddtkd=letreclooptklenidpre_d=matchi=lenwith|true->lett'={v=Keyd;succs=t.succs}inbeginmatcht.vwith|Keyold->`Replaced(old,t')|_->`Newt'end|false->letv=matcht.vwith|Amb|Pre_->Amb|Key_asv->v|Nil->pre_dinlett'=tryCmap.findk.[i]t.succswithNot_found->emptyinmatchloopt'klen(i+1)dpre_dwith|`Newn->`New{v;succs=Cmap.addk.[i]nt.succs}|`Replaced(o,n)->`Replaced(o,{v;succs=Cmap.addk.[i]nt.succs})inlooptk(String.lengthk)0d(Pred(* allocate less *))letfind_nodetk=letrecauxtkleni=ifi=lenthentelseaux(Cmap.findk.[i]t.succs)klen(i+1)inauxtk(String.lengthk)0letfindtk=trymatch(find_nodetk).vwith|Keyv|Prev->`Okv|Amb->`Ambiguous|Nil->`Not_foundwithNot_found->`Not_foundletambiguitiestp=(* ambiguities of [p] in [t]. *)trylett=find_nodetpinmatcht.vwith|Key_|Pre_|Nil->[]|Amb->letadd_charsc=s^(String.make1c)inletrem_chars=String.subs0((String.lengths)-1)inletto_listm=Cmap.fold(funktacc->(k,t)::acc)m[]inletrecauxaccp=function|((c,t)::succs)::rest->letp'=add_charpcinletacc'=matcht.vwith|Pre_|Amb->acc|Key_->(p'::acc)|Nil->assertfalseinauxacc'p'((to_listt.succs)::succs::rest)|[]::[]->acc|[]::rest->auxacc(rem_charp)rest|[]->assertfalseinaux[]p(to_listt.succs::[])withNot_found->[]letof_listl=letaddt(s,v)=matchaddtsvwith`Newt->t|`Replaced(_,t)->tinList.fold_leftaddemptyl