Legend:
Page
Library
Module
Module type
Parameter
Class
Class type
Source
Source file ppx_deriving_make.ml
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219openPpxlibopenAsttypesopenParsetreeopenAst_helperopenPpx_deriving.Ast_convenienceletderiver="make"letraise_errorf=Ppx_deriving.raise_errorfletattr_defaultcontext=Attribute.declare"deriving.make.default"contextAst_pattern.(single_expr_payload__)(fune->e)letattr_default=(attr_defaultAttribute.Context.label_declaration,attr_defaultAttribute.Context.core_type)letmk_attr_splitcontext=Attribute.declare_flag"deriving.make.split"contextletct_attr_split=mk_attr_splitAttribute.Context.core_typeletlabel_attr_split=mk_attr_splitAttribute.Context.label_declarationletattr_split=(label_attr_split,ct_attr_split)letmk_attr_maincontext=Attribute.declare_flag"deriving.make.main"contextletct_attr_main=mk_attr_mainAttribute.Context.core_typeletlabel_attr_main=mk_attr_mainAttribute.Context.label_declarationletattr_main=(label_attr_main,ct_attr_main)letget_label_attribute(label_attr,ct_attr)label=matchAttribute.getlabel_attrlabelwith|Some_asv->v|None->Attribute.getct_attrlabel.pld_typelethas_label_flag(label_flag,ct_flag)({pld_type;_}aslabel)=Attribute.has_flagct_flagpld_type||Attribute.has_flaglabel_flaglabelletfind_mainlabels=letmains,regulars=List.partition(has_label_flagattr_main)labelsinmatchmains,regularswith|[],labels->Ok(None,labels)|[main],labels->Ok(Somemain,labels)|_::{pld_loc;_}::_,_->Error(Location.error_extensionf~loc:pld_loc"Duplicate [@deriving.%s.main] annotation"deriver)letis_optional({pld_name={txt=name};pld_type;_}aslabel)=matchget_label_attributeattr_defaultlabelwith|Some_->true|None->has_label_flagattr_splitlabel||(matchPpx_deriving.remove_pervasives~deriverpld_typewith|[%type:[%t?_]list]|[%type:[%t?_]option]->true|_->false)letadd_str_label_arg~quoter~locaccum({pld_name={txt=name};pld_type;_}aslabel)=matchget_label_attributeattr_defaultlabelwith|Somedefault->Exp.fun_(Label.optionalname)(Some(Ppx_deriving.quote~quoterdefault))(pvarname)accum|None->letpld_type=Ppx_deriving.remove_pervasives~deriverpld_typeinifhas_label_flagattr_splitlabelthenmatchpld_typewith|[%type:[%t?lhs]*[%t?rhs]list]whenname.[String.lengthname-1]='s'->letname'=String.subname0(String.lengthname-1)inExp.fun_(Label.labelledname')None(pvarname')(Exp.fun_(Label.optionalname)(Some[%expr[]])(pvarname)[%exprlet[%ppvarname]=[%eevarname'],[%eevarname]in[%eaccum]])|_->Ast_builder.Default.pexp_extension~loc(Location.error_extensionf~loc"[@deriving.%s.split] annotation requires a type of form \
'a * 'a list and label name ending with `s'"deriver)elsematchpld_typewith|[%type:[%t?_]list]->Exp.fun_(Label.optionalname)(Some[%expr[]])(pvarname)accum|[%type:[%t?_]option]->Exp.fun_(Label.optionalname)None(pvarname)accum|_->Exp.fun_(Label.labelledname)None(pvarname)accumletstr_of_record_type~quoter~loclabels=letfields=labels|>List.map(fun{pld_name={txt=name;loc}}->name,evarname)inmatchfind_mainlabelswith|Errorextension->Ast_builder.Default.pexp_extension~locextension|Ok(main,labels)->lethas_option=List.existsis_optionallabelsinletfn=matchmainwith|Some{pld_name={txt=name}}->Exp.fun_Label.nolabelNone(pvarname)(recordfields)|Nonewhenhas_option->Exp.fun_Label.nolabelNone(punit())(recordfields)|None->recordfieldsin(* The labels list must be reversed here so that the arguments are in the
same order as the record fields. *)List.fold_left(add_str_label_arg~quoter~loc)fn(List.revlabels)letstr_of_type({ptype_loc=loc}astype_decl)=letquoter=Ppx_deriving.create_quoter()inmatchtype_decl.ptype_kindwith|Ptype_recordlabels->letcreator=str_of_record_type~quoter~loclabelsinOk(Vb.mk(pvar(Ppx_deriving.mangle_type_decl(`Prefixderiver)type_decl))(Ppx_deriving.sanitize~quotercreator))|_->Error(Location.error_extensionf~loc"%s can be derived only for record types"deriver)letwrap_predef_optiontyp=typletadd_sig_label_argaccum({pld_name={txt=name;loc};pld_type;_}aslabel)=matchget_label_attributeattr_defaultlabelwith|Some_->Typ.arrow(Label.optionalname)(wrap_predef_optionpld_type)accum|None->letpld_type=Ppx_deriving.remove_pervasives~deriverpld_typeinifhas_label_flagattr_splitlabelthenmatchpld_typewith|[%type:[%t?lhs]*[%t?rhs]list]whenname.[String.lengthname-1]='s'->letname'=String.subname0(String.lengthname-1)inTyp.arrow(Label.labelledname')lhs(Typ.arrow(Label.optionalname)(wrap_predef_option[%type:[%trhs]list])accum)|_->Ast_builder.Default.ptyp_extension~loc(Location.error_extensionf~loc"[@deriving.%s.split] annotation requires a type of form \
'a * 'a list and label name ending with `s'"deriver)elsematchpld_typewith|[%type:[%t?_]list]->Typ.arrow(Label.optionalname)(wrap_predef_optionpld_type)accum|[%type:[%t?opt]option]->Typ.arrow(Label.optionalname)(wrap_predef_optionopt)accum|_->Typ.arrow(Label.labelledname)pld_typeaccumletsig_of_record_type~loc~typlabels=matchfind_mainlabelswith|Errorextension->Ast_builder.Default.ptyp_extension~locextension|Ok(main,labels)->lethas_option=List.existsis_optionallabelsinlettyp=matchmainwith|Some{pld_name={txt=name};pld_type}->Typ.arrowLabel.nolabelpld_typetyp|Nonewhenhas_option->Typ.arrowLabel.nolabel(tconstr"unit"[])typ|None->typin(* The labels list must be reversed here so that the arguments are in the
same order as the record fields. *)List.fold_leftadd_sig_label_argtyp(List.revlabels)letsig_of_type({ptype_loc=loc}astype_decl)=lettyp=Ppx_deriving.core_type_of_type_decltype_declinmatchtype_decl.ptype_kindwith|Ptype_recordlabels->lettyp=sig_of_record_type~loc~typlabelsinletval_name=Ppx_deriving.mangle_type_decl(`Prefixderiver)type_declinOk(Sig.value(Val.mk(mknolocval_name)typ))|_->Error(Location.error_extensionf~loc"%s can only be derived for record types"deriver)(* Ppxlib does not keep track of which type the attribute was attached to
in a set of type declarations and does not provide a nice and reliable
way to manually check it.
Until we have something better, we have to assume that the
[[@@deriving make]] attribute was meant for the whole set and properly
placed. That means that if there is at least one type declaration in the
set for which we can derive make, we will ignore errors from the rest. *)letpartition_resultl=leterrors,oks=List.fold_left(fun(errors,oks)res->matchreswith|Okx->(errors,x::oks)|Errore->(e::errors,oks))([],[])linList.reverrors,List.revoksletimpl_generator=Deriving.Generator.V2.make_noarg(fun~ctxt(_,type_decls)->matchpartition_result(List.mapstr_of_typetype_decls)with|_,(_::_asvbs)->[Str.valueNonrecursivevbs]|errors,[]->letloc=Expansion_context.Deriver.derived_item_locctxtinList.map(funext->Ast_builder.Default.pstr_extension~locext[])errors)letintf_generator=Deriving.Generator.V2.make_noarg(fun~ctxt(_,type_decls)->matchpartition_result(List.mapsig_of_typetype_decls)with|_,(_::_asvds)->vds|errors,[]->letloc=Expansion_context.Deriver.derived_item_locctxtinList.map(funext->Ast_builder.Default.psig_extension~locext[])errors)letderiving:Deriving.t=Deriving.addderiver~str_type_decl:impl_generator~sig_type_decl:intf_generator