123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147(*
* OCanren: syntax extension.
* Copyright (C) 2016-2022
* Dmitrii Kosarev a.k.a. Kakadu
* St.Petersburg University, JetBrains Research
*)(** {i Hash} plugin.
For type declaration [type ('a,'b,...) typ = ...] it will create a transformation
function with type
[(GT.H.t -> 'a -> GT.H.t * 'a) ->
(GT.H.t -> 'b -> GT.H.t * 'b) -> ... ->
GT.H.t -> ('a,'b,...) typ -> GT.H.t * ('a,'b,...) typ ]
which takes a value and hashtable (possibly on-empty) and returns hash concsed
representation of the value with (maybe) update hashtable.
*)openPpxlibopenStdppxopenPrintfopenGTCommonlettrait_name="hash"moduleMake(AstHelpers:GTHELPERS_sig.S)=structmoduleP=Plugin.Make(AstHelpers)lettrait_name=trait_nameopenAstHelpersletht_typ~loc=Typ.of_longident~loc(Ldot(Ldot(Lident"GT","H"),"t"))(* The class representing a plugin for hashconsing. It accepts
[initial_args] which may care additional arguments specific to plugin
and [tdecls] -- type declartion that should be processed.
During code generate phase all plugins require access to type declarations
declared mutually. That's why we pass type declaration to plugin's
constructor and not to generation method
*)classginitial_argstdecls=object(self:'self)inheritP.with_inherited_attrinitial_argstdeclsmethodtrait_name=trait_name(* Default inherited attribute is a predefined in GT type of hash table *)methodinh_of_main~loc_tdecl=ht_typ~loc(* Inherited attribute for parameter is the same as default one*)methodinh_of_param~loc_tdecl_name=ht_typ~loc(* The synthesized attribute of hashconsing is a tuple of new value and
a new hash table *)methodsyn_of_param~locs=Typ.tuple~loc[ht_typ~loc;Typ.var~locs](* The same for default synthsized attribute *)methodsyn_of_main~loc?in_classtdecl=Typ.tuple~loc[ht_typ~loc;Typ.use_tdecltdecl](* Type parameters of the class are type parameters of type being processed
plus extra parameter to support polymorphic variants *)methodplugin_class_params~loc(typs:Ppxlib.core_typelist)~typname=(* the same as in 'show' plugin *)List.maptyps~f:Typ.from_caml@[Typ.var~loc@@Naming.make_extra_paramtypname](* method [on_tuple_constr ~loc ~is_self_rec ~mutual_decls ~inhe tdecl cinfo ts]
receive expression fo rinherited attribute in [inhe],
the name of constructor (algebrain or polyvariant) in [cinfo]
and parameters' type in [ts]
*)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|[]->(* without argument we simply return a hash and unchanged value *)Exp.tuple~loc[inhe;c[]]|ts->(* Constructor with arguments gives oppotunite to save some memory *)letres_var_name=sprintf"%s_rez"inletargcount=List.lengthtsin(* a shortcut for hashconsing function *)lethfhc=Exp.field~loc(Exp.of_longident~loc(Ldot(Lident"GT","hf")))(Lident"hc")in(* We fold argument and construct a new has and a new argument
on every step
*)List.fold_right(List.mapi~f:(funnx->n,x)ts)~init:((* After folding we hashcons constructor of hashconsed arguments *)Exp.app_list~lochfhc[Exp.sprintf~loc"ht%d"argcount;c@@List.mapts~f:(fun(name,_)->Exp.ident~loc@@res_var_namename)])~f:(fun(i,(name,typ))acc->(* for every argument we constuctr a pair of new hash and
new hashconsed argument *)Exp.let_one~loc(Pat.tuple~loc[Pat.sprintf~loc"ht%d"(i+1);Pat.sprintf~loc"%s"@@res_var_namename])(* to call transformation for argument we use a method from
base class
*)(self#app_transformation_expr~loc(* transformation is being generated from the type of argument *)(self#do_typ_gen~loc~is_self_rec~mutual_declstdecltyp)(* inherited argument to use *)(ifi=0theninheelseExp.sprintf~loc"ht%d"i)(* the subject of transformation *)(Exp.ident~locname))acc)methodon_record_declaration~loc~is_self_rec~mutual_declstdecllabs=(* TODO: *)failwith"not implemented"endletcreate=(newg:>P.plugin_constructor)endletregister()=Expander.register_plugintrait_name(moduleMake:Plugin_intf.MAKE)let()=register()