123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150(*
* Generic transformers: plugins.
* Copyright (C) 2016-2023
* Dmitrii Kosarev aka Kakadu
* St.Petersburg State University, JetBrains Research
*)(** {i Stateful} plugin: functors + inherited value
to make decisions about how to map values.
Behave the same as {!Eval} trait but can may return modified state.
Inherited attributes' type (both default and for type parameters) is ['env].
Synthetized attributes' type (both default and for type parameters) is ['env * _ t].
For type declaration [type ('a,'b,...) typ = ...] it will create transformation
function with type
[('env -> 'a -> 'env * 'a2) ->
('env -> 'b -> 'env * 'b2) -> ... ->
'env -> ('a,'b,...) typ -> 'env * ('a2, 'b2, ...) typ ] *)openPpxlibopenStdppxopenPrintfopenGTCommonopenHelpersBaselettrait_name="stateful"moduleMake(AstHelpers:GTHELPERS_sig.S)=structmoduleG=Gmap.Make(AstHelpers)moduleP=Plugin.Make(AstHelpers)lettrait_name=trait_nameopenAstHelpersclassginitial_argstdecls=object(self:'self)(* TODO: maybe do not inherit from gmap a.k.a. functor *)inheritG.ginitial_argstdeclsassuperinheritP.with_inherited_attrinitial_argstdeclsmethodtrait_name=trait_namemethod!inh_of_main~loc_tdecl=Typ.var~loc"env"method!syn_of_param~locs=Typ.tuple~loc[Typ.var~loc"env";Typ.var~loc@@Gmap.param_name_manglers]methodinh_of_param~loctdecl_name=Typ.var~loc"env"method!syn_of_main~loc?in_classtdecl=letin_class=matchin_classwith|None->false|Someb->binTyp.tuple~loc[self#inh_of_main~loctdecl;super#syn_of_main~loc~in_classtdecl]methodplugin_class_params~loctyps~typname=super#plugin_class_params~loctyps~typname@[Typ.var~loc"env"]methodon_tuple_constr~loc~is_self_rec~mutual_decls~inhetdeclconstr_infots=letc=matchconstr_infowith|Some(`Normals)->Exp.construct~loc(lidents)|Some(`Polys)->Exp.variant~locs|None->assert(List.lengthts>=2);Exp.tuple~locinmatchtswith|[]->Exp.tuple~loc[inhe;c[]]|ts->letres_var_name=sprintf"%s_rez"inletys=List.mapi~f:(funnx->n,x)tsinList.fold_rightys~init:(Exp.tuple~loc[Exp.sprintf~loc"env%d"(List.lengthys);c@@List.mapts~f:(fun(n,t)->Exp.ident~loc@@res_var_namen)])~f:(fun(i,(name,typ))acc->Exp.let_one~loc(Pat.tuple~loc[Pat.sprintf~loc"env%d"(i+1);Pat.sprintf~loc"%s"@@res_var_namename])(self#app_transformation_expr~loc(self#do_typ_gen~loc~is_self_rec~mutual_declstdecltyp)(ifi=0theninheelseExp.sprintf~loc"env%d"i)(Exp.ident~locname))acc)method!on_record_declaration~loc~is_self_rec~mutual_declstdecllabs=(* TODO: *)lettempvals=List.map~f:(fun_->gen_symbol~prefix:"lab"())labsinletpat=Pat.record~loc@@List.maplabs~f:(funl->Lidentl.pld_name.txt,Pat.var~locl.pld_name.txt)inletenv_top=gen_symbol~prefix:"env"()inleteenv=Exp.ident~locenv_topinletpenv=Pat.sprintf~loc"%s"env_topinletmethname=sprintf"do_%s"tdecl.ptype_name.txtin[Cf.method_concrete~locmethname@@Exp.fun_~locpenv@@Exp.fun_~locpat@@List.fold_right2labstempvals~f:(fun{pld_name;pld_type}tvalacc->Exp.let_one~locPat.(tuple~loc[penv;var~loctval])(self#app_transformation_expr~loc(self#do_typ_gen~loc~is_self_rec~mutual_declstdeclpld_type)eenv(Exp.ident~locpld_name.txt))acc)~init:(Exp.tuple~loc[eenv;Exp.record~loc(List.map2~f:(fun{pld_name}asdf->lidentpld_name.txt,Exp.ident~locasdf)labstempvals)])]endletcreate=(newg:>P.plugin_constructor)endletregister()=Expander.register_plugintrait_name(moduleMake:Plugin_intf.MAKE)let()=register()