123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458(* SPDX-License-Identifier: LGPL-2.1-or-later *)(*
* OCanren PPX
* Copyright (C) 2016-2021
* Dmitrii Kosarev aka Kakadu, Petr Lozov
* St.Petersburg State University, JetBrains Research
*)modulePprintast_=PprintastopenBaseopenPpxlibopenPpxlib.Ast_builder.DefaultopenPpxlib.Ast_helperopenPrintfmoduleFormat=Caml.FormatopenMyhelpersletuse_logging=falseletlogfmt=ifuse_loggingthenFormat.kasprintf(funs->Format.printf"%s\n%!"s)fmtelseFormat.ifprintfFormat.std_formatterfmt;;letfailwiths?(loc=Location.none)fmt=Location.raise_errorf~locfmtletnolabelize=List.map~f:(fune->Nolabel,e)letnotifyfmt=Printf.ksprintf(funs->let_cmd=Printf.sprintf"notify-send \"%s\""sinlet(_:int)=Caml.Sys.command_cmdin())fmt;;let(@@)=Caml.(@@)letnolabel=Asttypes.Nolabelletmangle_construct_namename=letlow=String.mapi~f:(function|0->Char.lowercase|_->Fn.id)nameinmatchlowwith|"val"|"if"|"else"|"for"|"do"|"let"|"open"|"not"->low^"_"|_->low;;letlower_lidlid=Location.{lidwithtxt=mangle_construct_namelid.Location.txt}lethas_name_attr(xs:attributes)=letexceptionFoundofstringintryList.iterxs~f:(function|{attr_loc;attr_name={txt="name"};attr_payload=PStr[si]}->letopenAst_patterninletp=pstr_eval(pexp_constant(pconst_string____none))nilinparsepattr_loc~on_error:(fun_->())si(funs->raise(Founds))|_->());Nonewith|Founds->Somes;;letdecorate_with_attributestdeclptype_attributes={tdeclwithptype_attributes}includestructletmake_typ_exn?(ccompositional=false)~lococa_logic_identkindtyp=letrechelper=function|[%type:int]ast->oca_logic_ident~loc:t.ptyp_loct|t->(matcht.ptyp_descwith|Ptyp_constr({txt=Ldot(Lident"GT",_)},[])->oca_logic_ident~loc:t.ptyp_loct|Ptyp_constr({txt=Ldot(Lident"GT","list")},xs)->ptyp_constr~loc(Located.mk~loc:t.ptyp_loc(lident_of_list["OCanren";"Std";"List";kind]))(List.map~f:helperxs)|Ptyp_constr({txt=Ldot(path,"ground")},xs)->ptyp_constr~loc(Located.mk~loc(Ldot(path,kind)))(List.map~f:helperxs)|Ptyp_constr({txt=Lident"ground"},xs)->ptyp_constr~loc(Located.mk~loc(Lidentkind))xs|Ptyp_tuple[l;r]->ptyp_constr~loc(Located.mk~loc:t.ptyp_loc(lident_of_list["OCanren";"Std";"Pair";kind]))[helperl;helperr]|Ptyp_constr({txt=Lidents},[])->oca_logic_ident~loc:t.ptyp_loct|Ptyp_constr(({txt=Lident"t"}asid),xs)->oca_logic_ident~loc:t.ptyp_loc@@ptyp_constr~locid(List.map~f:helperxs)|_->t)inmatchtypwith|{ptyp_desc=Ptyp_constr(id,args)}->ifccompositionalthenhelpertypelse(letttt=ptyp_constr~locid(List.map~f:helperargs)inoca_logic_ident~locttt)|{ptyp_desc=Ptyp_tuple[l;r]}->ptyp_constr~loc(Located.mk~loc@@lident_of_list["OCanren";"Std";"Pair";kind])(List.map~f:helper[l;r])|_->failwiths"can't generate %s type: %a"kindPpxlib.Pprintast.core_typetyp;;letltypify_exn?(ccompositional=false)~loctyp=letoca_logic_ident~loc=Located.mk~loc(lident_of_list["OCanren";"logic"])inmake_typ_exn~ccompositional~loc(fun~loct->ptyp_constr~loc(oca_logic_ident~loc:t.ptyp_loc)[t])"logic"typ;;letgtypify_exn?(ccompositional=false)~loctyp=make_typ_exn~ccompositional~loc(fun~loct->t)"ground"typ;;let%expect_test_=letloc=Location.noneinlettesti=lett2=matchi.pstr_descwith|Pstr_type(_,[{ptype_manifest=Somet}])->ltypify_exn~ccompositional:true~loct|_->assertfalseinFormat.printf"%a\n%!"Ppxlib.Pprintast.core_typet2intest[%stritypet1=(int*int)Std.List.ground];[%expect{| (int OCanren.logic, int OCanren.logic) OCanren.Std.Pair.logic Std.List.logic |}];();;endletinjectify~loctyp=letoca_logic_ident~loc=Located.mk~loc(Ldot(Lident"OCanren","ilogic"))inletadd_ilogic~loct=ptyp_constr~loc(oca_logic_ident~loc)[t]inletrechelpert=(* Format.printf "HERR %a\n%!" PPP.core_type t; *)(* .... ground ~~~> injected ...
.... t ~~~> .... t ilogic
*)matchtwith|[%type:GT.int]|[%type:int]|[%type:GT.string]|[%type:string]|[%type:GT.bool]|[%type:bool]->[%type:[%tt]OCanren.ilogic]|[%type:[%t?arg]GT.list]->[%type:[%thelperarg]OCanren.Std.List.groundi]|{ptyp_desc=Ptyp_constr({txt=Ldot(Lident"GT",s)},[])}->ptyp_constr~loc(oca_logic_ident~loc:t.ptyp_loc)[t]|{ptyp_desc=Ptyp_constr({txt=Ldot(path,"ground")},[])}->ptyp_constr~loc(Located.mk~loc(Ldot(path,"injected")))[]|{ptyp_desc=Ptyp_constr({txt=Ldot(path,"ground")},xs)}->ptyp_constr~loc(Located.mk~loc(Ldot(path,"injected")))@@List.map~f:helperxs|{ptyp_desc=Ptyp_constr({txt=Lident"t"},xs)}->add_ilogic~loc@@ptyp_constr~loc(Located.mk~loc(Lident"t"))(List.map~f:helperxs)|{ptyp_desc=Ptyp_constr({txt=Lident"ground"},xs)}->ptyp_constr~loc(Located.mk~loc(Lident"injected"))(List.map~f:helperxs)|{ptyp_desc=Ptyp_var_}->t|_->Location.raise_errorf~loc"injectify: bad type `%a`"Pprintast.core_typetinhelpertyp;;let%expect_test"injectify"=letloc=Location.noneinlettesti=lett2=matchi.pstr_descwith|Pstr_type(_,[{ptype_manifest=Somet}])->injectify~loct|_->assertfalseinFormat.printf"%a\n%!"Ppxlib.Pprintast.core_typet2intest[%stritypenonrecx=GT.intt];[%expect{| GT.int OCanren.ilogic t OCanren.ilogic |}];test[%stritypenonrecground=groundt];[%expect{| injected t OCanren.ilogic |}];test[%stritypenonrecground=intGT.list];[%expect{| int OCanren.ilogic OCanren.Std.List.groundi |}];();;typekind=|Reify|Prj_exnletmanifest_of_tdecl_exntdecl=matchtdecl.ptype_manifestwith|None->failwiths~loc:tdecl.ptype_loc"types without manifest are not allowed"|Somem->m;;letprocess_main~locbase_tdecl(rec_,tdecl)=letis_rec=matchrec_with|Recursive->true|Nonrecursive->falseinletltyp=letptype_manifest=matchtdecl.ptype_manifestwith|None->failwith"no manifest"|Some({ptyp_desc=Ptyp_constr(id,args)}astyp)->Some(ltypify_exn~loctyp)|t->tinletptype_attributes=List.filtertdecl.ptype_attributes~f:(funattr->matchattr.attr_name.txtwith|"distrib"->false|_->true)in{tdeclwithptype_name=Located.mk~loc"logic";ptype_manifest;ptype_attributes}inletnames=extract_namestdecl.ptype_paramsinletinjected_typ=letptype_manifest=matchtdecl.ptype_manifestwith|None->failwiths~loc:tdecl.ptype_loc"No manifest"|Some({ptyp_desc=Ptyp_constr(id,args)}astyp)->Option.some(injectify~loctyp)|t->tintype_declaration~loc~name:(Located.mk~loc"injected")~private_:Public~kind:Ptype_abstract~cstrs:[]~params:(List.mapnames~f:(funs->Typ.vars,(NoVariance,NoInjectivity)))~manifest:ptype_manifestinletcreators=letnamecd=mangle_construct_namecd.pcd_name.txtinmatchbase_tdecl.ptype_kindwith|Ptype_variantcds->List.mapcds~f:(funcd->letname=matchhas_name_attrcd.pcd_attributeswith|None->namecd|Somename->nameinmatchcd.pcd_argswith|Pcstr_tuplexs->letargs=List.mapxs~f:(fun_->Ppxlib.gen_symbol())inletadd_argsrhs=matchargswith|[]->[%exprfun()->[%erhs]]|args->List.fold_right~init:rhsargs~f:(funxacc->Exp.fun_nolabelNone(Pat.var(Located.mk~locx))acc)in[%strilet[%pPat.var~loc(Located.mk~locname)]=[%eadd_args[%exprOCanren.inji[%eExp.construct(Located.map_lidentcd.pcd_name)(ifList.is_emptyargsthenNoneelseSome(Exp.mytuple~loc(List.mapargs~f:(Exp.lident~loc))))]]];;]|_->failwiths~loc:base_tdecl.ptype_loc"constructors with records are not implemented")|Ptype_record_->failwiths~loc:base_tdecl.ptype_loc"%s %d Record constructors are not implemented"Caml.__FILE__Caml.__LINE__|Ptype_open|Ptype_abstract->failwiths~loc:base_tdecl.ptype_loc"%s %d Open and abstract types are not supported"Caml.__FILE__Caml.__LINE__inletmk_arg_reifiers=sprintf"r%s"sinletmake_reifier_gen~kind?(typ=None)is_rectdecl=letpat,base_reifier,name=matchkindwith|Reify->[%pat?reify],[%exprOCanren.reify],"reify"|Prj_exn->[%pat?prj_exn],[%exprOCanren.prj_exn],"prj_exn"inletmanifest=manifest_of_tdecl_exntdeclinletadd_args=letloc=tdecl.ptype_locinfunrhs->List.fold_rightnames~init:rhs~f:(funnameacc->[%exprfun[%pPat.var(Located.mk~loc(mk_arg_reifiername))]->[%eacc]])inletrechelpertyp:expression=letloc=typ.ptyp_locinmatchtypwith|{ptyp_desc=Ptyp_constr({txt=Lident"ground"},_)}->[%exprself]|{ptyp_desc=Ptyp_vars}->pexp_ident~loc(Located.mk~loc(lident(mk_arg_reifiers)))|[%type:GT.int]|[%type:int]|[%type:GT.bool]|[%type:bool]|[%type:GT.string]|[%type:string]->base_reifier|[%type:[%t?arg]GT.list]->failwiths~loc"There are some issues with GT.list. Please, use fully qualified \
OCanren.Std.List.ground for now "|{ptyp_desc=Ptyp_constr({txt=Ldot(m,_)},args)}->letrhs=pexp_ident~loc(Located.mk~loc(Ldot(m,name)))inList.fold_left~init:rhsargs~f:(funaccx->pexp_apply~locacc[nolabel,helperx])|_->failwiths~loc:typ.ptyp_loc"not supported: %a"Pprintast.core_typetypinletbody=matchmanifest.ptyp_descwith|Ptyp_constr({txt},args)->letfmapt=pexp_apply~loc[%exprfmapt](List.mapargs~f:(funt->Nolabel,helpert))in[%exprletopenEnv.MonadinletopenEnv.Monad.SyntaxinReifier.fix(funself->[%ebase_reifier]<..>chain[%ematchkindwith|Reify->[%exprReifier.zed(Reifier.rework~fv:[%efmapt])]|Prj_exn->fmapt])]|_->failwiths~loc:manifest.ptyp_loc"should not happen %s %d"Caml.__FILE__Caml.__LINE__inletpat=matchtypwith|None->pat|Somet->ppat_constraint~locpattinpstr_value~locNonrecursive[value_binding~loc~pat~expr:(add_argsbody)]inletmake_reifieris_rectdecl=letmanifest=manifest_of_tdecl_exntdeclinletlogic_typ=ltypify_exn~ccompositional:true~locmanifestinmake_reifier_gen~kind:Reify~typ:(ifList.is_emptytdecl.ptype_paramsthenSome[%type:(_,[%tlogic_typ])Reifier.t]elseNone)is_rectdeclinletmake_prj_exnis_rectdecl=letmanifest=manifest_of_tdecl_exntdeclinmake_reifier_gen~kind:Prj_exn~typ:(ifList.is_emptytdecl.ptype_paramsthenSome[%type:(_,[%tgtypify_exn~ccompositional:true~locmanifest])Reifier.t]elseNone)is_rectdeclinletmake_fmapttdecl=letnames=extract_names(name_type_params_in_tdtdecl).ptype_params|>List.map~f:(funprefix->gen_symbol~prefix())inletadd_funsrhs=List.fold_rightnames~f:(funnameacc->[%exprfun[%pppat_var~loc(Located.mk~locname)]->[%eacc]])~init:rhsinletsubj=gen_symbol~prefix:"subj"()inletexpr=add_funs[%exprfun[%pppat_var~loc(Located.mk~locsubj)]->letopenEnv.Monadin[%eList.fold_left~init:[%exprEnv.Monad.return(GT.gmapt)]names~f:(funaccname->[%expr[%eacc]<*>[%epexp_ident~loc(Located.mk~loc(Lidentname))]])]<*>[%epexp_ident~loc(Located.mk~loc(lidentsubj))]]inpstr_value~locNonrecursive[value_binding~loc~pat:[%pat?fmapt]~expr]inList.concat[[pstr_type~locNonrecursive[base_tdecl]];[pstr_type~locrec_[decorate_with_attributestdeclbase_tdecl.ptype_attributes]];[pstr_type~locrec_[decorate_with_attributesltypbase_tdecl.ptype_attributes]];[pstr_type~locrec_[injected_typ]];[make_fmaptbase_tdecl];[make_prj_exnis_rectdecl;make_reifieris_rectdecl];creators];;letprocess_composable=List.map~f:(funtdecl->letloc=tdecl.pstr_locinmatchtdecl.pstr_descwith|Pstr_type(flg,[t])->(matcht.ptype_manifestwith|Somem->pstr_type~locNonrecursive[{twithptype_attributes=[attribute~loc~name:(Located.mk~loc"deriving")~payload:(PStr[[%strireify]])]}]|None->tdecl)|_->tdecl);;