Legend:
Page
Library
Module
Module type
Parameter
Class
Class type
Source
Source file engine.ml
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408(*
* Copyright (c) 2019-2020 Craig Ferguson <me@craigfe.io>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*)openPpxlibincludeEngine_intfmoduleSSet=Set.Make(String)letrepr_types=SSet.of_list["unit";"bool";"char";"int";"int32";"int64";"float";"string";"bytes";"list";"array";"option";"pair";"triple";"result";]moduleLocated(Attributes:Attributes.S)(A:Ast_builder.S):S=structtypestate={rec_flag:rec_flag;type_name:string;lib:stringoption;repr_name:string;rec_detected:boolref;var_repr:([`Any|`Varofstring]->expressionoption)ref;(** Given a type variable in a type, get its corresponding typerep (if
the variable is properly bound). *)}letadd_var_repr:typeab.(a->boption)ref->a*b->unit=funf_ref(a,b)->letf_old=!f_refinletf_newa'=ifa=a'thenSomebelsef_olda'inf_ref:=f_newopenUtilsopenUtils.Make(A)moduleReader=Monad.ReadermoduleAlgebraic=structincludeAlgebraicincludeAlgebraic.Located(A)(Reader)endopenAopenReader.SyntaxopenReaderletall_unlabelled=List.map(funx->(Nolabel,x))letrecursive~libfparame=letmu=evar(matchlibwithSomes->s^".mu"|None->"mu")in[%expr[%emu](fun[%ppvarfparam]->[%ee])]letrepr_name_of_type_name=function"t"->"t"|x->x^"_t"letin_lib~libx=matchlibwithSomelib->lib^"."^x|None->xletcontains_tvartvartyp=(objectinherit[bool]Ast_traverse.foldassupermethod!core_type_desct=super#core_type_desct>>funacc->acc||matchtwithPtyp_varvwhenv=tvar->true|_->falseend)#core_typetypfalseletrecderive_coretyp=let*{rec_flag;type_name;repr_name;rec_detected;lib;var_repr}=askinletloc=typ.ptyp_locinmatchtyp.ptyp_descwith|Ptyp_constr({txt=const_name;_},args)->(matchAttribute.getAttributes.reprtypwith|Somee->returne|None->letlident=matchconst_namewith|Lidentconst_name->letname=(* If this type is the one we are deriving and the 'nonrec'
keyword hasn't been used, replace with the repr
name *)ifrec_flag<>Nonrecursive&&String.equalconst_nametype_namethen(rec_detected:=true;repr_name(* If not a base type, assume a composite repr with the
same naming convention *))elseletnobuiltin=matchAttribute.getAttributes.nobuiltintypwith|Some()->true|None->falseinifnobuiltin||not(SSet.memconst_namerepr_types)thenrepr_name_of_type_nameconst_nameelsein_lib~libconst_nameinLocated.lidentname|Ldot(lident,name)->letname=repr_name_of_type_namenameinLocated.mk@@Ldot(lident,name)|Lapply_->invalid_arg"Lident.Lapply not supported"inlet+cons_args=args>|=derive_core|>sequence|>mapall_unlabelledinpexp_apply(pexp_identlident)cons_args)|Ptyp_variant(_,Open,_)->Raise.Unsupported.type_open_polyvar~loctyp|Ptyp_variant(rowfields,Closed,_labellist)->derive_polyvarianttype_namerowfields|Ptyp_poly_->Raise.Unsupported.type_poly~loctyp|Ptyp_tupleargs->derive_tupleargs|Ptyp_arrow_->Raise.Unsupported.type_arrow~loctyp|Ptyp_any->Location.raise_errorf~loc"Unbound type variable"|Ptyp_varv->(match!var_repr(`Varv)with|Somer->returnr|None->Location.raise_errorf~loc"Unbound type variable"v)|Ptyp_package_->Raise.Unsupported.type_package~loctyp|Ptyp_extension_->Raise.Unsupported.type_extension~loctyp|Ptyp_alias(c,var)->ifcontains_tvarvarcthen(add_var_reprvar_repr(`Varvar,evarvar);let+inner=derive_corecinrecursive~libvarinner)elsederive_corec|_->invalid_arg"unsupported"andderive_tupleargs=let*{lib;_}=askinmatchargswith|[t]->(* This case can occur when the tuple type is nested inside a variant *)derive_coret|_->lettuple_type=(matchList.lengthargswith|2->"pair"|3->"triple"|n->Raise.Unsupported.tuple_size~locn)|>in_lib~lib|>evarinargs>|=derive_core|>sequence|>map(all_unlabelled>>pexp_applytuple_type)andderive_recordls=let*{type_name;lib;_}=askinletsubderivelabel_decl=letfield_name=label_decl.pld_name.txtinlet+field_repr=derive_corelabel_decl.pld_typeinAlgebraic.Typ.{field_name;field_repr}inAlgebraic.(encodeTyp.Record)~subderive~lib~type_namelsandderive_variantcs=let*{type_name;lib;_}=askinletsubderivec=letcase_name=c.pcd_name.txtinlet+case_cons=matchc.pcd_argswith|Pcstr_record_->invalid_arg"Inline record types unsupported"|Pcstr_tuple[]->returnNone|Pcstr_tuplecs->let+tuple_typ=derive_tuplecsinSome(tuple_typ,List.lengthcs)inAlgebraic.Typ.{case_name;case_cons}inAlgebraic.(encodeVariant)~subderive~lib~type_namecsandderive_polyvariantnamerowfields=let*{lib;_}=askinletsubderivef=let+case_name,case_cons=matchf.prf_descwith|Rtag(label,_,[])->return(label.txt,None)|Rtag(label,_,typs)->let+tuple_typ=derive_tupletypsin(label.txt,Some(tuple_typ,List.lengthtyps))|Rinherit_->assertfalseinAlgebraic.Typ.{case_name;case_cons}inAlgebraic.(encodePolyvariant)~subderive~lib~type_name:namerowfieldsletderive_lident:?repr:expression->?nobuiltin:unit->longident->(expression,state)Reader.t=fun?repr?nobuiltintxt->let+{lib;_}=askinletnobuiltin=matchnobuiltinwithSome()->true|None->falseinmatchreprwith|Somee->e|None->(matchtxtwith|Lidentcons_name->if(notnobuiltin)&&SSet.memcons_namerepr_typesthenevar(in_lib~libcons_name)else(* If not a basic type, assume a composite
repr /w same naming convention *)evar(repr_name_of_type_namecons_name)|Ldot(lident,cons_name)->pexp_ident(Located.mk@@Ldot(lident,repr_name_of_type_namecons_name))|Lapply_->invalid_arg"Lident.Lapply not supported")letderive_type_decl:type_declaration->(expression,state)Reader.t=funtyp->matchtyp.ptype_kindwith|Ptype_abstract->(matchtyp.ptype_manifestwith|None->invalid_arg"No manifest"|Somec->(matchc.ptyp_descwith(* No need to open library module *)|Ptyp_constr({txt;loc=_},[])->letrepr=Attribute.getAttributes.reprcandnobuiltin=Attribute.getAttributes.nobuiltincinderive_lident?repr?nobuiltintxt(* Type constructor: list, tuple, etc. *)|_->derive_corec))|Ptype_variantcs->derive_variantcs|Ptype_recordls->derive_recordls|Ptype_open->Raise.Unsupported.type_open~locletparse_libexpr=matchexprwith|{pexp_desc=Pexp_construct({txt=Lident"None";_},None);_}->None|{pexp_desc=Pexp_construct({txt=Lident"Some";_},Some{pexp_desc=Pexp_constant(Pconst_string(lib,None));_});_;}->Somelib|{pexp_loc=loc;_}->Location.raise_errorf~loc"Could not process `lib' argument: must be either `Some \"Lib\"' or \
`None'"(* Remove duplicate elements from a list (preserving the order of the first
occurrence of each duplicate). *)letlist_uniq_stable=letrecinner~seenacc=function|[]->List.revacc|x::xswhennot(List.memxseen)->inner~seen:(x::seen)(x::acc)xs|_::xs(* seen *)->inner~seenaccxsininner~seen:[][]moduleUnbound_tvars=structtypeacc={free:stringlist;ctx_bound:stringlist}(* Find all unbound type variables, renaming any instances of [Ptyp_any] to a
fresh variable. *)letfindtyp=(objectinherit[acc]Ast_traverse.fold_mapassupermethod!core_type_desctacc=matchtwith|Ptyp_varvwhennot(List.memvacc.ctx_bound)->(t,{accwithfree=v::acc.free})|Ptyp_any->letname=gen_symbol()in(Ptyp_varname,{accwithfree=name::acc.free})|Ptyp_alias(c,v)->(* Push [v] to the bound stack, traverse the alias, then remove it. *)letc,acc=super#core_typec{accwithctx_bound=v::acc.ctx_bound}inletctx_bound=matchacc.ctx_boundwith|v'::ctx_boundwhenv=v'->ctx_bound|_->assertfalsein(Ptyp_alias(c,v),{accwithctx_bound})|_->super#core_type_desctaccend)#core_typetyp{free=[];ctx_bound=[]}endletexpand_typ?libtyp=lettyp,Unbound_tvars.{free=tvars;_}=Unbound_tvars.findtypinlettvars=List.revtvars|>list_uniq_stableinletenv={rec_flag=Nonrecursive;type_name="t";repr_name="t";rec_detected=reffalse;lib;var_repr=ref(function|`Any->assertfalse(* We already renamed all instances of [Ptyp_any] *)|`Varx->Some(evarx));}inrun(derive_coretyp)env|>lambdatvarsletderive_sig?name?libinput_ast=matchinput_astwith|_,[typ]->lettype_name=typ.ptype_name.txtinletname=Located.mk(matchnamewith|Somen->n|None->repr_name_of_type_nametype_name)inletty_lident=(matchlibwith|Some_->in_lib~lib"t"|None->((* This type decl may shadow the repr type ['a t] *)matchname.txtwith|"t"->"ty"|_->"t"))|>Located.lidentinlettype_=combinator_type_of_type_declarationtyp~f:(fun~loc:_t->ptyp_constrty_lident[t])in[psig_value(value_description~name~type_~prim:[])]|_->invalid_arg"Multiple type declarations not supported"letderive_str?name?libinput_ast=matchinput_astwith|rec_flag,[typ]->lettparams=typ.ptype_params|>List.map(function|{ptyp_desc=Ptyp_varv;_},_->v|{ptyp_desc=Ptyp_any;_},_->"_"|_->assertfalse)inletenv=lettype_name=typ.ptype_name.txtinletrepr_name=matchnamewith|Somes->s|None->repr_name_of_type_nametype_nameinletrec_detected=reffalseinletvar_repr=ref(function|`Any->Raise.Unsupported.type_any~loc|`Varv->ifList.memvtparamsthenSome(evarv)elseNone)in{rec_flag;type_name;repr_name;rec_detected;lib;var_repr}inletexpr=run(derive_type_decltyp)envin(* If the type is syntactically self-referential and the user has not
asserted 'nonrec' in the type declaration, wrap in a 'mu'
combinator *)letexpr=if!(env.rec_detected)&&rec_flag==Recursivethenrecursive~lib:env.libenv.repr_nameexprelseexprinletexpr=lambdatparamsexprinletpat=pvarenv.repr_namein[pstr_valueNonrecursive[value_binding~pat~expr]]|_->invalid_arg"Multiple type declarations not supported"end