Legend:
Page
Library
Module
Module type
Parameter
Class
Class type
Source
Source file name.ml
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295open!ImportmoduleFormat=Caml.Formatletfold_dot_suffixesname~init:acc~f=letreccollapse_after_at=function|[]->[]|part::parts->ifnot(String.is_emptypart)&&Char.equalpart.[0]'@'then[String.concat(String.drop_prefixpart1::parts)~sep:"."]elsepart::collapse_after_atpartsinletrecloopaccparts=matchpartswith|[]->acc|part::parts->loop(f(String.concat(part::parts)~sep:".")acc)partsinString.split_on_charname~sep:'.'|>collapse_after_at|>loopacc;;letdot_suffixesname=fold_dot_suffixesname~init:[]~f:(funxacc->x::acc)letsplit_path=letrecloopsi=ifi=String.lengthsthen(s,None)elsematchs.[i]with|'.'->after_dots(i+1)|_->loops(i+1)andafter_dotsi=ifi=String.lengthsthen(s,None)elsematchs.[i]with|'A'..'Z'->(String.prefixs(i-1),Some(String.drop_prefixsi))|'.'->after_dots(i+1)|_->loops(i+1)infuns->loops0modulePattern=structtypet={name:string;dot_suffixes:String.Set.t}letmakename={name;dot_suffixes=String.Set.of_list(dot_suffixesname)}letnamet=t.nameletmatchestmatched=String.Set.memmatchedt.dot_suffixesendletget_outer_namespacename=matchString.index_optname'.'with|None->None|Somei->Some(String.subname~pos:0~len:i)moduleWhitelisted=struct(* White list the following attributes, as well as all their dot suffixes.
Since these attributes are interpreted by the compiler itself, we cannot check
at the level of a ppx rewriter that they have been properly interpreted, so
we just accept them anywhere.
Sadly, the compiler silently ignores them if they are misplaced...
*)letcreate_setfully_qualified_names=List.fold_left~f:(funaccname->fold_dot_suffixesname~init:acc~f:(funxacc->String.Set.addxacc))~init:String.Set.emptyfully_qualified_namesletattributes=create_set["ocaml.alert";"ocaml.boxed";"ocaml.deprecated";"ocaml.deprecated_mutable";"ocaml.doc";"ocaml.extension_constructor";"ocaml.immediate";"ocaml.immediate64";"ocaml.inline";"ocaml.inlined";"ocaml.local";"ocaml.noalloc";"ocaml.ppwarning";"ocaml.remove_aliases";"ocaml.specialise";"ocaml.specialised";"ocaml.tailcall";"ocaml.text";"ocaml.unboxed";"ocaml.unroll";"ocaml.unrolled";"ocaml.untagged";"ocaml.warn_on_literal_pattern";"ocaml.warnerror";"ocaml.warning"](* White list the following extensions.
Since these extensions are interpreted by the compiler itself, we cannot check
at the level of a ppx rewriter that they have been properly interpreted, so
we just accept them anywhere.
*)letextensions=create_set["ocaml.error";"ocaml.extension_constructor"]letis_whitelisted~kindname=matchkindwith|`Attribute->String.Set.memnameattributes|`Extension->String.Set.memnameextensionsletget_attribute_list()=String.Set.elementsattributesletget_extension_list()=String.Set.elementsextensionsendmoduleReserved_namespaces=structlettbl:(string,unit)Hashtbl.t=Hashtbl.create16letreservens=Hashtbl.add_exntbl~key:ns~data:()let()=reserve"merlin"let()=reserve"reason"let()=reserve"refmt"let()=reserve"metaocaml"let()=reserve"ocamlformat"letis_in_reserved_namespacesname=matchget_outer_namespacenamewith|Somens->Hashtbl.memtblns|None->Hashtbl.memtblnameletcheck_not_reserved~kindname=letkind,list=matchkindwith|`Attribute->"attribute",Whitelisted.attributes|`Extension->"extension",Whitelisted.extensionsinifString.Set.memnamelistthenPrintf.ksprintffailwith"Cannot register %s with name '%s' as it matches an \
%s reserved by the compiler"kindnamekindelseifis_in_reserved_namespacesnamethenPrintf.ksprintffailwith"Cannot register %s with name '%s' as its namespace \
is marked as reserved"kindnameendletignore_checksname=Reserved_namespaces.is_in_reserved_namespacesname||String.is_prefixname~prefix:"_"moduleRegistrar=structtypeelement={fully_qualified_name:string;declared_at:Caller_id.t}typeall_for_context={mutableall:elementString.Map.t}type'at={all_by_context:('a,all_for_context)Hashtbl.t;skip:stringlist;kind:string;string_of_context:'a->stringoption}letcreate~kind~current_file~string_of_context={all_by_context=Hashtbl.create16;skip=[current_file;__FILE__];kind;string_of_context}letget_all_for_contexttcontext=Hashtbl.find_or_addt.all_by_contextcontext~default:(fun()->{all=String.Map.empty});;letregister~kindtcontextname=Reserved_namespaces.check_not_reserved~kindname;letcaller=Caller_id.get~skip:t.skipinletall=get_all_for_contexttcontextin(matchString.Map.find_optnameall.allwith|None->()|Somee->letdeclared_at=function|None->""|Some(loc:Caml.Printexc.location)->Printf.sprintf" declared at %s:%d"loc.filenameloc.line_numberinletcontext=matcht.string_of_contextcontextwith|None->""|Somes->" on "^s^"s"inPrintf.ksprintffailwith"%s '%s'%s%s matches %s '%s'%s"(String.capitalize_asciit.kind)namecontext(declared_atcaller)t.kinde.fully_qualified_name(declared_ate.declared_at));lett={fully_qualified_name=name;declared_at=caller}inall.all<-fold_dot_suffixesname~init:all.all~f:(funnameacc->String.Map.addnametacc);;;letspellchecktcontext?(white_list=[])name=letall=letall=get_all_for_contexttcontextinString.Map.fold(funkey_acc->key::acc)all.all[]inmatchSpellcheck.spellcheck(all@white_list)namewith|Some_asx->x|None->letother_contexts=Hashtbl.fold(functx{all}acc->ifPoly.(<>)contextctx&&String.Map.memnameallthenmatcht.string_of_contextctxwith|None->acc|Somes->(s^"s")::accelseacc)t.all_by_context[]inletpp_text=Format.pp_print_textinletcurrent_contextppf=matcht.string_of_contextcontextwith|None|Some""->()|Somes->leta_or_an=matchs.[0]with|'a'|'e'|'i'|'o'|'u'|'y'->"an"|_->"a"inFormat.fprintfppf"@ but@ is@ used@ here@ in@ the@ context@ of@ %s@ %a"a_or_anpp_textsinmatchList.sort~cmp:(funxy->-(String.comparexy))other_contextswith|[]->None|[c]->Some(Format.asprintf"@[Hint:@ `%s'@ is@ available@ for@ %a%t.@]@\n\
Did you put it at the wrong level?"namepp_textccurrent_context)|last::rev_others->letothers=List.revrev_othersinSome(Format.asprintf"@[Hint:@ `%s'@ is@ available@ for@ %a@ and@ %a%t.@]@\n\
Did you put it at the wrong level?"name(Format.pp_print_listpp_text~pp_sep:(funppf()->Format.fprintfppf",@ "))otherspp_textlastcurrent_context);;(* TODO: hint spelling errors regarding reserved namespaces names and white
listed names instead of taking an optional [white_list] parameter. *)letraise_errorftcontext?white_listfmt(name:stringLoc.t)=Printf.ksprintf(funmsg->matchspellchecktcontextname.txt?white_listwith|None->Location.raise_errorf~loc:name.loc"%s"msg|Somes->Location.raise_errorf~loc:name.loc"%s.\n%s"msgs)fmtname.txt;;end