123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246openPpxlibopenStdLabelsopenAst_builder.DefaultopenMiscellanyopenPrintersopenNamesopenLidentopenInv_ctxopenBuilders(******************************************************************************)(** {1 Working with constructors for algebraic data types} *)(** Extracts the variable name from a [Ppat_var] pattern
- Raises [Not_found] if the input pattern is not of the form [Ppat_var] *)letget_varname({ppat_desc;_}:pattern):string=matchppat_descwith|Ppat_var{txt;_}->txt|_->raiseNot_found(** Takes [ty], the type of a [val] declaration in a signature,
and returns the type of the arguments of the corresponding
constructor for the [expr] datatype.
- The [abs_ty_names] argument is a list of abstract types
that are defined in the module signature (to determine
when arguments should be instantiated with the [expr] type)
For the [Set] module signature example,
- [val empty : 'a t] corresponds to the 0-arity [Empty] constructor
- [val is_empty : 'a t -> bool] corresponds to [Is_empty of expr * bool]
- Monomorphic primitive types are preserved.
The [is_arrow] optional
named argument specifies whether [ty] is an arrow type: if yes, then
references to abstract types should be replaced with [expr], otherwise
an occurrence of an abstract type in an non-arrow type
(e.g. [val empty : 'a t]) should be ignored (so [val empty : 'a t]
corresponds to the nullary constructor [Empty]). *)letrecget_arg_tys_of_expr_cstr?(is_arrow=false)(ty:core_type)(abs_ty_names:stringlist):core_typelist=letloc=ty.ptyp_locinmatchmonomorphizetywith|ty'whenList.memty'~set:(base_types~loc)->[ty']|{ptyp_desc=Ptyp_constr({txt=lident;_},_);_}asty'->lettyconstr=string_of_lidentlidentinifList.memtyconstr~set:abs_ty_namesthenifis_arrowthen[[%type:expr]]else[]else[ty']|{ptyp_desc=Ptyp_arrow(_,t1,t2);_}->get_arg_tys_of_expr_cstr~is_arrow:truet1abs_ty_names@get_arg_tys_of_expr_cstr~is_arrow:truet2abs_ty_names|{ptyp_desc=Ptyp_tupletys;_}->List.concat_map~f:(funty->get_arg_tys_of_expr_cstr~is_arrowtyabs_ty_names)tys|_->failwith"TODO: get_arg_tys_of_expr_cstr"(** Helper function: [get_cstr_args loc get_ty args] takes [args],
a list containing the {i representation} of constructor arguments,
applies the function [get_ty] to each element of [args] and produces
a formatted tuple of constructor arguments (using the [ppat_tuple] smart
constructor for the [pattern] type).
- Note that [args] has type ['a list], i.e. the representation of
constructor arguments is polymorphic -- this function is instantiated
with different types when called in [get_cstr_metadata] *)letget_cstr_args~(loc:Location.t)(get_ty:'a->core_type)(args:'alist):pattern*inv_ctx=letarg_tys:core_typelist=List.map~f:get_tyargsinletarg_names:patternlist=List.map~f:(mk_fresh_pvar~loc)arg_tysinletgamma:inv_ctx=List.fold_left2~f:(funaccvar_patty->(ty,get_varnamevar_pat)::acc)~init:[]arg_namesarg_tysin(ppat_tuple~locarg_names,gamma)(** Takes a list of [constructor_declaration]'s and returns
a list consisting of 4-tuples of the form
(constructor name, constructor arguments, typing context, return type) *)letget_cstr_metadata(cstrs:(constructor_declaration*core_type)list):(Longident.tLocation.loc*patternoption*inv_ctx*core_type)list=List.mapcstrs~f:(fun({pcd_name={txt;loc};pcd_args;_},ret_ty)->letcstr_name=with_loc(Longident.parsetxt)~locinmatchpcd_argswith(* Constructors with no arguments *)|Pcstr_tuple[]->(cstr_name,None,empty_ctx,ret_ty)(* N-ary constructors (where n > 0) *)|Pcstr_tuplearg_tys->let(cstr_args,gamma):pattern*inv_ctx=get_cstr_args~locFun.idarg_tysin(cstr_name,Somecstr_args,gamma,ret_ty)|Pcstr_recordarg_lbls->letcstr_args,gamma=get_cstr_args~loc(funlbl_decl->lbl_decl.pld_type)arg_lblsin(cstr_name,Somecstr_args,gamma,ret_ty))(** Variant of [get_cstr_metadata] which returns
only a list of pairs containing constructor names & constructor args *)letget_cstr_metadata_minimal(cstrs:constructor_declarationlist):(Longident.tLocation.loc*patternoption)list=List.mapcstrs~f:(fun{pcd_name={txt;loc};pcd_args;_}->letcstr_name=with_loc(Longident.parsetxt)~locinmatchpcd_argswith(* Constructors with no arguments *)|Pcstr_tuple[]->(cstr_name,None)(* N-ary constructors (where n > 0) *)|Pcstr_tuplearg_tys->let(cstr_args,_):pattern*inv_ctx=get_cstr_args~locFun.idarg_tysin(cstr_name,Somecstr_args)|Pcstr_recordarg_lbls->letcstr_args,_=get_cstr_args~loc(funlbl_decl->lbl_decl.pld_type)arg_lblsin(cstr_name,Somecstr_args))(** Extracts the constructor name (along with its location) from
a constructor declaration *)letget_cstr_name(cstr:constructor_declaration):Longident.tLocation.loc=let{txt;loc}=cstr.pcd_nameinwith_loc~loc(Longident.parsetxt)(** Takes a [type_declaration] for an algebraic data type
and returns a list of (constructor name, constructor arguments)
- Raises an exception if the [type_declaration] doesn't correspond to an
algebraic data type *)letget_cstrs_of_ty_decl(ty_decl:type_declaration):(Longident.tLocation.loc*patternoption)list=matchty_decl.ptype_kindwith|Ptype_variantargs->get_cstr_metadata_minimalargs|_->failwith"error: expected an algebraic data type definition"(** Computes the arity of a constructor for an algebraic data type *)letget_cstr_arity(cstr:constructor_declaration):int=matchcstr.pcd_argswith|Pcstr_tuplexs->List.lengthxs|Pcstr_recordlbls->List.lengthlbls(** Retrieves the argument types of a constructor for an algebraic data type *)letget_cstr_arg_tys(cstr:constructor_declaration):core_typelist=matchcstr.pcd_argswith|Pcstr_tupletys->tys|Pcstr_recordlbls->List.map~f:(funlbl->lbl.pld_type)lbls(******************************************************************************)(** {1 Working with type parameters & type declarations} *)(** [get_type_varams td] extracts the type parameters
from the type declaration [td]
- Type variables (e.g. ['a]) are instantiated with [int] *)letget_type_params(td:type_declaration):core_typelist=List.maptd.ptype_params~f:(fun(core_ty,_)->monomorphizecore_ty)(** Extracts the (monomorphized) return type of a type expression
(i.e. the rightmost type in an arrow type) *)letrecget_ret_ty(ty:core_type):core_type=letloc=ty.ptyp_locinletty_mono=monomorphizetyinifList.memty_mono~set:(base_types~loc)thenty_monoelsematchty_mono.ptyp_descwith|Ptyp_constr_|Ptyp_tuple_|Ptyp_any|Ptyp_var_->ty_mono|Ptyp_arrow(_,_,t2)->get_ret_tyt2|_->failwith"Type expression not supported by get_ret_ty"(** Takes a [type_declaration] and returns a pair of the form
[(<type_name, list_of_type_parameters)] *)letget_ty_name_and_params({ptype_name;ptype_params;_}:type_declaration):string*core_typelist=letty_params=List.map~f:fstptype_paramsin(ptype_name.txt,ty_params)(** Takes a module signature and returns a list containing pairs of the form
[(<type_name>, <list_of_type_parameters>)]. The list is ordered based on
the order of appearance of the type declarations in the signature. *)letget_ty_decls_from_sig(sig_items:signature):(string*core_typelist)list=List.fold_leftsig_items~init:[]~f:(funacc{psig_desc;_}->matchpsig_descwith|Psig_type(_,ty_decls)->List.map~f:get_ty_name_and_paramsty_decls::acc|_->acc)|>List.concat|>List.rev(** Retrieves all the abstract types from a signature as a list of
[type_declaration]s *)letget_abs_tys_from_sig(sig_items:signature):type_declarationlist=List.fold_left~f:(funacc{psig_desc;_}->matchpsig_descwith|Psig_type(_,ty_decls)->acc@ty_decls|_->acc)~init:[]sig_items(** Retrieves the names of all the abstract types in a signature *)letget_abs_ty_names(sig_items:signature):stringlist=letabs_tys=get_abs_tys_from_sigsig_itemsinList.map~f:(funabs_ty->no_locabs_ty.ptype_name)abs_tys(******************************************************************************)(** {1 Working with pattern matches} *)(** [get_match_arm ~loc expr_vars ~abs_ty_parameterized] returns the
match arms of the inner pattern match in [interp], e.g.
an expression of the form [ValIntT e]
- The argument [expr_vars] is a list of variable names that
have type [expr]
- The named argument [abs_ty_parameterized] represents whether the
abstract type [t] in the module signature is parameterized (e.g. ['a t]) *)letget_match_arm(expr_vars:stringlist)~(abs_ty_parameterized:bool)~(loc:Location.t):pattern=matchexpr_varswith|[]->failwith"impossible: get_match_arm"|[x]->mk_valt_pat~loc~abs_ty_parameterized(add_primex)|_->letval_exprs:patternlist=List.map~f:(funx->mk_valt_pat~loc~abs_ty_parameterized(add_primex))expr_varsinppat_tuple~locval_exprs(** Creates the RHS of the inner pattern-match in [interp], for the special
case where we are dealing with a unary [value] constructor
and a unary module function, e.g. [match e with ValInt x -> M.f x]
(In this example, [get_unary_case_rhs] produces the expression [M.f x])
- [value_cstr] is the name of the constructor for the [value] type
- [expr_cstr] is the constructor for the [expr] type, which corresponds
to a function inside the module with name [mod_name]
- [x] is the argument that will be applied to the module function *)letget_unary_case_rhs(value_cstr:Longident.tLocation.loc)(mod_name:string)(expr_cstr:Longident.tLocation.loc)(x:string)~(loc:Location.t):expression=letmod_func=pexp_ident~loc(add_lident_loc_prefixmod_nameexpr_cstr)inletmod_func_arg=evar(add_primex)~locinletmod_func_app=[%expr[%emod_func][%emod_func_arg]]inpexp_construct~locvalue_cstr(Somemod_func_app)(** Variant of [get_unary_case_rhs] which handles the situation
when the RHS of the case statement is an n-ary function with
arguments [xs] *)letget_nary_case_rhs(ret_ty_cstr:constructor_declaration)(mod_name:string)(expr_cstr:Longident.tLocation.loc)(xs:expressionlist)~loc:expression=letmod_func=pexp_ident~loc(add_lident_loc_prefixmod_nameexpr_cstr)inletmod_func_app=pexp_apply~locmod_func(List.map~f:(funx->(Nolabel,x))xs)inletvalue_cstr=get_cstr_nameret_ty_cstrinpexp_construct~locvalue_cstr(Somemod_func_app)