Legend:
Page
Library
Module
Module type
Parameter
Class
Class type
Source
Source file common.ml
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291openPpxlibopenAst_builder.Defaultletlist_assoc_find_exnt~equalkey=matchList.find_opt(fun(key',_)->equalkeykey')twith|None->raiseNot_found|Somex->sndxletlist_assoc_memt~equalkey=matchList.find_opt(fun(key',_)->equalkeykey')twith|None->false|Some_->trueletstring_concat?(sep="")l=matchlwith|[]->""(* The stdlib does not specialize this case because it could break existing projects. *)|[x]->x|l->String.concatseplletstring_split_on_charsstr~on=letrecchar_list_meml(c:char)=matchlwith|[]->false|hd::tl->Char.equalhdc||char_list_memtlcinletsplit_genstr~on=letis_delimc=char_list_memoncinletlen=String.lengthstrinletrecloopacclast_pospos=ifpos=-1thenString.substr0last_pos::accelseifis_delimstr.[pos]then(letpos1=pos+1inletsub_str=String.substrpos1(last_pos-pos1)inloop(sub_str::acc)pos(pos-1))elseloopacclast_pos(pos-1)inloop[]len(len-1)insplit_genstr~onletis_whitespace=function|'\t'|'\n'|'\011'(* vertical tab *)|'\012'(* form feed *)|'\r'|' '->true|_->falseletstring_strip?(drop=is_whitespace)t=letlfindi?(pos=0)t~f=letn=String.lengthtinletrecloopi=ifi=nthenNoneelseiffit.[i]thenSomeielseloop(i+1)inloopposinletrfindi?post~f=letrecloopi=ifi<0thenNoneelseiffit.[i]thenSomeielseloop(i-1)inletpos=matchposwith|Somepos->pos|None->String.lengtht-1inloopposinletlast_non_drop~dropt=rfindit~f:(fun_c->not(dropc))inletfirst_non_drop~dropt=lfindit~f:(fun_c->not(dropc))inletlength=String.lengthtiniflength=0||not(dropt.[0]||dropt.[length-1])thentelse(matchfirst_non_dropt~dropwith|None->""|Somefirst->(matchlast_non_dropt~dropwith|None->assertfalse|Somelast->String.subtfirst(last-first+1)))letlist_partition_tft~f=letpartition_mapt~f=letreclooptfstsnd=matchtwith|[]->List.revfst,List.revsnd|x::t->(matchfxwith|Oky->loopt(y::fst)snd|Errory->looptfst(y::snd))inloopt[][]inletfx=iffxthenOkxelseErrorxinpartition_mapt~fletcore_typesloc=ListLabels.map~f:(fun(s,y)->s,y)["unit",[%exprRpc.Types.Unit];"int",[%exprRpc.Types.(BasicInt)];"int32",[%exprRpc.Types.(BasicInt32)];"int64",[%exprRpc.Types.(BasicInt64)];"string",[%exprRpc.Types.(BasicString)];"float",[%exprRpc.Types.(BasicFloat)];"bool",[%exprRpc.Types.(BasicBool)]](** Many of the following functions are lifted from ppx_deriving. It's quite likely that
there are good alternatives to these somewhere in ppxlib, but I've not yet found them.
They are used to deal with parameterised types. When declaring a function derived from
a parameterised type, the function will be extended to take an argument for each
type parameter. The important functions below are `poly_fun_of_type_decl` and
`poly_apply_of_type_decl` - for declaring and using the derived functions respectively.
*)letfold_right_type_paramsfnparamsaccum=ListLabels.fold_right~f:(fun(param,_)accum->matchparamwith|{ptyp_desc=Ptyp_any;_}->accum|{ptyp_desc=Ptyp_varname;_}->fnnameaccum|_->assertfalse)params~init:accum(** [fold_right_type_decl fn accum type_] performs a right fold over all type variable
(i.e. not wildcard) parameters in [type_]. *)letfold_right_type_declfn{ptype_params;_}accum=fold_right_type_paramsfnptype_paramsaccum(** [poly_fun_of_type_decl type_ expr] wraps [expr] into [fun poly_N -> ...] for every
type parameter ['N] present in [type_]. For example, if [type_] refers to
[type ('a, 'b) map], [expr] will be wrapped into [fun poly_a poly_b -> [%e expr]]. *)letpoly_fun_of_type_decl~loctype_declexpr=fold_right_type_decl(funnameexpr->pexp_fun~locNolabelNone(ppat_var~loc{txt="poly_"^name;loc})expr)type_declexprletfold_left_type_paramsfnaccumparams=ListLabels.fold_left~f:(funaccum(param,_)->matchparamwith|{ptyp_desc=Ptyp_any;_}->accum|{ptyp_desc=Ptyp_varname;_}->fnaccumname|_->assertfalse)~init:accumparams(** [fold_left_type_decl fn accum type_] performs a left fold over all type variable
(i.e. not wildcard) parameters in [type_]. *)letfold_left_type_declfnaccum{ptype_params;_}=fold_left_type_paramsfnaccumptype_params(** [poly_apply_of_type_decl type_ expr] wraps [expr] into [expr poly_N] for every
type parameter ['N] present in [type_]. For example, if [type_] refers to
[type ('a, 'b) map], [expr] will be wrapped into [[%e expr] poly_a poly_b].
[_] parameters are ignored. *)letpoly_apply_of_type_decl~loctype_declexpr=fold_left_type_decl(funexprname->Ast_helper.Exp.applyexpr[Nolabel,evar~loc("poly_"^name)])exprtype_decl(** [expr_of_option ~loc o] turns an optional expression into an expression
of an optional value. In several places there are optional attributes,
e.g. [@@version foo], which end up as values of type `expression option`.
These are often turned into optional values in the generated code. *)letexpr_of_option~loco=matchowith|None->[%exprNone]|Somed->[%exprSome[%ed]](** Typed attribute getters *)moduleAttrs=structletdefaultcontext=Attribute.declare"rpc.default"contextAst_pattern.(pstr(pstr_eval__nil^::nil))(funx->x)letlabel_default=defaultAttribute.Context.label_declarationlettd_default=defaultAttribute.Context.type_declarationletct_default=defaultAttribute.Context.core_typeletrtag_default=defaultAttribute.Context.rtagletdoccontext=Attribute.declare"rpc.doc"contextAst_pattern.(pstr(pstr_eval__nil^::nil))(funx->x)letlabel_doc=docAttribute.Context.label_declarationletconstr_doc=docAttribute.Context.constructor_declarationlettd_doc=docAttribute.Context.type_declarationletversioncontext=Attribute.declare"rpc.version"contextAst_pattern.(pstr(pstr_eval__nil^::nil))(funx->x)letlabel_version=versionAttribute.Context.label_declarationlettd_version=versionAttribute.Context.type_declarationletconstr_version=versionAttribute.Context.constructor_declarationletlabel_typ=Attribute.declare"rpc.typ"Attribute.Context.label_declarationAst_pattern.(pstr(pstr_eval__nil^::nil))(funx->x)letnamecontext=Attribute.declare"rpc.name"contextAst_pattern.(pstr(pstr_eval(pexp_constant(pconst_string____none))nil^::nil))(funx_loc->x)letconstr_name=nameAttribute.Context.constructor_declarationletrt_name=nameAttribute.Context.rtagletkey=Attribute.declare"rpc.key"Attribute.Context.label_declarationAst_pattern.(pstr(pstr_eval(pexp_constant(pconst_string____none))nil^::nil))(funx_loc->x)letis_dict=Attribute.declare"rpc.dict"Attribute.Context.core_typeAst_pattern.(pstrnil)()end(* The following functions are for extracting `ocaml.doc` attributes from the AST. These are
captured and used for 'doc' fields of the generated values representing the types. Ppxlib
seems to object to using these attributes as they are 'already in use', so we don't get to
use the nice `Attributes` module and have to roll our own. *)letattrlocnameattrs=letpat=Ast_pattern.(pstr(pstr_eval(pexp_constant(pconst_string____none))__^::nil))inList.find_opt(fun{attr_name={txt;_};_}->String.equaltxtname)attrs|>Option.map(fun{attr_payload;_}->attr_payload)|>funo->Option.bindo(funstr->Ast_pattern.parsepatlocstr~on_error:(fun_->None)(funstr_loc_->Somestr))letsplit=string_split_on_chars~on:['\n']letconvert_docx=splitx|>ListLabels.map~f:(string_strip~drop:(function|'\n'|' '->true|_->false))(** [get_doc loc rpcdoc attrs] extracts documentation from the type declarations. rpcdoc is
the result of looking for \@doc tags. If this is found, we use that. If not, we look for
ocamldoc docstrings and return them instead. In both cases, the result is an expression of
type list *)letget_doc~locrpcdoc(attrs:attributes)=letocamldoc=attrloc"ocaml.doc"attrsinmatchrpcdoc,ocamldocwith|Somee,_->e|_,Somes->elist~loc(convert_docs|>ListLabels.map~f:(estring~loc))|_,_->elist~loc[]