123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558openBaseopenPpxlibopenAst_builder.Defaultletdefault=Attribute.declare"python.default"Attribute.Context.label_declarationAst_pattern.(pstr(pstr_eval__nil^::nil))(funx->x);;letoption=Attribute.declare"python.option"Attribute.Context.label_declarationAst_pattern.(pstrnil)(funx->x);;letdisallow_extra_fields=Attribute.declare"python.disallow_extra_fields"Attribute.Context.type_declarationAst_pattern.(pstrnil)();;letlident~locstr=Loc.make~loc(Lidentstr)letfresh_label=letcounter=ref0infun~loc->Int.incrcounter;letlabel=Printf.sprintf"_lbl_%d"!counterinppat_var(Loc.make~loclabel)~loc,pexp_ident(lident~loclabel)~loc;;letraise_errorf~locfmt=Location.raise_errorf~loc(Stdlib.(^^)"ppx_python: "fmt)(* Generated function names. *)letpython_oftname="python_of_"^tnameletof_pythontname=tname^"_of_python"(* For parameterized types, use these function names as arguments. *)letpython_of_argtname="__python_of_"^tnameletof_python_argtname="__"^tname^"_of_python"letapp_list~loc(func:expression)(args:expressionlist)=[%expr[%efunc][%eelist~locargs]];;letcurry_app_list~loc(func:expression)(args:expressionlist)=List.fold_leftargs~init:func~f:(funaccarg->[%expr[%eacc][%earg]]);;letfun_multi~loc(args:labellist)(body:expression)=List.fold_rightargs~init:body~f:(funargacc->pexp_funNolabel~locNone(ppat_var(Loc.make~locarg)~loc)acc);;letclosure_of_fn(fn:expression->expression)~loc:expression=letloc={locwithloc_ghost=true}inletarg_pat,arg_expr=fresh_label~locinpexp_funNolabel~locNonearg_pat(fnarg_expr);;moduleSignature:sigvalgen:[`to_|`of_|`both]->(signature,rec_flag*type_declarationlist)Deriving.Generator.tend=structletof_td~kindtd:signature_itemlist=let{Location.loc;txt=tname}=td.ptype_nameinletto_python_type=List.fold_left(List.revtd.ptype_params)~init:[%type:[%tPpxlib.core_type_of_type_declarationtd]->Pytypes.pyobject]~f:(funacc(tvar,_variance)->[%type:([%ttvar]->Pytypes.pyobject)->[%tacc]])inletof_python_type=List.fold_left(List.revtd.ptype_params)~init:[%type:Pytypes.pyobject->[%tPpxlib.core_type_of_type_declarationtd]]~f:(funacc(tvar,_variance)->[%type:(Pytypes.pyobject->[%ttvar])->[%tacc]])inletpsig_value~name~type_=psig_value~loc(value_description~loc~name:(Loc.makename~loc)~type_~prim:[])inmatchkindwith|`both->[psig_value~name:(python_oftname)~type_:to_python_type;psig_value~name:(of_pythontname)~type_:of_python_type]|`to_->[psig_value~name:(python_oftname)~type_:to_python_type]|`of_->[psig_value~name:(of_pythontname)~type_:of_python_type];;letgenkind=Deriving.Generator.make_noarg(fun~loc:_~path:_(_rec_flag,tds)->List.concat_maptds~f:(of_td~kind));;endmoduleStructure:sigvalof_python_ty:core_type->expression->expressionvalto_python_ty:core_type->expression->expressionvalgen:[`to_|`of_|`both]->(structure,rec_flag*type_declarationlist)Deriving.Generator.tend=structletchange_lidloc_suffix~flid=Located.map(function|Lidentstr->Lident(fstr)|Ldot(m,str)->Ldot(m,fstr)|Lapply_->raise_errorf~loc:lid.loc"lapply not supported")lid;;letrechandle_core_type~tuple~var~constr~polymorphic_variantctv=letloc={ct.ptyp_locwithloc_ghost=true}inmatchct.ptyp_descwith|Ptyp_tuplecore_types->tuple~loccore_typesv|Ptyp_vartv->[%expr[%epexp_ident~loc(lident(vartv)~loc)][%ev]]|Ptyp_constr(longident_loc,args)->letlid_loc=change_lidloc_suffix~f:constrlongident_locinletargs=List.mapargs~f:(funarg->letarg_fn=handle_core_type~tuple~var~constr~polymorphic_variantarginclosure_of_fn~locarg_fn)@[v]incurry_app_list(pexp_identlid_loc~loc)args~loc|Ptyp_alias(alias,_)->handle_core_type~tuple~var~constr~polymorphic_variantaliasv|Ptyp_variant(row_fields,Closed,None)->polymorphic_variantrow_fields~locv|Ptyp_variant(_,_,_)->raise_errorf~loc"'%a' not supported, only closed variants with no labels are supported"Pprintast.core_typect|_->raise_errorf~loc"'%a' not supported"Pprintast.core_typect;;letrecof_python_tycore_typev=handle_core_type~tuple:(of_python_tuple~wrap:Fn.id)~var:of_python_arg~constr:of_python~polymorphic_variant:of_python_polymorphic_variantcore_typevandof_python_tuple~wrap~loccore_typesv=letlist=List.mapicore_types~f:(funicore_type->[%exprlett=Py.Tuple.get_item[%ev][%eeinti~loc]in[%eof_python_tycore_type[%exprt]]])inlettuple_len=eint(List.lengthcore_types)~locin[%exprifnot(Py.Tuple.check[%ev])thenPrintf.sprintf"not a python tuple %s"(Py.Object.to_string[%ev])|>failwith;letp_len=Py.Tuple.size[%ev]inifp_len<>[%etuple_len]thenPrintf.sprintf"tuple size mismatch %d <> %d"[%etuple_len]p_len|>failwith;[%ewrap(pexp_tuple~loclist)]]andof_python_polymorphic_variantrow_fields~locv=letmatch_cases~args=List.maprow_fields~f:(fun{prf_desc;prf_loc=loc;prf_attributes=_}->matchprf_descwith|Rinherit_->raise_errorf~loc"inherited polymorphic variant not supported"|Rtag(label,has_constant_constructor,ctors)->letrhsargs=pexp_variant~loclabel.txtargsinletrhs=matchctors,has_constant_constructorwith|[],_->rhsNone|[core_type],false->rhs(Some(of_python_tycore_typeargs))|[_],true->raise_errorf~loc"cannot have both a constant and non-constant constructor"|_,_->raise_errorf~loc"multiple constructors are not supported"incase~lhs:(ppat_constant~loc(Pconst_string(label.txt,loc,None)))~guard:None~rhs)@[case~lhs:[%pat?cstor]~guard:None~rhs:[%exprfailwith(Printf.sprintf"unexpected constructor %s"cstor)]]in[%exprifnot(Py.Tuple.check[%ev])thenPrintf.sprintf"not a python tuple %s"(Py.Object.to_string[%ev])|>failwith;letp_len=Py.Tuple.size[%ev]inifp_len<>2thenPrintf.sprintf"not a python pair %s"(Py.Object.to_string[%ev])|>failwith;letcstor,_args=Py.Tuple.to_pair[%ev]inletcstor=Py.String.to_stringcstorin[%epexp_match~loc[%exprcstor](match_cases~args:[%expr_args])]];;letof_python_fieldsfields~wrap~loc~allow_extra_fieldsv=letrecord_fields=List.mapfields~f:(funfield->letname_as_string=estring~locfield.pld_name.txtinletdefault_branch=matchAttribute.getdefaultfieldwith|Somedefault->default|None->(matchAttribute.getoptionfieldwith|Some_->[%exprNone]|None->[%exprPrintf.sprintf"cannot find field %s in dict"[%ename_as_string]|>failwith])inletexpr=[%exprmatchPpx_python_runtime.Dict_str_keys.find[%ev][%ename_as_string]with|exception(Stdlib.Not_found|Not_found_s_)->[%edefault_branch]|v->__pyocaml_field_read:=!__pyocaml_field_read+1;[%eof_python_tyfield.pld_type[%exprv]]]inlidentfield.pld_name.txt~loc,expr)inletcheck_extra_fields=ifallow_extra_fieldsthen[%expr()]else((* The [fail_on_extra_fields] bit is slow but this is ok as it's only used
when an error is generated so outside of the path that we're optimizing
for. *)letfield_names=List.mapfields~f:(funfield->estring~locfield.pld_name.txt)|>elist~locin[%exprif!__pyocaml_field_read<>Py.Dict.size[%ev]thenPpx_python_runtime.Dict_str_keys.fail_on_extra_fields[%ev]~expected_field_names:[%efield_names]])in[%exprifnot(Py.Dict.check[%ev])thenPrintf.sprintf"not a python dict %s"(Py.Object.to_string[%ev])|>failwith;let__pyocaml_field_read=ref0inlet__pyocaml_res=[%ewrap(pexp_recordrecord_fields~locNone)]in[%echeck_extra_fields];__pyocaml_res];;letof_python_variantvariant~loc~allow_extra_fieldsv=letmatch_cases~args=List.mapvariant~f:(funvariant->letrhsargs=pexp_construct~loc(lident~locvariant.pcd_name.txt)argsinletrhs=matchvariant.pcd_argswith|Pcstr_tuple[]->rhsNone|Pcstr_tuplecore_types->of_python_tuplecore_typesargs~loc~wrap:(funv->rhs(Somev))|Pcstr_recordfields->of_python_fieldsfields~locargs~wrap:(funrecord->rhs(Somerecord))~allow_extra_fieldsincase~lhs:(ppat_constant~loc(Pconst_string(variant.pcd_name.txt,loc,None)))~guard:None~rhs)@[case~lhs:[%pat?cstor]~guard:None~rhs:[%exprfailwith(Printf.sprintf"unexpected constructor %s"cstor)]]in[%exprifnot(Py.Tuple.check[%ev])thenPrintf.sprintf"not a python tuple %s"(Py.Object.to_string[%ev])|>failwith;letp_len=Py.Tuple.size[%ev]inifp_len<>2thenPrintf.sprintf"not a python pair %s"(Py.Object.to_string[%ev])|>failwith;letcstor,_args=Py.Tuple.to_pair[%ev]inletcstor=Py.String.to_stringcstorin[%epexp_match~loc[%exprcstor](match_cases~args:[%expr_args])]];;letrecto_python_tycore_typev=lettuple~loccore_typesv=letpat,expr=to_python_tuple~loccore_typesinpexp_let~locNonrecursive[value_binding~loc~pat~expr:v]exprinhandle_core_type~tuple~var:python_of_arg~constr:python_of~polymorphic_variant:to_polymorphic_variantcore_typevandto_python_tuple~loccore_types=letvar_namei="t"^Int.to_stringiinletpat=List.mapicore_types~f:(funi_->ppat_var~loc(Loc.make(var_namei)~loc))|>ppat_tuple~locinletlist=List.mapicore_types~f:(funicore_type->to_python_tycore_type(pexp_ident(lident(var_namei)~loc)~loc))inpat,app_list[%exprPy.Tuple.of_list]~loclistandto_polymorphic_variantrow_fields~locv=letmatch_cases=List.maprow_fields~f:(fun{prf_desc;prf_loc=loc;prf_attributes=_}->matchprf_descwith|Rinherit_->raise_errorf~loc"inherited polymorphic variant not supported"|Rtag(label,has_constant_constructor,ctors)->letconstructor=estring~loclabel.txtinletargs_lhs,args_rhs=matchctors,has_constant_constructorwith|[],_->None,[%exprPy.none]|[core_type],false->Some[%pat?t],to_python_tycore_type[%exprt]|[_],true->raise_errorf~loc"cannot have both a constant and non-constant constructor"|_,_->raise_errorf~loc"multiple constructors are not supported"incase~lhs:(ppat_variant~loclabel.txtargs_lhs)~guard:None~rhs:[%exprPy.Tuple.of_pair(Py.String.of_string[%econstructor],[%eargs_rhs])])inpexp_match~locvmatch_cases;;letto_python_fieldsfields~locv=letmandatory_fields,optional_fields=List.partition_tffields~f:(funfield->Attribute.getoptionfield|>Option.is_none)inletmandatory_fields=List.mapmandatory_fields~f:(funfield->letname_as_string=estring~locfield.pld_name.txtinletvalue=pexp_fieldv(lident~locfield.pld_name.txt)~locin[%expr[%ename_as_string],[%eto_python_tyfield.pld_typevalue]])inletmandatory_dict=app_list~loc[%exprPpx_python_runtime.Dict_str_keys.create]mandatory_fieldsinifList.is_emptyoptional_fieldsthenmandatory_dictelse(letoptional_setters=List.mapoptional_fields~f:(funfield->letname_as_string=estring~locfield.pld_name.txtinletvalue=pexp_fieldv(lident~locfield.pld_name.txt)~locinletpat_ident=lident~loc"pat_value"|>pexp_ident~locin[%exprmatch[%evalue]with|None->()|Some_aspat_value->Ppx_python_runtime.Dict_str_keys.setdict[%ename_as_string][%eto_python_tyfield.pld_typepat_ident]])in[%exprletdict=[%emandatory_dict]in[%eesequence~locoptional_setters];dict]);;letto_python_variantvariant~locv=letmatch_cases=List.mapvariant~f:(funvariant->letconstructor=estring~locvariant.pcd_name.txtinletargs_lhs,args_rhs=matchvariant.pcd_argswith|Pcstr_tuple[]->None,[%exprPy.none]|Pcstr_tuplecore_types->letpat,expr=to_python_tuple~loccore_typesinSomepat,expr|Pcstr_recordfields->Some[%pat?t],to_python_fieldsfields~loc[%exprt]incase~lhs:(ppat_construct~loc(lident~locvariant.pcd_name.txt)args_lhs)~guard:None~rhs:[%exprPy.Tuple.of_pair(Py.String.of_string[%econstructor],[%eargs_rhs])])inpexp_match~locvmatch_cases;;letexpr_of_td~tvar_wrapper~type_expr~variant~recordtd=let{Location.loc;txt=_}=td.ptype_nameinlettvars=List.maptd.ptype_params~f:(fun(te,_variance)->matchte.ptyp_descwith|Ptyp_varlbl->tvar_wrapperlbl|_->(* we've called [name_type_params_in_td] *)assertfalse)inletexprarg_t=matchtd.ptype_kindwith|Ptype_abstract->(matchtd.ptype_manifestwith|None->raise_errorf~loc"abstract types not yet supported"|Somety->type_exprtyarg_t)|Ptype_variantcstrs->variantcstrs~locarg_t|Ptype_recordfields->recordfields~locarg_t|Ptype_open->raise_errorf~loc"open types not yet supported"infun_multi~loctvars(closure_of_fnexpr~loc);;letgenkind=letattributes=matchkindwith|`both|`of_->[Attribute.Tdefault;Attribute.Toption;Attribute.Tdisallow_extra_fields]|`to_->[]inDeriving.Generator.make_noarg~attributes(fun~loc~path:_(rec_flag,tds)->lettds=List.maptds~f:name_type_params_in_tdinletof_python_bindings()=List.maptds~f:(funtd->letpat=let{Location.loc;txt=tname}=td.ptype_nameinletname=of_pythontnameinppat_var~loc(Loc.makename~loc)inletexpr=letallow_extra_fields=Option.is_none(Attribute.getdisallow_extra_fieldstd)inexpr_of_td~tvar_wrapper:of_python_arg~type_expr:of_python_ty~variant:(of_python_variant~allow_extra_fields)~record:(of_python_fields~wrap:Fn.id~allow_extra_fields)tdinvalue_binding~loc~pat~expr)inletto_python_bindings()=List.maptds~f:(funtd->letpat=let{Location.loc;txt=tname}=td.ptype_nameinletname=python_oftnameinppat_var~loc(Loc.makename~loc)inletexpr=expr_of_td~tvar_wrapper:python_of_arg~type_expr:to_python_ty~variant:to_python_variant~record:to_python_fieldstdinvalue_binding~loc~pat~expr)inletbindings=matchkindwith|`both->to_python_bindings()@of_python_bindings()|`to_->to_python_bindings()|`of_->of_python_bindings()in[pstr_value~loc(really_recursiverec_flagtds)bindings]);;endletpython=Deriving.add"python"~str_type_decl:(Structure.gen`both)~sig_type_decl:(Signature.gen`both);;modulePython_of=structletname="python_of"letextension~loc~path:_ctyp=closure_of_fn(Structure.to_python_tyctyp)~locletderiver=Deriving.addname~str_type_decl:(Structure.gen`to_)~sig_type_decl:(Signature.gen`to_)~extension;;endmoduleOf_python=structletname="of_python"letextension~loc~path:_ctyp=closure_of_fn(Structure.of_python_tyctyp)~locletderiver=Deriving.addname~str_type_decl:(Structure.gen`of_)~sig_type_decl:(Signature.gen`of_)~extension;;end(* [py_string_expressions] maps from the string literal to the expression binding *)letpy_string_expressions=Hashtbl.create(moduleString)letexpand~expr_loc~string_loc~string=letloc={string_locwithloc_ghost=true}inletexpr_var,_expr=Hashtbl.find_or_addpy_string_expressionsstring~default:(fun()->letexpr=[%exprlazy(Py.String.of_string[%eestringstring~loc])]inletlen=Hashtbl.lengthpy_string_expressionsinletexpr_var=Printf.sprintf"py_string_%d"leninexpr_var,expr)in[%exprLazy.force[%eevarexpr_var~loc:expr_loc]];;let()=Ppxlib.Driver.register_transformation"ppx_python_conv"~rules:[Context_free.Rule.extension(Extension.declare"ppx_python_conv.py_string"Extension.Context.expressionAst_pattern.(pstr(pstr_eval(pexp_constant(pconst_string____drop))nil^::nil))(* [delimiter] can be things like "\n". This comes up if we use a multi-line
string. *)(fun~loc:expr_loc~path:_stringstring_loc->Merlin_helpers.hide_expression(expand~expr_loc~string_loc~string)))]~impl:(funstructure->letloc=Location.noneinletheader=Hashtbl.datapy_string_expressions|>List.map~f:(fun(key,value)->[%strilet[%ppvarkey~loc]=[%evalue]])inHashtbl.clearpy_string_expressions;header@structure);;