12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433(**************************************************************************)(* *)(* Copyright 2013 OCamlPro *)(* *)(* All rights reserved. This file is distributed under the terms of *)(* the Lesser GNU Public License version 3.0. *)(* *)(* This software is distributed in the hope that it will be useful, *)(* but WITHOUT ANY WARRANTY; without even the implied warranty of *)(* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *)(* Lesser GNU General Public License for more details. *)(* *)(**************************************************************************)(* - Types - *)openIndexTypes(* This type is used to pass the full structure to functions building sub-trees,
so that they can (lazily) lookup type or module type indirections in scope.
Values of this type should have the form {[
[ [Module;Submodule], lazy subtrie_at_Module.Submodule;
[Module], lazy subtrie_at_Module;
[], lazy subtrie_at_Root ]
]}
*)typeparents=(stringlist*tLazy.t)list(* - Utility functions - *)openIndexMiscletorig_file_name=function|Cmtf|Cmti f|Cmif->fletequal_kindk1k2=matchk1,k2with|Type,Type|Value,Value|Exception,Exception|OpenType,OpenType|Field_,Field_|Variant_,Variant_|Method_,Method_|Module,Module|ModuleType,ModuleType|Class,Class|ClassType,ClassType|Keyword,Keyword->true|Type,_|Value,_|Exception,_|OpenType,_|Field_,_|Variant_,_|Method_,_|Module,_|ModuleType,_|Class,_|ClassType,_|Keyword,_->falselethas_kindkinfo=equal_kindkinfo.kind(* - Trie loading and manipulation functions - *)(* Used as path separator *)letdot=char_of_int0letfix_path_prefixstripnew_pfx=letrectlnn=function|[]->[]|_::tlasl->ifn>0thentln(n-1)tlelselinletrev_pfx=List.revnew_pfxinfunid->{idwithpath=List.rev_appendrev_pfx(tlnstripid.path)}let fix_orig_path_prefixstripnew_pfx=letrectlnn=function|[]->[]|_::tlasl->ifn>0thentln(n-1)tlelselinletrev_pfx=List.revnew_pfxinfunid->{idwith orig_path=List.rev_appendrev_pfx(tlnstripid.orig_path)}letoverriding_merge t1t2=letf=(IndexTrie.filter_keys((<>)dot)t2)inIndexTrie.fold0(funtpathvalues->lett=List.fold_left(funtv->IndexTrie.addtpathv)(IndexTrie.unsettpath)valuesinifList.exists(function|{kind=Module|ModuleType|Class|ClassType}->true|_->false)valuesthenletsubpath=path@[dot]inIndexTrie.graft_lazytsubpath(lazy(IndexTrie.subt2subpath))elset)ft1letopen_module?(cleanup_path=false)tpath=letstrip_path=fix_path_prefix (List.lengthpath)[]inletsubmodule =IndexTrie.subt(modpath_to_key path)inletsubmodule=ifcleanup_paththenIndexTrie.map(fun_key->strip_path)submoduleelsesubmodulein(* IndexTrie.merge ~values:(fun _ v -> v) t submodule -- keeps hidden values in subtrees *)overriding_mergetsubmoduleletalias?(cleanup_path=false)toriginalias=letsubtree=IndexTrie.subt(modpath_to_key origin)inletsubtree=letstrip_path=fix_path_prefix(List.lengthorigin)aliasinifcleanup_paththenIndexTrie.map(fun_key->strip_path)subtreeelsesubtreeinIndexTrie.graftt(modpath_to_keyalias)subtree(* Pops comments from a list of comments (string * loc) to find the ones that
are associated to a given location. Also returns the remaining comments after
the location. *)letassociate_comment?(after_only=false)commentslocnextloc=ifloc=Location.nonethenNone,commentselseletlstart=loc.Location.loc_start.Lexing.pos_lnumandlend=loc.Location.loc_end.Lexing.pos_lnuminletisnextc=nextloc<>Location.none&&nextloc.Location.loc_start.Lexing.pos_cnum<c.Location.loc_end.Lexing.pos_cnuminletrecaux=function|[]->None,[]|(comment,cloc)::comments->let cstart=cloc.Location.loc_start.Lexing.pos_lnumandcend=cloc.Location.loc_end.Lexing.pos_lnuminifcend<lstart-1||cstart<lend&&after_onlythenauxcommentselseifcstart>lend+1||isnextcloc ||cstart>lstart&&cend<lend(*keep inner comments *)thenNone,(comment,cloc)::commentselseifString.length comment<2||comment.[0]<>'*'||comment.[1]='*'thenauxcommentselseletcomment=String.trim(String.subcomment1(String.lengthcomment-1))inmatchauxcommentswith|None,comments->Somecomment,comments|Somec,comments ->Some(String.concat"\n" [comment;c]),commentsinaux commentsletty_of_sig_item=letopenPrinttypinfunction#ifOCAML_VERSION<(4,08,0)|Types.Sig_value(id,decl)->tree_of_value_descriptioniddecl|Types.Sig_type(id,decl,rs)->tree_of_type_declarationiddeclrs|Types.Sig_typext(id,decl,es)->tree_of_extension_constructoriddecles|Types.Sig_module(id,{Types.md_type },rs)->tree_of_moduleidmd_typers|Types.Sig_modtype(id,decl)->tree_of_modtype_declaration iddecl|Types.Sig_class(id,decl,rs)->tree_of_class_declaration iddeclrs|Types.Sig_class_type(id,decl,rs)->tree_of_cltype_declaration iddeclrs#else|Types.Sig_value(id,decl,_)->tree_of_value_descriptioniddecl|Types.Sig_type(id,decl,rs,_)->tree_of_type_declarationiddeclrs|Types.Sig_typext(id,decl,es,_)-> tree_of_extension_constructoriddecles|Types.Sig_module(id,_,{Types.md_type},rs,_)->tree_of_moduleidmd_typers|Types.Sig_modtype(id,decl,_)->tree_of_modtype_declarationiddecl|Types.Sig_class(id,decl,rs,_)->tree_of_class_declarationiddeclrs|Types.Sig_class_type(id,decl,rs,_)->tree_of_cltype_declarationiddeclrs#endif(* -- Qualifying types -- *)#ifOCAML_VERSION>=(4,08,0)letns={Outcometree.printed_name=s}letnn{Outcometree.printed_name}=printed_name#elselet ns=sletnns=s#endif(* The types may contain unqualified identifiers.
We need to do some (lazy) lookup in the trie to qualify them, so that
for example [M.empty] shows up as [M.t] and not just [t] *)letqualify_ty(parents:parents)ty=letqualifyident =letpath=letrec get_path=function|Outcometree.Oide_identname->[nnname]|Outcometree.Oide_dot(path,s)->get_pathpath@[s]|Outcometree.Oide_apply(p1,_p2)->get_pathp1inget_pathidentinletkey=modpath_to_key~enddot:falsepathinletreclookup=function|[]|([],_)::_->ident|((path1::pathn),lazyt)::parents->ifnot(List.exists(has_kindType)(IndexTrie.find_alltkey))thenlookupparentselseletrecadd_pfx=function|Outcometree.Oide_dot(idp,s)->Outcometree.Oide_dot(add_pfxidp,s)|Outcometree.Oide_apply(idp,idp2)->Outcometree.Oide_apply(add_pfxidp,idp2)|Outcometree.Oide_idents->letparentpath=List.fold_left(funacc modl->Outcometree.Oide_dot(acc,modl))(Outcometree.Oide_ident(npath1))pathninOutcometree.Oide_dot(parentpath,nns)in add_pfxidentinlookupparentsinletrecaux=(* Some kind of Outcometree.map_ty *)letopenOutcometreeinfunction|Otyp_abstract->Otyp_abstract#ifOCAML_VERSION>=(5,1,0)|Otyp_alias{non_gen;aliased;alias}->Otyp_alias{non_gen;aliased=auxaliased;alias}#else|Otyp_alias(ty,str)->Otyp_alias(auxty,str)#endif|Otyp_arrow(str,ty1,ty2)->Otyp_arrow(str,auxty1,auxty2)#ifOCAML_VERSION>=(5,1,0)|Otyp_class(id,tylist)->Otyp_class (qualifyid,List.mapauxtylist)#else|Otyp_class(bl,id,tylist)->Otyp_class(bl,qualifyid,List.mapauxtylist)#endif|Otyp_constr (id,tylist)->Otyp_constr(qualifyid,List.mapauxtylist)|Otyp_manifest(ty1,ty2)->Otyp_manifest(auxty1,auxty2)#ifOCAML_VERSION>=(5,1,0)|Otyp_object{fields;open_row}->Otyp_object{fields=List.map(fun(str,ty)->str,auxty)fields;open_row}#else|Otyp_object(strtylist,blopt)->Otyp_object (List.map(fun(str,ty)->str,auxty)strtylist,blopt)#endif|Otyp_record(strbltylist)->Otyp_record(List.map(fun(str,bl,ty)->str,bl,auxty)strbltylist)|Otyp_stuffstr->Otyp_stuffstr|Otyp_sum(strtylisttyoptlist)->Otyp_sum#if OCAML_VERSION>=(4,14,0)(List.map(fun{ocstr_name=str;ocstr_args=tylist;ocstr_return_type=tyopt}->{ocstr_name=str;ocstr_args =List.mapauxtylist;ocstr_return_type=matchtyoptwithSomety->Some(auxty)|None->None})#else(List.map (fun(str,tylist,tyopt)->str,List.mapauxtylist,matchtyoptwithSomety->Some(auxty)|None->None)#endifstrtylisttyoptlist)|Otyp_tuple (tylist)->Otyp_tuple(List.mapauxtylist)|Otyp_var(bl,str)->Otyp_var(bl,str)#ifOCAML_VERSION>=(5,1,0)|Otyp_variant(var,bl2,strlistopt)->Otyp_variant(var,bl2,strlistopt)#else|Otyp_variant(bl,var,bl2,strlistopt)->Otyp_variant(bl,var,bl2,strlistopt)#endif|Otyp_poly (str,ty)->Otyp_poly(str,auxty)#ifOCAML_VERSION>=(4,13,0)|Otyp_module(str,fl)->Otyp_module(str,List.map(fun(s,ty)->(s,auxty))fl)#else|Otyp_module (str,strl,tylist)->Otyp_module(str,strl,List.mapauxtylist)#endif|Otyp_open->Otyp_open#ifOCAML_VERSION>=(4,03,0)|Otyp_attribute(ty,attr)->Otyp_attribute(auxty,attr)#endifinauxtyletqualify_ty_in_sig_item(parents:parents)=letqual=qualify_typarentsinletopenOutcometreeinfunction|Osig_type(out_type_decl,rc)->Osig_type({out_type_declwithotype_type=qualout_type_decl.otype_type;otype_cstrs =List.map(fun(ty1,ty2)->qualty1,qualty2)out_type_decl.otype_cstrs},rc)#ifOCAML_VERSION >= (4,03,0)|Osig_valueo->Osig_value{owithoval_type=qualo.oval_type}#else|Osig_value(str,ty,str2)->Osig_value (str,qual ty,str2)#endif|Osig_typext(constr,es)->Osig_typext({constrwithoext_args=List.mapqualconstr.oext_args},es)|out_sig->out_sig(* don't get down in modules, classes and their types *)(* -- end -- *)letwith_path_loc?srcpathloc=matchsrcpathwith|None ->loc|Somepath->letpath=(* Some magic to get the real source when using jbuilder or
ocamlbuild *)letlpath=string_split Filename.dir_sep.[0]pathinletrecaux=function|"_build"::"default"::r->r|"_build"::"install" ::_->[]|"_build"::r->r|p::r->p::auxr|[]->[]inString.concatFilename.dir_sep(aux lpath)inletwith_path_pospos=letopenLexinginifnot(Filename.is_relativepos.pos_fname)thenposelse{poswithpos_fname=Filename.concatpathpos.pos_fname}inletopenLocationin{locwithloc_start=with_path_posloc.loc_start;loc_end=with_path_posloc.loc_end}letloc_of_sig_item=function#ifOCAML_VERSION<(4,08,0)|Types.Sig_value(_,descr)->descr.Types.val_loc|Types.Sig_type(_,descr,_)->descr.Types.type_loc|Types.Sig_typext(_,descr,_)->descr.Types.ext_loc|Types.Sig_module(_,descr,_)->descr.Types.md_loc|Types.Sig_modtype(_,descr)->descr.Types.mtd_loc|Types.Sig_class(_,descr,_)->descr.Types.cty_loc|Types.Sig_class_type(_,descr,_)->descr.Types.clty_loc#else|Types.Sig_value(_,descr,_)->descr.Types.val_loc|Types.Sig_type(_,descr,_,_)->descr.Types.type_loc|Types.Sig_typext(_,descr,_,_)->descr.Types.ext_loc|Types.Sig_module(_,_,descr,_,_)->descr.Types.md_loc|Types.Sig_modtype(_,descr,_)->descr.Types.mtd_loc|Types.Sig_class(_,descr,_,_)->descr.Types.cty_loc|Types.Sig_class_type(_,descr,_,_)->descr.Types.clty_loc#endifletid_of_sig_item=function#ifOCAML_VERSION<(4,08,0)|Types.Sig_value(id,_)|Types.Sig_type(id,_,_)|Types.Sig_typext(id,_,_)|Types.Sig_module (id,_,_)|Types.Sig_modtype(id,_)|Types.Sig_class(id,_,_)|Types.Sig_class_type(id,_,_)#else|Types.Sig_value(id,_,_)|Types.Sig_type(id,_,_,_)|Types.Sig_typext(id,_,_,_)|Types.Sig_module(id,_,_,_,_)|Types.Sig_modtype(id,_,_)|Types.Sig_class(id,_,_,_)|Types.Sig_class_type(id,_,_,_)#endif-> idletkind_of_sig_item=function|Types.Sig_value _->Value|Types.Sig_type_->Type#ifOCAML_VERSION<(4,08,0)|Types.Sig_typext (_,_,Types.Text_exception)->Exception#else|Types.Sig_typext(_,_,Types.Text_exception,_)->Exception#endif|Types.Sig_typext_->OpenType|Types.Sig_module_->Module|Types.Sig_modtype_->ModuleType|Types.Sig_class_->Class|Types.Sig_class_type_->ClassTypeletattrs_of_sig_item=function#ifOCAML_VERSION <(4,08,0)|Types.Sig_value(_,descr)->descr.Types.val_attributes|Types.Sig_type(_,descr,_)->descr.Types.type_attributes|Types.Sig_typext(_,descr,_)->descr.Types.ext_attributes|Types.Sig_module(_,descr,_)->descr.Types.md_attributes|Types.Sig_modtype(_,descr)->descr.Types.mtd_attributes|Types.Sig_class(_,descr,_)->descr.Types.cty_attributes|Types.Sig_class_type(_,descr,_)->descr.Types.clty_attributes#else|Types.Sig_value(_,descr,_)->descr.Types.val_attributes|Types.Sig_type(_,descr,_,_)->descr.Types.type_attributes|Types.Sig_typext(_,descr,_,_)->descr.Types.ext_attributes|Types.Sig_module(_,_,descr,_,_)->descr.Types.md_attributes|Types.Sig_modtype (_,descr,_)->descr.Types.mtd_attributes|Types.Sig_class(_,descr,_,_)->descr.Types.cty_attributes|Types.Sig_class_type(_,descr,_,_)->descr.Types.clty_attributes#endifletdoc_of_attributesattrs=letdoc_loc_id="ocaml.doc"in(* not exported ! *)letopenParsetreeintry#ifOCAML_VERSION>=(4,08,0)matchList.find(fun{attr_name={Location.txt}}->txt=doc_loc_id)attrswith|{attr_payload=PStr[{pstr_desc=Pstr_eval({pexp_desc},_)}]}->#elsematchList.find(fun({Location.txt},_)->txt=doc_loc_id)attrswith|_,PStr[{pstr_desc=Pstr_eval({pexp_desc},_)}]->#endif(matchpexp_descwith#ifOCAML_VERSION>=(4,11,0)|Pexp_constant(Pconst_string(s,_,_))->Somes#elifOCAML_VERSION>=(4,03,0)|Pexp_constant(Pconst_string(s,_))->Somes#else|Pexp_constant(Const_string(s,_))->Somes#endif|_->debug"Unexpected ocaml.doc docstring format";None)|_->NonewithNot_found->None#ifOCAML_VERSION>=(4,14,0)letmake_type_expr~desc~level~scope~id=Types.create_exprdesc~level~scope~id#elifOCAML_VERSION>=(4,13,0)letmake_type_expr~desc~level~scope~id=Types.Private_type_expr.createdesc~level~scope~id#elifOCAML_VERSION>=(4,07,0)letmake_type_expr~desc~level~scope~id={Types.desc;level;scope;id}#elifOCAML_VERSION>=(4,03,0)letmake_type_expr~desc~level~id={Types.desc;level;id}#endiflettrie_of_type_decl?commentsinfoty_decl=matchty_decl.Types.type_kindwith#ifOCAML_VERSION>=(5,2,0)|Types.Type_abstract_->[],comments#else|Types.Type_abstract->[],comments#endif|Types.Type_open->[],comments|Types.Type_record(fields,_repr)->List.map(fun{Types.ld_id;ld_type;ld_attributes}->#if OCAML_VERSION>=(4,14,0)letty=Printtyp.tree_of_typexpPrinttyp.Typeld_typein#elseletty=Printtyp.tree_of_typexpfalseld_typein#endifletty=Outcometree.Osig_type (Outcometree.({otype_name="";otype_params=[];otype_type=ty;otype_private=Asttypes.Public;#ifOCAML_VERSION>=(4,03,0)#ifOCAML_VERSION>=(4,10,0)otype_immediate=Type_immediacy.Unknown;#elseotype_immediate=false;#endif#ifOCAML_VERSION>=(4,04,0)otype_unboxed=false;#endif#endifotype_cstrs =[];}),Outcometree.Orec_not)inletdoc=doc_of_attributesld_attributesinletid_name=Ident.nameld_idinstring_to_key id_name,IndexTrie.create~value:{path=info.path;orig_path=info.path;kind=Fieldinfo;name=id_name;ty=Somety;loc_sig=info.loc_sig;loc_impl=info.loc_impl;doc =lazydoc;file=info.file;}())fields,comments#if OCAML_VERSION>=(4,13,0)|Types.Type_variant (variants,_rep)->#else|Types.Type_variantvariants->#endifList.map(fun{Types.cd_id;cd_args;cd_attributes}->letty=letparams=matchcd_argswith#ifOCAML_VERSION>=(4,03,0)|Cstr_tuple[]->Outcometree.Otyp_sum[]|Cstr_tuple (param::_asl)->#ifOCAML_VERSION>=(4,14,0)Printtyp.tree_of_typexpPrinttyp.Type#elsePrinttyp.tree_of_typexpfalse#endif(make_type_expr~desc:(Types.Ttuplel)#ifOCAML_VERSION>=(4,14,0)~level:(Types.get_levelparam)#else~level:param.Types.level#endif#ifOCAML_VERSION>=(4,08,0)~scope:0#elifOCAML_VERSION>=(4,07,0)~scope:None#endif#ifOCAML_VERSION>=(4,14,0)~id:(Types.get_idparam))#else~id:param.Types.id)#endif|Cstr_record params->Outcometree.Otyp_record (List.map(funl->(Ident.namel.Types.ld_id,l.ld_mutable =Mutable,#ifOCAML_VERSION>=(4,14,0)Printtyp.tree_of_typexpPrinttyp.Typel.ld_type)#elsePrinttyp.tree_of_typexpfalsel.ld_type)#endif)params)#else|[]->Outcometree.Otyp_sum[]|param::_asl->Printtyp.tree_of_typexpfalse{Types.desc=Types.Ttuple l;level =param.Types.level;id=param.Types.id}#endifinOutcometree.Osig_type(Outcometree.({otype_name="";otype_params=[];otype_type=params;otype_private =Asttypes.Public;#ifOCAML_VERSION>=(4,03,0)#ifOCAML_VERSION>=(4,10,0)otype_immediate=Type_immediacy.Unknown;#elseotype_immediate=false;#endif#ifOCAML_VERSION>=(4,04,0)otype_unboxed =false;#endif#endifotype_cstrs=[];}),Outcometree.Orec_not)inletdoc=doc_of_attributescd_attributesinletid_name=Ident.namecd_idinstring_to_keyid_name,IndexTrie.create~value:{path =info.path;orig_path=info.path;kind=Variantinfo;name=id_name;ty=Somety;loc_sig=info.loc_sig;loc_impl=info.loc_impl;doc=lazydoc;file=info.file;}())variants,comments(** Implements looking up a module path in the parents list *)letlookup_parents(parents:parents)pathsig_path=letsig_key,path_key=matchsig_pathwith|hd::tl->modpath_to_key[hd],modpath_to_keytl|[]->assertfalseinletreclookup=function|[]->ifdebug_enabledthendebug"WARN: Module or sig reference %s not found a %s\n"(modpath_to_stringsig_path)(modpath_to_stringpath);IndexTrie.empty|(parentpath,lazyt)::parents->lets=IndexTrie.subtsig_keyinifs=IndexTrie.emptythenlookupparentselselets=IndexTrie.sub spath_keyinletrewrite_path=fix_path_prefix (List.lengthparentpath+List.length sig_path)pathinIndexTrie.map(fun_k v->rewrite_pathv)sinlookupparentsletrecpath_of_ocaml=function|Path.Pidentid->[Ident.nameid]#ifOCAML_VERSION>=(4,08,0)|Path.Pdot(path,s)->path_of_ocamlpath@[s]#else|Path.Pdot(path,s,_)->path_of_ocamlpath @[s]#endif|Path.Papply(p1,_p2)->path_of_ocamlp1#ifOCAML_VERSION>=(5,1,0)|Pextra_ty (p,_extra_ty)->path_of_ocamlp#endifletrectrie_of_sig_item?comments?srcpathimplloc_trie(parents:parents)(orig_file:orig_file)pathsig_itemnext=letid=id_of_sig_itemsig_iteminletloc=with_path_loc ?srcpath(loc_of_sig_itemsig_item)inletnextloc=matchnextwith|None-> Location.none|Somen->with_path_loc?srcpath(loc_of_sig_itemn)inletdoc,comments=matchdoc_of_attributes(attrs_of_sig_itemsig_item),commentswith|Somes,_->lazy(Somes),comments|None,None->lazyNone,None|None,Somecomments->letassoc=lazy(associate_comment(Lazy.forcecomments)locnextloc)inlazy(fst(Lazy.forceassoc)),Some(lazy(snd(Lazy.forceassoc)))inletty=Some(ty_of_sig_itemsig_item)inletkind=kind_of_sig_itemsig_iteminletloc_sig=lazylocinletloc_impl=lazy(matchimplloc_triewith|lazyNone->loc|lazy(Somet)->tryletpath =List.tlpath@[Ident.nameid]inletkey=modpath_to_key~enddot:falsepathinletc=List.find(has_kindkind)(IndexTrie.find_alltkey)inLazy.forcec.loc_implwithNot_found->Location.none)inletinfo={path;orig_path=path;kind;name=Ident.nameid;ty;loc_sig;loc_impl;doc;file=orig_file}inletsiblings,comments=(* read fields / variants ... *)matchsig_itemwith#ifOCAML_VERSION>=(4,08,0)|Types.Sig_type(_id,descr,_is_rec,_)->#else|Types.Sig_type(_id,descr,_is_rec)->#endiftrie_of_type_decl?commentsinfodescr|_->[],commentsin(* ignore functor arguments *)letrecsig_item_contents=function|Types.Sig_module#ifOCAML_VERSION>=(4,08,0)(id,presence,#ifOCAML_VERSION>=(4,10,0)({Types.md_type=Types.Mty_functor(_,s)}asfunct),#else({Types.md_type =Types.Mty_functor(_,_,s)}asfunct),#endifis_rec,visibility)->letfunct={functwithTypes.md_type=s}insig_item_contents (Types.Sig_module(id,presence,funct,is_rec,visibility))#else(id,({Types.md_type=Types.Mty_functor(_,_,s)}asfunct),is_rec)->letfunct={functwithTypes.md_type=s}insig_item_contents(Types.Sig_module(id,funct,is_rec))#endif|Types.Sig_modtype#ifOCAML_VERSION>=(4,08,0)#ifOCAML_VERSION>=(4,10,0)(id,({Types.mtd_type=Some(Types.Mty_functor(_,s))}asfunct),visibility)#else(id,({Types.mtd_type=Some(Types.Mty_functor(_,_,s))}as funct),visibility)#endif->letfunct={functwithTypes.mtd_type=Somes}insig_item_contents (Types.Sig_modtype(id,funct,visibility))#else(id,({Types.mtd_type=Some(Types.Mty_functor(_,_,s))}asfunct))->letfunct={functwithTypes.mtd_type=Somes}insig_item_contents(Types.Sig_modtype(id,funct))#endif|si->siin(* read module / class contents *)letchildren,comments =matchsig_item_contents sig_itemwith#ifOCAML_VERSION>=(4,08,0)|Types.Sig_module(id,_,{Types.md_type=Types.Mty_signaturesign},_,_)|Types.Sig_modtype(id,{Types.mtd_type=Some(Types.Mty_signaturesign)},_)#else|Types.Sig_module(id,{Types.md_type=Types.Mty_signaturesign},_)|Types.Sig_modtype(id,{Types.mtd_type=Some(Types.Mty_signaturesign)})#endif->letpath=path@[Ident.nameid]inletchildren_comments=lazy(foldl_next(fun(t,comments)signnext->letchlds,comments=trie_of_sig_item?comments?srcpathimplloc_trie((path,lazyt)::parents)orig_filepathsignnextinList.fold_leftIndexTrie.appendtchlds,comments)(IndexTrie.empty,comments)sign)inletchildren=lazy(fst(Lazy.force children_comments))inletcomments=matchcomments,children_commentswith|None,_->None|Some_,lazy(_,comments)->commentsinchildren,comments|Types.Sig_module(_,#ifOCAML_VERSION>=(4,08,0)_,#endif{Types.md_type=Types.Mty_identsig_ident#ifOCAML_VERSION>=(4,04,0)&&OCAML_VERSION<(4,08,0)|Types.Mty_alias (_,sig_ident)#else|Types.Mty_aliassig_ident#endif},_#ifOCAML_VERSION>=(4,08,0),_#endif)|Types.Sig_modtype(_,{Types.mtd_type=Some(Types.Mty_identsig_ident#ifOCAML_VERSION>=(4,04,0)&&OCAML_VERSION<(4,08,0)|Types.Mty_alias(_,sig_ident)#else|Types.Mty_aliassig_ident#endif)}#ifOCAML_VERSION>=(4,08,0),_#endif)->letsig_path=path_of_ocamlsig_identinletchildren=lazy((* Only keep the children, don't override the module reference *)letlocal_path=path@[Ident.nameid]inletcanonical()=matchdocwith|lazy(Somed)->letrecaux=function|"@canonical"::path::_->Some(IndexMisc.string_split'.'path)|_::r->auxr|[]->Noneinaux(IndexMisc.string_split' 'd)|_->Noneinletm=lazy(letm=lookup_parentsparentslocal_pathsig_pathinmatchcanonical()with|Somepath->letstrip_path=fix_orig_path_prefix (List.lengthsig_path)pathinIndexTrie.map(fun_key->strip_path)m|None->m)inIndexTrie.graft_lazy IndexTrie.empty[]m)inchildren,comments#ifOCAML_VERSION>=(4,08,0)|Types.Sig_class (id,{Types.cty_type=cty},_,_)|Types.Sig_class_type(id,{Types.clty_type=cty},_,_)#else|Types.Sig_class(id,{Types.cty_type=cty},_)|Types.Sig_class_type(id,{Types.clty_type=cty},_)#endif->letrecget_clsig=function|Types.Cty_constr (_,_,cty)|Types.Cty_arrow(_,_,cty)->get_clsigcty|Types.Cty_signature clsig->clsiginletclsig=get_clsig ctyinlet path=path@[Ident.nameid]inlet(fields,_)=Ctype.flatten_fields(Ctype.object_fields clsig.Types.csig_self)inlazy(List.fold_left(funt(lbl,_,ty_expr)->iflbl="*dummy method*"thentelse#ifOCAML_VERSION>=(4,14,0)let()=Printtyp.prepare_for_printing[ty_expr]inletty=Printtyp.tree_of_typexpPrinttyp.Typety_exprin#elselet ()=Printtyp.reset_and_mark_loopsty_exprinletty=Printtyp.tree_of_typexpfalsety_exprin#endifletty=Outcometree.Osig_type(Outcometree.({otype_name="";otype_params=[];otype_type=ty;otype_private=Asttypes.Public;#ifOCAML_VERSION>=(4,03,0)#ifOCAML_VERSION>=(4,10,0)otype_immediate=Type_immediacy.Unknown;#elseotype_immediate=false;#endif#ifOCAML_VERSION >=(4,04,0)otype_unboxed =false;#endif#endifotype_cstrs=[];}),Outcometree.Orec_not)inIndexTrie.addt(string_to_keylbl){path=path;orig_path=path;kind=Methodinfo;name=lbl;ty=Somety;loc_sig=loc_sig;loc_impl=loc_impl;doc=lazyNone;file=info.file})IndexTrie.emptyfields),comments|_->lazy IndexTrie.empty,commentsinletname=Ident.nameidinifString.lengthname>0&&name.[0]='#'then[],commentselse(string_to_keyname,IndexTrie.create~value:info~children:(lazy[dot,Lazy.forcechildren])())::siblings,comments(* These four functions go through the typedtree to extract includes *)letreclookup_trie_of_module_exprparentstpath=function|Typedtree.Tmod_ident(incpath,{Location.txt=_lid})->letincpath=path_of_ocamlincpathindebug"Including %s impl at %s\n"(modpath_to_stringincpath)(modpath_to_stringpath);letparents=(path,lazyt)::parentsinletsub=lookup_parentsparentspathincpathinoverriding_mergetsub|Typedtree.Tmod_constraint(e,_,_,_)(* | Typedtree.Tmod_apply (e,_,_) *)->lookup_trie_of_module_exprparentstpathe.mod_desc#ifOCAML_VERSION>=(4,10,0)|Typedtree.Tmod_apply({mod_desc=Typedtree.Tmod_functor(Typedtree.Named(Someid,_,_),f)},#else|Typedtree.Tmod_apply({mod_desc=Typedtree.Tmod_functor(id,_,_,f)},#endif{mod_desc=Typedtree.Tmod_ident(arg,_)|Typedtree.Tmod_constraint({mod_desc=Typedtree.Tmod_ident(arg,_)},_,_,_)},_)->letid_name=Ident.nameidinlett=lookup_trie_of_module_exprparentstpathf.Typedtree.mod_descindebug"Grafting %s at %s\n"id_name(modpath_to_string(path_of_ocamlarg));letfunctor_arg =lazy(lookup_parentsparents(path_of_ocamlarg)path)inIndexTrie.graft_lazyt(modpath_to_key[id_name])functor_arg|_->tletrecextract_includes_from_submodule_sigparents tpathname=function|Typedtree.Tmty_signaturesign->letpath=path@[name]inlet sub_includes=lazy(get_includes_sig ((path,lazyt)::parents)(IndexTrie.subt(modpath_to_key[name]))pathsign)inIndexTrie.graft_lazyt(modpath_to_key[name])sub_includes#ifOCAML_VERSION>=(4,10,0)|Typedtree.Tmty_functor(_,e)#else|Typedtree.Tmty_functor (_,_,_,e)#endif|Typedtree.Tmty_with(e,_)->extract_includes_from_submodule_sigparentstpathnamee.Typedtree.mty_desc|_->tandextract_includes_from_submodule_sig_optparentstpathidmty=#ifOCAML_VERSION>=(4,10,0)matchidwithNone->t|Someid->#endifextract_includes_from_submodule_sigparentstpath(Ident.nameid)mtyandget_includes_implparentstpathttree_struct=letrecextract_submodule_impltname=function|Typedtree.Tmod_structurestr->letpath=path@[name]inletsub_includes=lazy(get_includes_impl((path,lazyt)::parents)(IndexTrie.subt(modpath_to_key[name]))pathstr)inIndexTrie.graft_lazyt(modpath_to_key [name])sub_includes(* | Typedtree.Tmod_functor (arg_id,_,arg_t,e) *)#ifOCAML_VERSION>=(4,10,0)|Typedtree.Tmod_apply({mod_desc=Typedtree.Tmod_functor(Typedtree.Named(Someid,_,_),f)},#else|Typedtree.Tmod_apply({mod_desc=Typedtree.Tmod_functor(id,_,_,f)},#endif{mod_desc =Typedtree.Tmod_ident(arg,_)|Typedtree.Tmod_constraint({mod_desc =Typedtree.Tmod_ident(arg,_)},_,_,_)},_)->letid_name=Ident.nameidindebug"Grafting %s at %s\n" id_name(modpath_to_string(path_of_ocamlarg));letfunctor_arg=lazy(lookup_parents((path,lazyt)::parents)(path_of_ocamlarg)(path@[name]))inextract_submodule_impl(IndexTrie.graft_lazyt(modpath_to_key[id_name])functor_arg)namef.Typedtree.mod_desc#ifOCAML_VERSION>=(4,10,0)|Typedtree.Tmod_functor(_,e)#else|Typedtree.Tmod_functor(_,_,_,e)#endif|Typedtree.Tmod_constraint(e,_,_,_)->extract_submodule_impl tnamee.Typedtree.mod_desc|_->tinletextract_submodule_impl_opttidmty=#ifOCAML_VERSION>=(4,10,0)matchidwithNone->t|Someid->#endifextract_submodule_implt(Ident.nameid)mtyinList.fold_left(funtstruc_item->matchstruc_item.Typedtree.str_descwith#ifOCAML_VERSION >=(4,08,0)|Typedtree.Tstr_include{Typedtree.incl_mod={Typedtree.mod_desc=e}}->#else|Typedtree.Tstr_include{Typedtree.incl_mod={Typedtree.mod_desc=e}}->#endiflookup_trie_of_module_exprparentstpathe#ifOCAML_VERSION >=(4,08,0)|Typedtree.Tstr_openTypedtree.{open_expr={mod_desc=Tmod_ident(p,_loc)}}(* TODO: handle the other new open cases *)#else|Typedtree.Tstr_open{Typedtree.open_path=p}#endif->letsub=lookup_parents((path,lazyt)::parents)path(path_of_ocamlp)inoverriding_mergetsub|Typedtree.Tstr_module{Typedtree.mb_id;mb_expr={Typedtree.mod_desc}}->extract_submodule_impl_opttmb_idmod_desc|Typedtree.Tstr_recmodulel->List.fold_left(funt{Typedtree.mb_id;mb_expr={Typedtree.mod_desc}}->extract_submodule_impl_opttmb_idmod_desc)tl|Typedtree.Tstr_modtype{Typedtree.mtd_id=id;mtd_type=Some{Typedtree.mty_desc=e}}->extract_includes_from_submodule_sigparentstpath (Ident.nameid)e|_->t)tttree_struct.Typedtree.str_itemsandget_includes_sigparentstpathttree_sig=letrecextract_includest=function|Typedtree.Tmty_ident(incpath,_)->letincpath=path_of_ocamlincpathindebug "Including %s sig at %s\n"(modpath_to_string incpath)(modpath_to_stringpath);letparents=(path,lazyt)::parentsinletsub =lookup_parents parentspathincpathinoverriding_mergetsub|Typedtree.Tmty_with(e,_)->extract_includeste.Typedtree.mty_desc|Typedtree.Tmty_typeofe->lookup_trie_of_module_expr parentstpathe.Typedtree.mod_desc|_->tinList.fold_left (funtsig_item->match sig_item.Typedtree.sig_descwith|Typedtree.Tsig_include{Typedtree.incl_mod={Typedtree.mty_desc=e}}->extract_includeste|Typedtree.Tsig_module{Typedtree.md_id;md_type={Typedtree.mty_desc}}->extract_includes_from_submodule_sig_optparentstpathmd_idmty_desc|Typedtree.Tsig_modtype{Typedtree.mtd_id=id;mtd_type=Some{Typedtree.mty_desc}}->extract_includes_from_submodule_sigparentstpath(Ident.nameid)mty_desc|Typedtree.Tsig_recmodulel->List.fold_left(funt{Typedtree.md_id;md_type={Typedtree.mty_desc}}->extract_includes_from_submodule_sig_optparentstpathmd_idmty_desc)tl|_->t)tttree_sig.Typedtree.sig_itemsletadd_locs~locst=IndexTrie.map(funpathinfo->letloc_info=lazy (List.find(has_kindinfo.kind)(IndexTrie.find_alllocspath))inletlookupfld none =letloc=Lazy.force(fldinfo)inifloc=nonethen tryLazy.force(fld(Lazy.forceloc_info))withNot_found ->noneelselocin{infowithloc_sig=lazy(lookup(funi->i.loc_sig)Location.none);loc_impl=lazy(lookup (funi->i.loc_impl)Location.none);doc=lazy(lookup(funi->i.doc)None);})tletcmt_includesparentstpath cmt_contents =matchcmt_contents.Cmt_format.cmt_annotswith|Cmt_format.Implementationimpl->get_includes_impl parentstpathimpl|Cmt_format.Interfacesign->get_includes_sigparentstpathsign|_->IndexTrie.empty(* Can work in asubtree (t doesn't have to be the root) *)letqualify_type_identsparentst=letqualify_keyid=letrel_path=let recrm_pfxparentspath=matchparents,pathwith|[_root],path->path|_::parents,_::path->rm_pfxparentspath|_->assertfalseinrm_pfxparentsid.pathinletqualify_ty ty=letparents=letrecauxaccpath=matchacc,pathwith|((pfx,parent)::_),modl::r->lett=lazy(IndexTrie.sub(Lazy.forceparent)(string_to_key (modl)@[dot]))inaux((pfx@[modl],t)::acc)r|_->accinauxparentsrel_pathinqualify_ty_in_sig_item parents tyin{idwithty=matchid.tywithSomety->Some(qualify_tyty)|None->None}inIndexTrie.mapqualifytletcmt_signcmt_contents =matchcmt_contents.Cmt_format.cmt_annotswith|Cmt_format.Implementation{Typedtree.str_type=sign;_}|Cmt_format.Interface{Typedtree.sig_type=sign;_}|Cmt_format.Packed(sign,_)->Somesign|_->Noneletprotect_read readerf=tryreaderfwith|Cmt_format.Error _|Cmi_format.Error_->raise(Bad_formatf)(* Look for a cmt file for the purpose of loading implementation locations.
(assuming other information is already loaded eg. from the cmti). *)letlookup_loc_impl orig_file=matchorig_file with|Cmt_->None|Cmif|Cmtif->letcmt=Filename.chop_extensionf^".cmt"inifSys.file_exists cmtthenSomecmtelseletdir=Filename.dirnamecmtin(* dune 2puts .cmt under native/ while cmi and cmti are under byte/ *)ifFilename.basenamedir="byte"thenlet(/)=Filename.concatinletcmt=Filename.dirnamedir/"native"/Filename.basenamecmtinifSys.file_existscmtthenSome cmtelseNoneelseNoneletload_loc_implparents filename cmt_contents=debug" -Registering %s (for implementation locations)..."filename;letchrono=timer()inmatchcmt_signcmt_contentswith|Somesign->letsrcpath=cmt_contents.Cmt_format.cmt_builddir inlett=foldl_next(funtsig_itemnext->letchld,_comments=trie_of_sig_item ~srcpath(lazyNone)parents(Cmtfilename)[]sig_itemnextinList.fold_left IndexTrie.appendtchld)IndexTrie.emptysignindebug" %.3fs\n%!"(chrono());letincludes=cmt_includesparentst[]cmt_contentsinlett=add_locs ~locs:includestinSomet|_->debug" %.3fs\n%!"(chrono());Noneletload_cmi~qualifyroottmodulorig_file=IndexTrie.map_subtreet(string_to_keymodul)(funt->letfile=orig_file_nameorig_fileinletinfo=lazy(letchrono=timer()inletinfo=protect_readCmi_format.read_cmifileindebug" %.3fs\n"(chrono());info)inletimpl_cmt=lazy(matchlookup_loc_implorig_filewith|Somecmt->debug"Loading %s (for implementation locations)..."cmt;letchrono=timer()inletcmt_contents=protect_readCmt_format.read_cmtcmtindebug" %.3fs\n"(chrono());Some(cmt,cmt_contents)|None ->None)inletchildren=lazy(letinfo=Lazy.forceinfoindebug" -Registering %s..."file;letchrono=timer()inletrecimplloc_trie=lazy(matchLazy.forceimpl_cmtwith|Some(file,info)->load_loc_impl[[modul],lazy_t;[],root]fileinfo|None->None)andlazy_t=lazy(foldl_next(funtsig_itemnext->letparents=[[modul],lazyt;[],root]inlet chld,_comments=trie_of_sig_itemimplloc_trie parentsorig_file [modul]sig_itemnextinList.fold_left IndexTrie.appendtchld)IndexTrie.emptyinfo.Cmi_format.cmi_sign)inlett=Lazy.forcelazy_tindebug" %.3fs ; done\n%!"(chrono());t)inlett=IndexTrie.addt[]{path=[];orig_path =[];kind=Module;name=modul;ty=None;loc_sig=Lazy.from_valLocation.none;loc_impl =Lazy.from_valLocation.none;doc=lazyNone;file =orig_file;}inletchildren=ifqualify thenlazy(qualify_type_idents[[modul],children;[],root](Lazy.forcechildren))elsechildreninIndexTrie.graft_lazyt[dot]children)letload_cmt~qualifyroottmodulorig_file =IndexTrie.map_subtree t(string_to_keymodul)(fun t->letcmt_file=orig_file_name orig_fileinletinfo=lazy(debug "Loading %s..." cmt_file;letchrono=timer()inletinfo=protect_read Cmt_format.read_cmtcmt_fileindebug" %.3fs\n"(chrono());info)inletimpl_cmt=lazy(matchlookup_loc_implorig_filewith|Somecmt->debug"Loading %s (for implementation locations)..."cmt;letchrono=timer()inletcmt_contents=protect_readCmt_format.read_cmtcmtindebug" %.3fs\n" (chrono());Some(cmt,cmt_contents)|None->None)inletchildren=lazy(letinfo=Lazy.forceinfoindebug" -Registering %s..."cmt_file;letchrono=timer()inletcomments=Some(Lazy.from_valinfo.Cmt_format.cmt_comments)inletrecimplloc_trie=lazy(matchLazy.forceimpl_cmtwith|Some(file,info)->load_loc_impl[[modul],lazy_t;[],root]fileinfo|None ->None)and lazy_t=lazy(match cmt_signinfo with|Somesign->let srcpath=info.Cmt_format.cmt_builddir inlett,_trailing_comments =foldl_next(fun(t,comments)sig_itemnext->letparents=[[modul],lazyt;[],root]inletchld,comments =trie_of_sig_item?comments~srcpathimplloc_trieparentsorig_file[modul]sig_itemnextinList.fold_leftIndexTrie.appendtchld,comments)(IndexTrie.empty,comments)signint|None->IndexTrie.empty)inlett=Lazy.forcelazy_tindebug" %.3fs\n%!"(chrono());t)inletchildren=lazy (letincludes=cmt_includes[[modul],children;[],root]t[](Lazy.forceinfo)inadd_locs~locs:includes(Lazy.forcechildren))inletloc_sig,loc_impl =letof_infoi=matchi.Cmt_format.cmt_sourcefilewith|Somef->Location.in_filef|None->Location.noneinmatchorig_file with|Cmi_|Cmti_->lazy(of_info(Lazy.forceinfo)),lazy(matchLazy.forceimpl_cmtwith|Some(_,i)->of_infoi|None->Location.none)|Cmt_->let l=lazy(of_info(Lazy.forceinfo))inl,linlett=IndexTrie.addt[]{path=[];orig_path =[];kind=Module;name=modul;ty=None;loc_sig;loc_impl;doc=lazyNone;file=orig_file;}inletchildren=ifqualifythenlazy(qualify_type_idents[[modul],children;[],root](Lazy.forcechildren))else childreninIndexTrie.graft_lazyt[dot]children)letdebug_file_counter=ref0letdebug_dir_counter =ref0letload_file~qualify roottmodulf=incrdebug_file_counter;matchfwith|Cmi_->load_cmi~qualifyroottmodulf|Cmt_|Cmti_->load_cmt~qualifyroottmodulfletload_files~qualifytdirfiles=letsplit_filenamefile=tryleti=String.rindexfile'.'inletlen=String.lengthfileinletmodul=capitalize(String.subfile0i)inletext=lowercase(String.subfile(i+1)(len-i-1))inmodul,extwithNot_found->file,""inletsort_modulesacc(dir,file)=letregbase=IndexTrie.addacc(string_to_keybase)inmatchsplit_filenamefilewith|base,"cmi"->regbase(Cmi(Filename.concatdirfile))|base,"cmt"->regbase(Cmt(Filename.concatdirfile))|base,"cmti"->regbase(Cmti(Filename.concatdirfile))|_->accinletmodules=List.fold_leftsort_modulesIndexTrie.emptydirfilesinletrecroot=lazy(IndexTrie.fold0(funtmodulfiles->matchfileswith|[]->t|f1::fs->(* Load by order of priority:
- first cmti, more info than cmi, ocamldocs, and doesn't expose
private values
- then cmt, it means there is no mli, everything is exposed
- then cmi, has the interface if not much more *)letchoose_filef1f2=matchf1,f2with|(Cmti_asf),_|_,(Cmti_asf)|(Cmt_asf),_|_,(Cmt_asf)|(Cmi_asf),_->finletfile=List.fold_leftchoose_filef1fsinletmodul=key_to_stringmodulinload_file~qualifyroottmodulfile)modulest)inLazy.forcerootletload_dirs~qualifytdirs=letdirfiles=List.fold_left(funaccdir->incrdebug_dir_counter;letfiles=List.rev_map(funf->dir,f)(Array.to_list(Sys.readdirdir))inList.rev_appendfilesacc)[](List.revdirs)inload_files~qualifytdirfilesletload~qualifypaths=lett=IndexTrie.create()inlett=List.fold_left(funtinfo->IndexTrie.addt(string_to_keyinfo.name)info)tIndexPredefined.allinletchrono=timer()inlett=load_dirs~qualifytpathsindebug"Modules directory loaded in %.3fs (%d files in %d directories)...\n"(chrono())!debug_file_counter!debug_dir_counter;#ifOCAML_VERSION>=(4,07,0)open_module~cleanup_path:truet["Stdlib"]#elseopen_module~cleanup_path:truet["Pervasives"]#endifletfully_open_module?(cleanup_path=false)~qualifytpath=letbase_path=matchpathwith|m::_->string_to_keym|[]->[]in(* Merge trying to keep the documentation if the new trie has none *)letmergeintfsimpls=letkeep_intfinfo=tryletintf=List.find(has_kindinfo.kind)intfsinletdoc=lazy(matchinfo.docwith|lazyNone->Lazy.forceintf.doc|lazysome->some)inletloc_sig=intf.loc_sigin{infowithdoc;loc_sig}withNot_found->infoinList.mapkeep_intfimplsinlettpath=modpath_to_keypathinletmod_trie=IndexTrie.subttpathinletmod_trie=trymatch(IndexTrie.findtbase_path).filewith|Cmtif|Cmif->letf=Filename.chop_extensionf^".cmt"inifnot(Sys.file_existsf)thenmod_trieelseletdir,base=Filename.dirnamef,Filename.basenamefinlett=load_files~qualifyIndexTrie.empty[dir,base]inlett=IndexTrie.subttpathinIndexTrie.merge~values:mergemod_triet|Cmt_->mod_triewithNot_found->mod_triein(* cleanup and merge at root (cf. open_module) *)letmod_trie=ifcleanup_paththenletpathlen=List.lengthpathinIndexTrie.map(fun_key->fix_path_prefixpathlen[])mod_trieelsemod_trieinoverriding_mergetmod_trieletadd_file~qualifytfile=letdir,file=Filename.dirnamefile,Filename.basenamefileinload_files~qualifyt[dir,file]