Legend:
Page
Library
Module
Module type
Parameter
Class
Class type
Source
Source file ppx_deriving_cconv.ml
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443# 1 "ppx_deriving_cconv.cppo.ml"(* Largely inspired from ppx_deriving_yojson *)openLongidentopenLocationopenAsttypesopenParsetreemoduleAH=Ast_helpermoduleAC=Ast_convenienceletderiver="cconv"letraise_errorf=Ppx_deriving.raise_errorfletencode_prefix=`Prefix"encode"letdecode_prefix=`Prefix"decode"letargn=Printf.sprintf"arg%d"letattr_encoderattrs=Ppx_deriving.attr~deriver"encoder"attrs|>Ppx_deriving.Arg.(get_attr~deriverexpr)letattr_decoderattrs=Ppx_deriving.attr~deriver"decoder"attrs|>Ppx_deriving.Arg.(get_attr~deriverexpr)letattr_ignoreattrs=Ppx_deriving.attr~deriver"ignore"attrs|>Ppx_deriving.Arg.(get_flag~deriver)letattr_defaultattrs=Ppx_deriving.attr~deriver"default"attrs|>Ppx_deriving.Arg.(get_attr~deriverexpr)letattr_stringnamedefaultattrs=matchPpx_deriving.attr~derivernameattrs|>Ppx_deriving.Arg.(get_attr~deriverstring)with|Somex->x|None->defaultletattr_key=attr_string"key"(* fold right, with index of element *)letfold_right_iflacc=letrecfold'faccil=matchlwith|[]->acc|x::tail->letacc=fold'facc(i+1)tailinfixaccinfold'facc0l# 59 "ppx_deriving_cconv.cppo.ml"letextract_pcd_args_tuple_values~locpcd_args=matchpcd_argswith|Pcstr_tuplel->l|Pcstr_record_->(* When calling this method, the constructors have been checked
already during pattern matching, but handle it just in case *)raise_errorf~loc"%s cannot be derived for record variants"deriverletcontains_record_variantconstrs=letis_record_variantconstr=matchconstr.pcd_argswith|Pcstr_record_->true|Pcstr_tuple_->falseinList.existsis_record_variantconstrs# 76 "ppx_deriving_cconv.cppo.ml"(* generate a [typ CConv.Encode.encoder] for the given [typ].
@param self an option contains the type being defined, and a reference
indicating whether a self-reference was used *)letencode_of_typ~selftyp=letrecencode_of_typtyp=matchattr_encodertyp.ptyp_attributeswith|None->encode_of_typ_rectyp|Somee->eandencode_of_typ_rectyp=matchtypwith|[%type:unit]->[%exprCConv.Encode.unit]|[%type:int]->[%exprCConv.Encode.int]|[%type:float]->[%exprCConv.Encode.float]|[%type:bool]->[%exprCConv.Encode.bool]|[%type:string]->[%exprCConv.Encode.string]|[%type:bytes]->[%exprCConv.Encode.(mapBytes.to_stringstring)]|[%type:char]->[%exprCConv.Encode.char]|[%type:[%t?typ]ref]->[%exprCConv.Encode.(map(!)[%eencode_of_typtyp])]|[%type:[%t?typ]list]->[%exprCConv.Encode.(list[%eencode_of_typtyp])]|[%type:int32]|[%type:Int32.t]->[%exprCConv.Encode.int32]|[%type:int64]|[%type:Int64.t]->[%exprCConv.Encode.int64]|[%type:nativeint]|[%type:Nativeint.t]->[%exprCConv.Encode.nativeint]|[%type:[%t?typ]array]->[%exprCConv.Encode.(array[%eencode_of_typtyp])]|[%type:[%t?typ]option]->[%exprCConv.Encode.(option[%eencode_of_typtyp])]|{ptyp_desc=Ptyp_constr({txt=lid},args)}->beginmatchself,lidwith|Some(name,used),Lidentlinamewhenliname=name->(* typ is actually a recursive reference to the type
being defined. Use a "self" variables that will be bound
with [CConv.Encode.record_fix] or [CConv.Encode.sum_fix] *)used:=true;AC.evar"self"|_->AC.app(AH.Exp.ident(mknoloc(Ppx_deriving.mangle_lidencode_prefixlid)))(List.mapencode_of_typargs)end|{ptyp_desc=Ptyp_tupletyps}->(* encode tuple, by destructuring it *)[%exprCConv.Encode.tuple{CConv.Encode.tuple_emit=funinto[%pAC.ptuple(List.mapi(funi_->AC.pvar(argni))typs)]->[%efold_right_i(funitypacc->[%expr[%eencode_of_typtyp].CConv.Encode.emitinto[%eAC.evar(argni)]::[%eacc]])typs[%expr[]]]}]|{ptyp_desc=Ptyp_variant(fields,_,_);ptyp_loc}->raise_errorf~loc:ptyp_loc"%s cannot be derived for poly variants"deriver|{ptyp_desc=Ptyp_varname}->[%expr([%eAC.evar("poly_"^name)]:'aCConv.Encode.encoder)]|{ptyp_desc=Ptyp_alias(typ,name)}->encode_of_typtyp|{ptyp_loc}->raise_errorf~loc:ptyp_loc"%s cannot be derived for %s"deriver(Ppx_deriving.string_of_core_typetyp)inencode_of_typtyp(* make an encoder from a type declaration *)letencode_of_type~options~path({ptype_loc=loc}astype_decl)=letencoder=matchtype_decl.ptype_kind,type_decl.ptype_manifestwith|Ptype_abstract,Somemanifest->encode_of_typ~self:Nonemanifest|Ptype_variantconstrs,_whencontains_record_variantconstrs->raise_errorf~loc"%s cannot be derived for record variants"deriver|Ptype_variantconstrs,_->letself_used=reffalseinletself=Some(type_decl.ptype_name.txt,self_used)in(* pattern matching *)letcases=List.map(fun{pcd_name={txt=name'};pcd_args;pcd_attributes}->letpcd_args=extract_pcd_args_tuple_values~locpcd_argsin(* first, encode arguments *)letargs=fold_right_i(funitypacc->letencoder=encode_of_typ~selftypin[%expr[%eencoder].CConv.Encode.emitinto[%eAC.evar(argni)]::[%eacc]])pcd_args[%expr[]]in(* result is name,arguments *)letresult=AC.tuple[AC.strname';args]in(* the pattern case itself *)AH.Exp.case(AC.pconstrname'(List.mapi(funi_->AC.pvar(argni))pcd_args))result)constrsinletf=AH.Exp.function_casesinletf=[%expr{CConv.Encode.sum_emit=funinto->[%ef]}]inif!self_usedthen[%exprCConv.Encode.sum_fix(funself->[%ef])]else[%exprCConv.Encode.sum[%ef]]|Ptype_recordlabels,_->letself_used=reffalseinletself=Some(type_decl.ptype_name.txt,self_used)in(* build the function record->hlist (here, its body). The record
is named "r". *)letdestruct=fold_right_i(funifieldtail->ifattr_ignorefield.pld_attributesthentail(* do not encode *)elseletencoder=encode_of_typ~selffield.pld_typeinletfield_name=attr_keyfield.pld_name.txtfield.pld_attributesin[%expr([%eAC.strfield_name],[%eencoder].CConv.Encode.emitinto[%eAH.Exp.field[%exprr](AC.lidfield.pld_name.txt)])::[%etail]])labels[%expr[]]inletdestruct=[%expr{CConv.Encode.record_emit=funintor->[%edestruct]}]inif!self_usedthen[%exprCConv.Encode.record_fix(funself->[%edestruct])]else[%exprCConv.Encode.record[%edestruct]]|Ptype_abstract,None->raise_errorf~loc"%s cannot be derived for fully abstract types"deriver|Ptype_open,_->raise_errorf~loc"%s cannot be derived for open types"deriverinletpolymorphize=Ppx_deriving.poly_fun_of_type_decltype_declin[AH.Vb.mk(AC.pvar(Ppx_deriving.mangle_type_declencode_prefixtype_decl))(polymorphize[%expr([%eencoder]:_CConv.Encode.encoder)])](* signature of the generated encoder *)letencode_sig_of_type~options~pathtype_decl=lettyp=Ppx_deriving.core_type_of_type_decltype_declinletpolymorphize_enc=Ppx_deriving.poly_arrow_of_type_decl(funvar->[%type:[%tvar]CConv.Encode.encoder])type_declin[AH.Sig.value(AH.Val.mk(mknoloc(Ppx_deriving.mangle_type_declencode_prefixtype_decl))(polymorphize_enc[%type:[%ttyp]CConv.Encode.encoder]))](* generate a [typ CConv.Decode.decoder] for the given [typ].
@param self an option contains the type being defined, and a reference
indicating whether a self-reference was used *)letdecode_of_typ~selftyp=letrecdecode_of_typtyp=matchattr_decodertyp.ptyp_attributeswith|None->decode_of_typ_rectyp|Somed->danddecode_of_typ_rectyp=matchtypwith|[%type:unit]->[%exprCConv.Decode.unit]|[%type:int]->[%exprCConv.Decode.int]|[%type:float]->[%exprCConv.Decode.float]|[%type:bool]->[%exprCConv.Decode.bool]|[%type:string]->[%exprCConv.Decode.string]|[%type:bytes]->[%exprCConv.Decode.(mapBytes.to_stringstring)]|[%type:char]->[%exprCConv.Decode.char]|[%type:[%t?typ]ref]->[%exprCConv.Decode.(map(!)[%edecode_of_typtyp])]|[%type:[%t?typ]list]->[%exprCConv.Decode.(list[%edecode_of_typtyp])]|[%type:int32]|[%type:Int32.t]->[%exprCConv.Decode.int32]|[%type:int64]|[%type:Int64.t]->[%exprCConv.Decode.int64]|[%type:nativeint]|[%type:Nativeint.t]->[%exprCConv.Decode.nativeint]|[%type:[%t?typ]array]->[%exprCConv.Decode.(array[%edecode_of_typtyp])]|[%type:[%t?typ]option]->[%exprCConv.Decode.(option[%edecode_of_typtyp])]|{ptyp_desc=Ptyp_constr({txt=lid},args)}->beginmatchself,lidwith|Some(name,used),Lidentlinamewhenliname=name->(* typ is actually a recursive reference to the type
being defined. Use a "self" variables that will be bound
with [CConv.Decode.record_fix] or [CConv.Decode.sum_fix] *)used:=true;AC.evar"self"|_->AC.app(AH.Exp.ident(mknoloc(Ppx_deriving.mangle_liddecode_prefixlid)))(List.mapdecode_of_typargs)end|{ptyp_desc=Ptyp_tupletyps}->(* decode tuple, matching on the list *)[%exprCConv.Decode.(tuple{tuple_accept=funsrcargs->matchargswith|[%p(* didn't find how to build pattern [v1; v2; ...; vn] *)fold_right_i(funitypat->[%pat?[%pAC.pvar(argni)]::[%ppat]])typs[%pat?[]]]->[%eAC.tuple(List.mapi(funity->[%exprCConv.Decode.applysrc[%edecode_of_typty][%eAC.evar(argni)]])typs)]|_->CConv.report_error"expected %d-ary tuple"[%eAC.int(List.lengthtyps)]})]|{ptyp_desc=Ptyp_variant(fields,_,_);ptyp_loc}->raise_errorf~loc:ptyp_loc"%s cannot be derived for poly variants"deriver|{ptyp_desc=Ptyp_varname}->[%expr([%eAC.evar("poly_"^name)]:'aCConv.Decode.decoder)]|{ptyp_desc=Ptyp_alias(typ,name)}->decode_of_typtyp|{ptyp_loc}->raise_errorf~loc:ptyp_loc"%s cannot be derived for %s"deriver(Ppx_deriving.string_of_core_typetyp)indecode_of_typtyp(* make an decoder from a type declaration *)letdecode_of_type~options~path({ptype_loc=loc}astype_decl)=letdecoder=matchtype_decl.ptype_kind,type_decl.ptype_manifestwith|Ptype_abstract,Somemanifest->decode_of_typ~self:Nonemanifest|Ptype_variantconstrs,_whencontains_record_variantconstrs->raise_errorf~loc"%s cannot be derived for record variants"deriver|Ptype_variantconstrs,_->letself_used=reffalseinletself=Some(type_decl.ptype_name.txt,self_used)in(* generate pattern matching cases *)letcases=List.map(fun{pcd_name={txt=name'};pcd_args;pcd_attributes}->letpcd_args=extract_pcd_args_tuple_values~locpcd_argsinAH.Exp.case[%pat?([%pAC.pstrname'],[%pAC.plist(List.mapi(funity->AC.pvar(argni))pcd_args)])](AC.constrname'(List.mapi(funity->letdecoder=matchattr_decoderpcd_attributeswith|None->decode_of_typ~selfty|Somed->din[%exprCConv.Decode.applysrc[%edecoder][%eAC.evar(argni)]])pcd_args)))constrsandlast_case=AH.Exp.case(AH.Pat.any())[%exprCConv.report_error"expected sum"]inletsum_decoder=[%expr{CConv.Decode.sum_accept=funsrcnameargs->[%eAH.Exp.match_[%expr(name,args)](cases@[last_case])]}]inif!self_usedthen[%exprCConv.Decode.sum_fix(funself->[%esum_decoder])]else[%exprCConv.Decode.sum[%esum_decoder]]|Ptype_recordlabels,_->letself_used=reffalseinletself=Some(type_decl.ptype_name.txt,self_used)in(* build a list of
let field = record_get "field" (decode field) src args in ... *)letbindings=fold_right_i(funifieldtail->letdecoder=matchattr_decoderfield.pld_attributeswith|None->decode_of_typ~selffield.pld_type|Somed->dinletfield_name=attr_keyfield.pld_name.txtfield.pld_attributesinletbody_expr=matchattr_defaultfield.pld_attributeswith|Somedefault->[%exprmatchCConv.Decode.record_get_opt[%eAC.strfield_name][%edecoder]srcargswith|Somev->v|None->[%edefault]]|None->[%exprCConv.Decode.record_get[%eAC.strfield_name][%edecoder]srcargs]in[%exprlet[%pAC.pvarfield.pld_name.txt]=[%ebody_expr]in[%etail]])labels(AC.record(* build the record *)(List.map(funfield->letname=field.pld_name.txtinname,AC.evarname)labels))inletrecord_decoder=[%expr{CConv.Decode.record_accept=funsrcargs->[%ebindings]}]inif!self_usedthen[%exprCConv.Decode.record_fix(funself->[%erecord_decoder])]else[%exprCConv.Decode.record[%erecord_decoder]]|Ptype_abstract,None->raise_errorf~loc"%s cannot be derived for fully abstract types"deriver|Ptype_open,_->raise_errorf~loc"%s cannot be derived for open types"deriverinletpolymorphize=Ppx_deriving.poly_fun_of_type_decltype_declin[AH.Vb.mk(AC.pvar(Ppx_deriving.mangle_type_decldecode_prefixtype_decl))(polymorphize[%expr([%edecoder]:_CConv.Decode.decoder)])](* signature of the generated encoder *)letdecode_sig_of_type~options~pathtype_decl=lettyp=Ppx_deriving.core_type_of_type_decltype_declinletpolymorphize_enc=Ppx_deriving.poly_arrow_of_type_decl(funvar->[%type:[%tvar]CConv.Decode.decoder])type_declin[AH.Sig.value(AH.Val.mk(mknoloc(Ppx_deriving.mangle_type_decldecode_prefixtype_decl))(polymorphize_enc[%type:[%ttyp]CConv.Decode.decoder]))]letstr_of_type~options~pathtype_decl=encode_of_type~options~pathtype_decl@decode_of_type~options~pathtype_declletsig_of_type~options~pathtype_decl=encode_sig_of_type~options~pathtype_decl@decode_sig_of_type~options~pathtype_decllet()=letopenPpx_derivinginregister(create"cconv"~type_decl_str:(fun~options~pathtype_decls->letrecu=ifList.lengthtype_decls>1thenRecursiveelseNonrecursivein[AH.Str.valuerecu(List.concat(List.map(str_of_type~options~path)type_decls))])~type_decl_sig:(fun~options~pathtype_decls->List.concat(List.map(sig_of_type~options~path)type_decls))());register(create"encode"~core_type:(encode_of_typ~self:None)~type_decl_str:(fun~options~pathtype_decls->letrecu=ifList.lengthtype_decls>1thenRecursiveelseNonrecursivein[AH.Str.valuerecu(List.concat(List.map(encode_of_type~options~path)type_decls))])~type_decl_sig:(fun~options~pathtype_decls->List.concat(List.map(encode_sig_of_type~options~path)type_decls))());register(create"decode"~core_type:(funtyp->(decode_of_typ~self:Nonetyp))~type_decl_str:(fun~options~pathtype_decls->letrecu=ifList.lengthtype_decls>1thenRecursiveelseNonrecursivein[AH.Str.valuerecu(List.concat(List.map(decode_of_type~options~path)type_decls))])~type_decl_sig:(fun~options~pathtype_decls->List.concat(List.map(decode_sig_of_type~options~path)type_decls))());()