Legend:
Page
Library
Module
Module type
Parameter
Class
Class type
Source
Source file name.ml
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326open!ImportmoduleFormat=Stdlib.Formatletfold_dot_suffixesname~init:acc~f=letreccollapse_after_at=function|[]->[]|part::parts->if(not(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|>loopaccletdot_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_suffixesend(* On the namespace "a.NAMESPACE", return the pair ("a", NAMESPACE) *)letsplit_outer_namespacename=matchString.index_optname'.'with|None->None|Somei->letn=String.lengthnameinletbefore_dot=String.subname~pos:0~len:iinletafter_dot=String.subname~pos:(i+1)~len:(n-i-1)inSome(before_dot,after_dot)moduleAllowlisted=struct(* Allow 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";"ocaml.toplevel_printer"(*Interpreted by the toplevel/utop*);"toplevel_printer"(*Interpreted by the toplevel/utop*);](* Allow 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_allowlisted~kindname=matchkindwith|`Attribute->String.Set.memnameattributes|`Extension->String.Set.memnameextensionsletget_attribute_list()=String.Set.elementsattributesletget_extension_list()=String.Set.elementsextensionsendmoduleReserved_namespaces=structtypereserved=(string,sub_namespaces)Hashtbl.tandsub_namespaces=All|Sub_namespacesofreserved(* If [tbl] contains a mapping from "x" to [All], then "x" and all paths that
* start with "x." are reserved with respect to [tbl]
*
* If [tbl] contains a mapping from "x" to [Sub_namespaces tbl'], and P is
* reserved with respect to [tbl'], then all paths "x.P" are reserved with
* respect to [tbl].
*)letcreate_reserved():reserved=Hashtbl.create16letrecreservenstbl=matchsplit_outer_namespacenswith|None->Hashtbl.add_exntbl~key:ns~data:All|Some(outer_ns,rest_ns)->(matchHashtbl.find_or_addtblouter_ns~default:(fun()->Sub_namespaces(create_reserved()))with|Sub_namespacesrest_tbl->reserverest_nsrest_tbl|All->())letrecis_in_reserved_namespacesnametbl=matchsplit_outer_namespacenamewith|Some(ns,rest)->(matchHashtbl.find_opttblnswith|Some(Sub_namespacesrest_tbl)->is_in_reserved_namespacesrestrest_tbl|SomeAll->true|None->false)|None->(matchHashtbl.find_opttblnamewith|SomeAll->true|Some(Sub_namespaces_)|None->false)lettbl=create_reserved()letreservens=reservenstblletis_in_reserved_namespacesname=is_in_reserved_namespacesnametbllet()=reserve"merlin"let()=reserve"reason"let()=reserve"refmt"(* reason *)let()=reserve"ns"(* rescript *)let()=reserve"res"(* rescript *)let()=reserve"metaocaml"let()=reserve"ocamlformat"let()=reserve"ppxlib.migration"letcheck_not_reserved~kindname=letkind,list=matchkindwith|`Attribute->("attribute",Allowlisted.attributes)|`Extension->("extension",Allowlisted.extensions)inifString.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})letcheck_collisions_local~caller~all_for_contexttcontextname=matchString.Map.find_optnameall_for_context.allwith|None->()|Somee->letdeclared_at=function|None->""|Some(loc:Stdlib.Printexc.location)->Printf.sprintf" declared at %s:%d"loc.filenameloc.line_numberinletcontext=matcht.string_of_contextcontextwith|None->""|Somes->" on "^s^"s"inPrintf.ksprintffailwith"Some ppx-es tried to register conflicting transformations: %s \
'%s'%s%s matches %s '%s'%s"(String.capitalize_asciit.kind)namecontext(declared_atcaller)t.kinde.fully_qualified_name(declared_ate.declared_at)letcheck_collisionstcontextname=letcaller=Caller_id.get~skip:t.skipinletall_for_context=get_all_for_contexttcontextincheck_collisions_local~caller~all_for_contexttcontextnameletregister~kindtcontextname=Reserved_namespaces.check_not_reserved~kindname;letcaller=Caller_id.get~skip:t.skipinletall=get_all_for_contexttcontextincheck_collisions_local~caller~all_for_context:alltcontextname;lett={fully_qualified_name=name;declared_at=caller}inall.all<-fold_dot_suffixesname~init:all.all~f:(funnameacc->String.Map.addnametacc)letspellchecktcontext?(allowlist=[])name=letall_for_context=get_all_for_contexttcontextinletall=String.Map.fold(funkey_acc->key::acc)all_for_context.all[]inmatchSpellcheck.spellcheck(all@allowlist)namewith|Some_asx->x|NonewhenString.Map.memnameall_for_context.all->None|None->(letother_contexts=Hashtbl.fold(functxall_from_contextacc->ifPoly.(<>)contextctx&&String.Map.memnameall_from_context.allthenmatcht.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))moduleError=struct(* TODO: hint spelling errors regarding reserved namespaces names and allowlisted
names instead of taking an optional [allowlist] parameter. *)letcreateftcontext?allowlistfmt(name:stringLoc.t)=Printf.ksprintf(funmsg->matchspellchecktcontextname.txt?allowlistwith|None->Location.Error.createf~loc:name.loc"%s"msg|Somes->Location.Error.createf~loc:name.loc"%s.\n%s"msgs)fmtname.txtletraise_errorftcontext?allowlistfmt(name:stringLoc.t)=Location.Error.raise@@createftcontext?allowlistfmtnameleterror_extensionftcontext?allowlistfmt(name:stringLoc.t)=Location.Error.to_extension@@createftcontext?allowlistfmtnameendletraise_errorf=Error.raise_errorfend