1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060(*
* Generic Transformers PPX syntax extension.
* Copyright (C) 2016-2021
* Dmitrii Kosarev aka Kakadu
* St.Petersburg State University, JetBrains Research
*)openBaseopenPpxlibopenPpxlib.Ast_builder.DefaultopenHelpersBaseopenPrintfopenNaminglet(@@)=Caml.(@@)typeconfig_plugin=Skip|UseofPlugin_intf.plugin_argsletregistered_plugins:(string*(modulePlugin_intf.MAKE))listref=ref[]letget_registered_plugins()=List.map~f:fst!registered_pluginsletregister_pluginnamem=letp=(name,m)inregistered_plugins:=p::!registered_plugins;()moduleMake(AstHelpers:GTHELPERS_sig.S)=structopenAstHelpersletprepare_patt_match~loc?else_casewhatconstructorsmake_rhs=leton_algcdts=letkcs=Exp.match_~locwhatcsink@@List.mapcdts~f:(funcd->matchcd.pcd_argswith|Pcstr_recordls->letnames=List.mapls~f:(fun_->gen_symbol())incase~lhs:(Pat.constr_record~loccd.pcd_name.txt@@List.map2_exnlsnames~f:(funls->(l.pld_name.txt,Pat.var~locs)))~rhs:(make_rhscdnames)|Pcstr_tupleargs->letnames=List.mapargs~f:(fun_->gen_symbol())in(* notify "constructing %s of %s" cd.pcd_name.txt (String.concat ~sep:" " names); *)case~lhs:(Pat.constr~loccd.pcd_name.txt@@List.map~f:(Pat.var~loc)names)~rhs:(make_rhscdnames))@(matchelse_casewith|None->[]|Somef->letname=gen_symbol~prefix:"else"()in[case~lhs:(Pat.sprintf~loc"%s"name)~rhs:(fname)])inleton_polycs=assertfalseinmatchconstructorswith|`Algebraiccdts->on_algcdts|`PolyVarcs->on_polycsletprepare_patt_match_poly~locwhatrowslabels~onrow~onlabel~oninherit=letkcs=Exp.match_~locwhatcsinletrs=List.maprows~f:(function|Rtag(lab,_,args)->letargs=matchargswith|[t]->unfold_tuplet|[]->[]|_->failwith"we don't support conjunction types"inletnames=List.mapargs~f:(fun_->gen_symbol~prefix:"_"())inletlhs=Pat.variant~loclab.txt@@List.map~f:(funs->Pat.var~locs)namesincase~lhs~rhs:(onrowlab@@List.zip_exnnamesargs)|Rinherittyp->matchtyp.ptyp_descwith|Ptyp_constr({txt;_},ts)->letnewname="subj"inletlhs=Pat.alias~loc(Pat.type_~loctxt)newnameincase~lhs~rhs:(oninherittstxtnewname)|_->failwith"this inherit field isn't supported")inletls=matchlabelswith|None->[]|Somels->List.mapls~f:(funlab->letnewname="subj"inletlhs=Pat.alias~loc(Pat.type_~loc(Lidentlab))newnameincase~lhs~rhs:(onlabellabnewname))ink@@rs@lsletparams_of_interface_class~locparams=(* actual params depend on sort of type.
2 + 3*params_count + 1 (for polyvar subtyping)
*)(List.concat@@map_type_param_namesparams~f:(funs->[named_type_arg~loc("i"^s);named_type_arg~locs;named_type_arg~loc("s"^s)]))@[named_type_arg~loc"inh";named_type_arg~locNaming.extra_param_name;named_type_arg~loc"syn"]letmake_interface_class_sig~loctdecl=letname=tdecl.ptype_nameinletkfields=[Sig.class_~loc~virt:true~name:(class_name_for_typname.txt)~params:(params_of_interface_class~loctdecl.ptype_params)fields]inleton_constructorcd=letmethname=Naming.meth_name_for_constructorcd.pcd_attributescd.pcd_name.txtinlettyps=matchcd.pcd_argswith|Pcstr_recordls->List.mapls~f:(funx->x.pld_type)|Pcstr_tuplets->tsinCtf.method_~locmethname~virt:true@@Typ.chain_arrow~loc@@[Typ.var~loc"inh";Typ.var~loc"extra"]@(List.maptyps~f:Typ.from_caml)@[Typ.var~loc"syn"]invisit_typedecl~loctdecl~onrecord:(fun_labels->(* almost the same as plugin#get_class_sig*)k[Ctf.method_~loc(Naming.meth_name_for_recordtdecl)~virt:true@@Typ.chain_arrow~loc@@letopenTypin[var~loc"inh";use_tdecltdecl;var~loc"syn"]])~onabstract:(fun()->(* For purely abstract type we can only generate interface
(we don't know methods) *)[])~onvariant:(funcds->k@@List.mapcds~f:on_constructor)~onmanifest:(funtyp->letwrapnameparams=letinh_params=List.concat_mapparams~f:(funtyp->[map_core_typetyp~onvar:(funn->Some(ptyp_var~loc:typ.ptyp_loc("i"^n)));typ;map_core_typetyp~onvar:(funn->Some(ptyp_var~loc:typ.ptyp_loc("s"^n)))])|>List.map~f:Typ.from_camlinletinh_params=inh_params@[Typ.var~loc"inh";Typ.var~locNaming.extra_param_name;Typ.var~loc"syn"]in[Ctf.inherit_~loc@@Cty.constr~loc(map_longident~f:class_name_for_typname)inh_params]inletrechelpertyp=matchtyp.ptyp_descwith|Ptyp_constr({txt;loc},params)->(* a type alias on toplevel *)k@@wraptxtparams|Ptyp_varname->letnew_lident=Ldot(Lident"GT","free")inletopenPpxlib.Ast_builder.Defaultinletloc=typ.ptyp_locinhelper@@ptyp_constr~loc(Located.mk~locnew_lident)[ptyp_var~locname]|Ptyp_tuplets->(* let's say we have predefined aliases for now *)letnew_lident=Ldot(Lident"GT",sprintf"tuple%d"@@List.lengthts)inletopenPpxlib.Ast_builder.Defaultinletloc=typ.ptyp_locinhelper@@ptyp_constr~loc(Located.mk~locnew_lident)ts|Ptyp_alias(typ,new_name)->letloc=typ.ptyp_locinmap_core_typetyp~onvar:(funas_->letparams=List.map~f:fsttdecl.ptype_paramsinletopenPpxlib.Ast_builder.DefaultinifString.equalas_new_namethenSome(ptyp_constr~loc(Located.lident~locname.txt)params)elseSome(ptyp_var~locas_))|>helper|Ptyp_variant(rows,_,labels)->(* rows go to virtual methods. label goes to inherit fields *)letmeths=List.concat_maprows~f:(funrf->matchrf.prf_descwith|Rtag(lab,_,args)->letargs=matchargswith|[]->[]|[{ptyp_desc=Ptyp_tuplets;_}]->ts|[t]->[t]|_->failwith"conjective not supported"inletmethname=Naming.meth_of_constrlab.txtinletts=letopenTypin[var~loc"inh";var~loc"extra"]@(List.map~f:from_camlargs)@[var~loc"syn"]|>chain_arrow~locin[Ctf.method_~loc~virt:truemethnamets]|Rinherittyp->matchtyp.ptyp_descwith|Ptyp_constr({txt;loc},params)->wraptxtparams|_->assertfalse)inkmeths|Ptyp_extension_->not_implemented"extensions in types not implemented: %s"(string_of_core_typetyp)|_->failwith" not implemented"inlettopleveltyp=matchtyp.ptyp_descwith|Ptyp_tuple_|Ptyp_var_->k@@[on_constructor@@Ppxlib.Ast_builder.Default.constructor_declaration~loc:typ.ptyp_loc~name:(Located.mapString.uppercasetdecl.ptype_name)~args:(Pcstr_tuple[])~res:None]|_->helpertypintopleveltyp)letinherit_iface_class~locnameparams=letinh_params=List.concat_mapparams~f:(funtyp->[map_core_typetyp~onvar:(funn->Some(ptyp_var~loc:typ.ptyp_loc("i"^n)));typ;map_core_typetyp~onvar:(funn->Some(ptyp_var~loc:typ.ptyp_loc("s"^n)))])|>List.map~f:Typ.from_camlinletinh_params=inh_params@[Typ.var~loc"inh";Typ.var~loc"extra";Typ.var~loc"syn"]inCf.inherit_~loc@@Cl.constr~loc(map_longident~f:class_name_for_typname)inh_paramsletmake_interface_class~loctdecl=letparams=List.map~f:fsttdecl.ptype_paramsinletname=tdecl.ptype_nameinletans?(is_poly=false)fields=class_declaration~loc~name:(class_name_for_typname.txt)fields~virt:true~params:(params_of_interface_class~loctdecl.ptype_params)inleton_constructorcd=letmethname=Naming.meth_name_for_constructorcd.pcd_attributescd.pcd_name.txtinlettyps=matchcd.pcd_argswith|Pcstr_recordls->List.mapls~f:(funx->x.pld_type)|Pcstr_tuplets->tsinCf.method_virtual~locmethname@@Typ.(List.fold_righttyps~init:(var~loc"syn")~f:(funt->arrow~loc(from_camlt))|>(arrow~loc(var~loc"extra"))|>(arrow~loc(var~loc"inh")))invisit_typedecl~loctdecl~onopen:(fun()->ans[])~onrecord:(fun_->ans[Cf.method_virtual~loc(sprintf"do_%s"tdecl.ptype_name.txt)@@Typ.(arrow~loc(var~loc"inh")@@arrow~loc(use_tdecltdecl)(var~loc"syn"))])~onvariant:(funcds->ans@@List.mapcds~f:on_constructor)~onmanifest:(funtyp->letwrap?(is_poly=false)nameparams=[inherit_iface_class~locnameparams]inletrechelpertyp=matchtypwith|_->matchtyp.ptyp_descwith|Ptyp_varname->letnew_lident=Ldot(Lident"GT","free")inletopenPpxlib.Ast_builder.Defaultinletloc=typ.ptyp_locinhelper@@ptyp_constr~loc(Located.mk~locnew_lident)[ptyp_var~locname]|Ptyp_constr({txt;loc},params)->(* a type alias on toplevel *)ans@@wraptxtparams|Ptyp_tuplets->(* let's say we have predefined aliases for now *)letnew_lident=Ldot(Lident"GT",sprintf"tuple%d"@@List.lengthts)inletopenPpxlib.Ast_builder.Defaultinletloc=typ.ptyp_locinhelper@@ptyp_constr~loc(Located.mk~locnew_lident)ts|Ptyp_alias(typ,new_name)->letloc=typ.ptyp_locinmap_core_typetyp~onvar:(funas_->letopenPpxlib.Ast_builder.DefaultinifString.equalas_new_namethenSome(ptyp_constr~loc(Located.lident~locname.txt)params)elseSome(ptyp_var~locas_))|>helper|Ptyp_variant(rows,_,labels)->(* rows go to virtual methods. label goes to inherit fields *)ans~is_poly:true@@List.concat_maprows~f:(funrf->matchrf.prf_descwith|Rtag(lab,_,[])->letmethname=sprintf"c_%s"lab.txtin[Cf.method_virtual~locmethname@@Typ.(var~loc"syn"|>(arrow~loc@@var~loc"extra")|>arrow~loc(var~loc"inh"))]|Rtag(lab,_,[typ])->(* print_endline "HERE"; *)letargs=matchtyp.ptyp_descwith|Ptyp_tuplets->ts|_->[typ]inletmethname=sprintf"c_%s"lab.txtin[Cf.method_virtual~locmethname@@letopenTypin(List.fold_rightargs~init:(var~loc"syn")~f:(funt->arrow~loc(from_camlt))|>(arrow~loc@@var~loc"extra")|>(arrow~loc(var~loc"inh")))]|Rtag(_,_,_)->failwith"Can't deal with conjunctive types"|Rinherittyp->matchtyp.ptyp_descwith|Ptyp_constr({txt;loc},params)->wrap~is_poly:truetxtparams|_->assertfalse)|Ptyp_extension_->not_implemented"extensions in types `%s`"(string_of_core_typetyp)|_->failwith"not implemented "inlettopleveltyp=matchtyp.ptyp_descwith|Ptyp_tuple_|Ptyp_var_->ans@@[on_constructor@@Ppxlib.Ast_builder.Default.constructor_declaration~loc:typ.ptyp_loc~name:(Located.mapString.uppercasetdecl.ptype_name)~args:(Pcstr_tuple[])~res:None]|_->helpertypintopleveltyp)letwildcard_tdecltd=letloc=loc_from_camltd.ptype_locinTyp.constr~loc(Lidenttd.ptype_name.txt)@@List.maptd.ptype_params~f:(fun_->Typ.any~loc)letmake_gcata_typ~loctdecl=leton_alias_or_abstract()=letargs=map_type_param_namestdecl.ptype_params~f:(funname->[Typ.any~loc;Typ.var~locname;Typ.var~loc@@"s"^name])|>List.concatinletargs=args@[Typ.var~loc"inh";Typ.use_tdecltdecl;Typ.var~loc"syn"]inTyp.class_~loc(Lident(class_name_for_typtdecl.ptype_name.txt))argsinlettr_t=visit_typedecl~loctdecl~onabstract:(fun()->on_alias_or_abstract())~onrecord:(fun_->Typ.object_~locOpen@@[sprintf"do_%s"tdecl.ptype_name.txt,Typ.(chain_arrow~loc[var~loc"inh";use_tdecltdecl;var~loc"syn"])])~onvariant:(funcds->Typ.object_~locOpen@@List.mapcds~f:(funcd->lettyps=matchcd.pcd_argswith|Pcstr_recordls->List.mapls~f:(funx->x.pld_type)|Pcstr_tuplets->tsinletnew_ts=letopenTypin[var~loc"inh";use_tdecltdecl]@(List.maptyps~f:Typ.from_caml)@[Typ.var~loc"syn"]in(Naming.meth_name_for_constructorcd.pcd_attributescd.pcd_name.txt,Typ.chain_arrow~locnew_ts)))~onmanifest:(funt->letrechelpertyp=matchtyp.ptyp_descwith|Ptyp_constr(_,_)->on_alias_or_abstract()|Ptyp_varname->letnew_lident=Ldot(Lident"GT","free")inletopenPpxlib.Ast_builder.Defaultinletloc=typ.ptyp_locinhelper@@ptyp_constr~loc(Located.mk~locnew_lident)[ptyp_var~locname]|Ptyp_variant(rows,_flg,_)->letparams=map_type_param_namestdecl.ptype_params~f:(funs->[Typ.any~loc;Typ.var~locs;Typ.var~loc@@"s"^s])inTyp.class_~loc(Lident(class_name_for_typtdecl.ptype_name.txt))(List.concatparams@Typ.[var~loc"inh";openize_poly~loc@@Typ.constr~loc(Lidenttdecl.ptype_name.txt)@@map_type_param_namestdecl.ptype_params~f:(Typ.var~loc);var~loc"syn"])|Ptyp_tuplets->helper@@constr_of_tuple~loc:t.ptyp_locts|_->failwith"Unsupported case during generate of the type of gcata"inhelpert)inletsubj_t=Typ.use_tdecltdeclinTyp.(chain_arrow~loc[tr_t;var~loc"inh";subj_t;var~loc"syn"])letmake_gcata_sig~loc?(shortname=false)tdecl=letwrap()=lettype_=make_gcata_typ~loctdeclinletname=ifshortnamethen"gcata"elsePrintf.sprintf"gcata_%s"tdecl.ptype_name.txtin[Sig.value~loc~nametype_]invisit_typedecl~loctdecl~onrecord:(fun_->wrap())~onvariant:(fun_->wrap())~onmanifest:(fun_->wrap())~onabstract:(fun()->[])letmake_gcata_str~loctdecl=letgcata_pat=Pat.var~loc(sprintf"gcata_%s"tdecl.ptype_name.txt)inletansk=lettr=letwrapt=ifis_polyvariant_tdecltdeclthenopenize_poly~loctelsetinPat.constraint_~loc(Pat.var~loc"tr")@@Typ.class_~loc(Lident(Naming.class_name_for_typtdecl.ptype_name.txt))(letparam_names=List.mapitdecl.ptype_params~f:(funi_->gen_symbol~prefix:(sprintf"typ%d"i)())inlettyp_self=Typ.constr~loc(Lidenttdecl.ptype_name.txt)@@List.mapparam_names~f:(Typ.var~loc)inList.concat_mapparam_names~f:(funname->Typ.[any~loc;var~locname;any~loc])@[Typ.any~loc;wrap@@typ_self;Typ.any~loc])inStr.single_value~locgcata_pat(Exp.fun_list~locPat.[tr;var~loc"inh";var~loc"subj"]k)inletmatch_and_openize~locidenttype_lident=letnew_name="foo"inExp.match_~locident[case~lhs:(Pat.alias~loc(Pat.type_~loctype_lident)new_name)~rhs:(Exp.ident~locnew_name)]inletonvariantcds=ans@@prepare_patt_match~loc(Exp.ident~loc"subj")(`Algebraiccds)(funcdnames->(* TODO: Subj ident has to be passed as an argument *)letsubj="subj"inList.fold_left("inh"::subj::names)~init:(Exp.send~loc(Exp.ident~loc"tr")(Naming.meth_name_for_constructorcd.pcd_attributescd.pcd_name.txt))~f:(funaccarg->Exp.app~locacc(Exp.ident~locarg)))invisit_typedecl~loctdecl~onopen:(fun()->ans@@Exp.failwith_~loc"Extensible types not yet supported")~onrecord:(fun_labels->letmethname=sprintf"do_%s"tdecl.ptype_name.txtinans@@Exp.(app_list~loc(send~loc(ident~loc"tr")methname)[ident~loc"inh";ident~loc"subj"]))~onmanifest:(funtyp->letrechelpert=matcht.ptyp_descwith|Ptyp_alias(t,_)->helpert|Ptyp_varname->letnew_lident=Ldot(Lident"GT","free")inletopenPpxlib.Ast_builder.Defaultinletloc=typ.ptyp_locinhelper@@ptyp_constr~loc(Located.mk~locnew_lident)[ptyp_var~locname]|Ptyp_constr({txt},_)->Str.single_value~locgcata_pat(Exp.of_longident~loc@@map_longidenttxt~f:Naming.gcata_name_for_typ)|Ptyp_tuplets->(* let's say we have predefined aliases for now *)helper@@constr_of_tuple~loc:t.ptyp_locts|Ptyp_variant(rows,_,maybe_labels)->letsubj_s="subj"inans@@prepare_patt_match_poly~loc(Exp.ident~locsubj_s)(List.maprows~f:(fun{prf_desc}->prf_desc))maybe_labels~onrow:(funcnamenames->List.fold_left~init:(Exp.send~loc(Exp.ident~loc"tr")("c_"^cname.txt))~f:(Exp.app~loc)((Exp.ident~loc"inh")::(match_and_openize~loc(Exp.ident~locsubj_s)(Lidenttdecl.ptype_name.txt))::(List.map~f:(fun(s,_)->Exp.ident~locs)names)))~onlabel:(funlabelpatname->failwith"not implemented")~oninherit:(funparamscidentpatname->Exp.app_list~loc(Exp.of_longident~loc@@map_longidentcident~f:(gcata_name_for_typ))(List.map["tr";"inh";patname]~f:(Exp.sprintf~loc"%s")))|Ptyp_object(_,_)->failwith"not implemented: object types"|Ptyp_class(_,_)->failwith"not implemented: class types"|Ptyp_package_->failwith"not implemented: package types"|Ptyp_extension_->failwith"not implemented: extension types"|Ptyp_arrow_->failwith"not implemented: arrow types"|Ptyp_any->failwith"not implemented: wildcard types (but it should be easy to rewrite)"|Ptyp_poly(_,_)->failwith"not implemented: existential types"inlettoplevelt=matcht.ptyp_descwith|Ptyp_var_|Ptyp_tuple_->ans@@Exp.app_list~loc(Exp.send~loc(Exp.ident~loc"tr")(Naming.meth_of_constr(String.uppercasetdecl.ptype_name.txt)))(List.map~f:(Exp.ident~loc)["inh";"subj"])|_->helpertintopleveltyp)~onvariant(* create opened renaming for polymorphic variant *)(* seems that we don't need it no more *)letmake_heading_gen~locwraptdecl=[]letcollect_plugins_str~loctdeclall_tdeclsplugins:Str.tlist=letwrapptdecl=p#eta_and_exp~center:(Exp.sprintf~loc"%s_%s"p#trait_nametdecl.ptype_name.txt)tdeclinletplugin_fields=List.mapplugins~f:(funp->Cf.method_concrete~locp#trait_name@@ifp#need_inh_attrthenExp.sprintf~loc"%s"@@Naming.trf_functionp#trait_nametdecl.ptype_name.txtelsewrapptdecl)inlettname=tdecl.ptype_name.txtin(* The pack itself *)letgcata_ident=Exp.sprintf~loc"gcata_%s"tnamein(Str.single_value~loc(Pat.sprintf~loc"%s"tname)@@Exp.record~loc[Ldot(lident"GT","gcata"),gcata_ident;Ldot(lident"GT","fix"),ifList.lengthall_tdecls>1thenExp.sprintf~loc"%s"@@Naming.make_fix_nameall_tdeclselseExp.fun_~loc(Pat.var~loc"eta")@@Exp.app_list~loc(Exp.of_longident~loc(Ldot(Lident"GT","transform_gc")))[gcata_ident;Exp.sprintf~loc"eta"];Ldot(lident"GT","plugins"),Exp.object_~loc@@class_structure~self:(Pat.any~loc)~fields:plugin_fields])::(List.filter_mapplugins~f:(funp->(* also we generate transformation function with unit preapplied
Because we seems to need them in case of abstract type in the interface
*)ifp#need_inh_attrthenNoneelseletfname=Naming.trf_functionp#trait_nametdecl.ptype_name.txtinOption.some@@Str.single_value~loc(Pat.sprintf~loc"%s"fname)(wrapptdecl)))letrename_paramstdecl=letloc=tdecl.ptype_locinvisit_typedecl~loctdecl~onmanifest:(funtyp->letnames=(map_type_param_namestdecl.ptype_params~f:id)inlet(r_names,new_manifest)=List.fold_left~init:([],typ)names~f:(fun(ns,acc)name->ifString.equalnameNaming.self_typ_param_namethenletn_new=Naming.self_typ_param_name^"__new"inlett2=map_core_typeacc~onvar:(funs->(* Caml.Printf.printf "cmp '%s' and '%s' = %b\n%!" s name (String.equal s name ); *)ifString.equalsnamethenSome(ptyp_var~locn_new)elseNone)in(n_new::ns,t2)else(name::ns,acc))in{tdeclwithptype_params=List.map2_exntdecl.ptype_params(List.revr_names)~f:(fun(_,v)s->(ptyp_var~locs,v));ptype_manifest=Somenew_manifest})~onvariant:(fun_->tdecl)~onabstract:(fun_->tdecl)~onrecord:(fun_->tdecl)(* TODO: Implement general case about renaming of paramters *)moduleG=Graph.Persistent.Digraph.Concrete(String)moduleT=Graph.Topological.Make(G)moduleSM=Caml.Map.Make(String)lettopsort_tdeclstdecls=(* TODO: we need topological sorting because in case
* type y = int x
* type 'a x = ....
* we need to declare class for x before class for y
* due to inheritance
*)letname_map=List.fold_left~init:SM.emptytdecls~f:(funacctdecl->matchtdeclwith|{ptype_name}->SM.addptype_name.txttdeclacc)inletg=List.fold_left~init:G.emptytdecls~f:(funacctdecl->letacc=G.add_vertexacctdecl.ptype_name.txtinletinfo=visit_typedecl~loc:tdecl.ptype_loctdecl~onrecord:(fun_->None)~onvariant:(fun_->None)~onabstract:(fun_->None)~onopen:(fun_->None)~onmanifest:(funtyp->matchtyp.ptyp_descwith|Ptyp_constr({txt=Lidents},_)->Somes|_->None)inmatchinfowith|None->acc|Somes->beginmatchSM.findsname_mapwith|exceptionCaml.Not_found->acc|_->G.add_edgeaccstdecl.ptype_name.txtend)inlettdecls_new=T.fold(funsacc->(SM.findsname_map)::acc)g[]|>List.revinassert(List.lengthtdecls=List.lengthtdecls_new);tdecls_new(* for structures *)letdo_typ~locsispluginsis_rectdecl=let(_:bool)=is_recinlettdecl=rename_paramstdeclinletintf_class=Str.of_class_declarations~loc[make_interface_class~loctdecl]inletgcata=make_gcata_str~loctdeclinletplugins=List.mapplugins~f:(funp->p(is_rec,[tdecl]))inList.concat[sis;[intf_class;gcata](* ; indexes_str ~loc plugins [tdecl] *);List.concat_mapplugins~f:(fung->g#do_single~loc~is_rectdecl);collect_plugins_str~loctdecl[tdecl]plugins]letfix_typ~loctdecls=letidx=ref(0)inletnext()=Int.incridx;!idxinletarr3abc=Typ.arrow~loca(Typ.arrow~locbc)inlettup~locxs=matchxswith|[]->failwith"bad arguemnt"|[x]->x|xs->Typ.tuple~locxsinletys=List.maptdecls~f:(funtdecl->letps=List.maptdecl.ptype_params~f:(fun_->sprintf"a%d"(next()))inletsubj_t=Typ.constr~loc(Lidenttdecl.ptype_name.txt)@@(List.mapps~f:(Typ.var~loc))inletinhs=List.mapps~f:(sprintf"%s_i")inletsyns=List.mapps~f:(sprintf"%s_s")inletmain_inh=Typ.var~loc@@sprintf"inh%d"(next())inletmain_syn=Typ.var~loc@@sprintf"syn%d"(next())inletcls=letargs=List.map3_exninhspssyns~f:(funips->[i;p;s])|>List.concat|>List.map~f:(Typ.var~loc)|>(funxs->xs@[main_inh;(ifis_polyvariant_tdecltdeclthenopenize_poly~locelseid)subj_t;main_syn])inTyp.class_~loc(Lident(Naming.class_name_for_typtdecl.ptype_name.txt))argsinlettrf=arr3main_inhsubj_tmain_synin(trf,cls))inletmutuals=tup~loc@@List.mapys~f:fstinList.fold_right~init:(tup~loc@@List.mapys~f:fst)ys~f:(fun(_trf,cls)acc->Typ.arrow~loc(Typ.arrow~locmutualscls)acc)letfix_sig~loctdecls=Sig.value~loc~name:(sprintf"%s"@@Naming.make_fix_nametdecls)(fix_typ~loctdecls)letfix_str~loctdecls=value_binding~loc~pat:(Pat.sprintf~loc"%s"@@Naming.make_fix_nametdecls)~expr:Exp.(fun_list~loc(List.maptdecls~f:(fun{ptype_name}->Pat.sprintf~loc"%s0"ptype_name.txt))@@Exp.let_~loc~rec_:true(List.maptdecls~f:(funtdecl->letek=Exp.fun_list~loc(map_type_param_namestdecl.ptype_params~f:(funtxt->Pat.sprintf~loc"f%s"txt))kinletinhsubjk=Exp.fun_list~loc[Pat.var~loc"inh";Pat.var~loc"subj"]kinletgc=Exp.app_list~loc(Exp.sprintf~loc"gcata_%s"tdecl.ptype_name.txt)[Exp.app_list~loc(Exp.sprintf~loc"%s0"tdecl.ptype_name.txt)((Exp.tuple~loc@@List.maptdecls~f:(fun{ptype_name={txt}}->Exp.sprintf~loc"trait%s"txt))::(map_type_param_namestdecl.ptype_params~f:(funtxt->Exp.sprintf~loc"f%s"txt))(* @
* [Exp.app_list ~loc
* (Exp.sprintf ~loc "trait%s" tdecl.ptype_name.txt)
* (map_type_param_names tdecl.ptype_params
* ~f:(fun txt -> Exp.sprintf ~loc "f%s" txt))
* ] *));Exp.ident~loc"inh";Exp.ident~loc"subj"]in(Pat.sprintf~loc"trait%s"tdecl.ptype_name.txt,e@@inhsubj@@gc)))@@Exp.tuple~loc(List.maptdecls~f:(fun{ptype_name}->Exp.sprintf~loc"trait%s"ptype_name.txt)))|>Str.of_vb~loc~rec_flag:Nonrecursive|>List.returnletcollect_plugins_sig~loctdeclsplugins=List.concat_maptdecls~f:(funtdecl->letwrap()=[Sig.value~loc~name:tdecl.ptype_name.txt@@Typ.constr~loc(Ldot(lident"GT","t"))[make_gcata_typ~loctdecl;Typ.object_~locClosed@@List.mapplugins~f:(funp->(p#trait_name,p#make_final_trans_function_typ~loctdecl))(* ; make_gcata_typ ~loc tdecl *);fix_typ~loctdecls]]invisit_typedecl~loctdecl~onabstract:(fun_->[])~onmanifest:(fun_->wrap())~onvariant:(fun_->wrap())~onrecord:(fun_->wrap()))letdo_mutual_types~locsispluginstdecls=lettdecls=topsort_tdeclstdeclsinletclasses,catas=letall=List.maptdecls~f:(funtdecl->(make_interface_class~loctdecl,make_gcata_str~loctdecl))in(List.map~f:fstall,List.map~f:sndall)inletplugins=List.mapplugins~f:(funp->p(true,tdecls))inList.concat[sis;List.mapclasses~f:(func->Str.of_class_declarations~loc[c]);catas;fix_str~loctdecls;List.concat_mapplugins~f:(fung->g#do_mutuals~loc~is_rec:truetdecls);List.concat_maptdecls~f:(funtdecl->collect_plugins_str~loctdecltdeclsplugins)](* for signatures *)letdo_typ_sig~locsispluginsis_rectdecl=letplugins=List.mapplugins~f:(funp->p(is_rec,[tdecl]))inletintf_class=make_interface_class_sig~loctdeclinletgcata=make_gcata_sig~loctdeclin(* Pprintast.signature_item Format.std_formatter @@
* psig_type ~loc:tdecl.ptype_loc Nonrecursive [tdecl]; *)List.concat[sis;intf_class;gcata;List.concat_mapplugins~f:(fung->g#do_single_sig~loc~is_rectdecl);collect_plugins_sig~loc[tdecl]plugins]letdo_mutual_types_sig~locsispluginstdecls=(* TODO: it could be a bug with topological sorting here *)sis@List.concat_maptdecls~f:(funtdecl->List.concat[make_interface_class_sig~loctdecl;make_gcata_sig~loctdecl])@[fix_sig~loctdecls]@List.concat_mapplugins~f:(funp->(p(true,tdecls))#do_mutuals_sigs~loc~is_rec:true)@(* (List.concat_map tdecls ~f:(fun tdecl ->
* List.concat_map plugins ~f:(fun p ->
* collect_plugins_sig ~loc tdecl (p tdecls))
* )
* ) @ *)(collect_plugins_sig~loctdecls(List.mapplugins~f:(funp->p(true,tdecls))))(* TODO: collect plugins for mutual types *)(* List.concat_map ~f:(do_typ_sig ~loc [] plugins true) tdecls *)letwrap_pluginname=function|Skip->id|Useargs->matchList.Assoc.find!registered_pluginsname~equal:String.equalwith|Somem->letmoduleF=(valm:Plugin_intf.MAKE)inletmoduleP=F(AstHelpers)inList.cons@@P.createargs|None->failwithf"Plugin '%s' is not registered"name()(* let sig_type_decl ~loc ~path si
* ?(use_show=skip) ?(use_gmap=skip) ?(use_foldl=skip) ?(use_show_type=skip)
* ?(use_compare=skip) ?(use_eq=skip)
* (rec_flag, tdls) =
* let plugins =
* wrap_plugin "show" use_show @@
* wrap_plugin "compare" use_compare @@
* wrap_plugin "gmap" use_gmap @@
* wrap_plugin "foldl" use_foldl @@
* wrap_plugin "show_typed" use_show_type @@
* wrap_plugin "eq" use_eq @@
* []
* in
* match rec_flag, tdls with
* | recursive, [] -> []
* | recursive, [tdecl] -> do_typ_sig si ~loc plugins true tdecl
* | recursive, ts -> do_mutal_types_sig ~loc plugins ts
* | nonrecursive, tdls ->
* list.concat_map ~f:(do_typ_sig ~loc si plugins false) tdls *)letsig_type_decl_many_plugins~locsiplugins_infodeclaration=letplugins=List.fold_leftplugins_info~init:[]~f:(funacc(name,args)->wrap_pluginnameargsacc)inletdeclaration=(fstdeclaration,List.map~f:rename_params(snddeclaration))inmatchdeclarationwith|Recursive,[]->[]|Recursive,[tdecl]->do_typ_sigsi~locpluginstruetdecl|Recursive,ts->(* Stdio.printf "Got %d declarations\n%!" (List.length ts); *)do_mutual_types_sig~locsipluginsts|Nonrecursive,tdls->List.concat_map~f:(do_typ_sig~locsipluginsfalse)tdlsletstr_type_decl_many_plugins~locsiplugins_infodeclaration=letplugins=List.fold_leftplugins_info~init:[]~f:(funacc(name,args)->wrap_pluginnameargsacc)inmatchdeclarationwith|Recursive,[]->[]|Recursive,[tdecl]->do_typ~locsipluginstruetdecl|Recursive,ts->do_mutual_types~locsipluginsts|Nonrecursive,decls->List.concat_map~f:(do_typ~locsipluginsfalse)declsletstr_type_ext_many_plugins~locsiplugins_infoextension=[]end(* part of old implementation where we are trying to collect all values in t
* first-class module. but we decided to roll back because we can't write
* generic function to access it *)letname_fcm_mttdecl=sprintf"mt_%s"tdecl.ptype_name.txt(* let gather_module_str tdecl plugins =
* let loc = tdecl.ptype_loc in
*
* let body = [%stri let gcata =
* [%e exp.sprintf "gcata_%s" tdecl.ptype_name.txt] ] ::[]
* in
* let body = list.fold_left ~init:body plugins
* ~f:(fun acc p ->
* let expr = exp.sprintf ~loc "%s" @@ p#make_trans_function_name tdecl in
* str.single_value ~loc (pat.of_string ~loc p#plugin_name) expr
* :: acc
* )
* in
* let expr = exp.pack_with_constraint ~loc
* (mod.structure ~loc @@ list.rev body)
* (located.lident ~loc (name_fcm_mt tdecl))
* in
* str.single_value ~loc (pat.sprintf "%s" tdecl.ptype_name.txt) expr *)(* let make_fcm_sig ~loc tdecl plugins =
* let fields = list.concat_map plugins ~f:(fun p ->
* let name = p#plugin_name in
* let type_ = p#make_trans_function_typ tdecl in
* [sig.value ~loc ~name type_ ]
* )
* in
* mty.signature ~loc ((make_gcata_sig ~shortname:true ~loc tdecl) :: fields )
*
* let prepare_mt ~loc tdecl plugins =
* let name = located.mk ~loc @@ sprintf "mt_%s" tdecl.ptype_name.txt in
* let type_ = some (make_fcm_sig ~loc tdecl plugins) in
* str.modtype ~loc (module_type_declaration ~loc ~name ~type_) *)