Legend:
Page
Library
Module
Module type
Parameter
Class
Class type
Source
Source file ppx_let_expander.ml
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267openBaseopenPpxlibopenAst_builder.DefaultmoduleList=structincludeListletreduce_exnl~f=matchlwith|[]->invalid_arg"List.reduce_exn"|hd::tl->fold_lefttl~init:hd~f;;endmoduleExtension_name=structtypet=|Sub|Sub_open|Bind|Bind_open|Bindn|Bindn_open|Map|Map_open|Mapn|Mapn_openletoperator_name=function|Sub|Sub_open->"sub"|Bind|Bind_open|Bindn|Bindn_open->"bind"|Map|Map_open|Mapn|Mapn_open->"map";;letto_string=function|Sub->"sub"|Sub_open->"sub_open"|Bind->"bind"|Bindn->"bindn"|Bindn_open->"bindn_open"|Bind_open->"bind_open"|Map->"map"|Map_open->"map_open"|Mapn->"mapn"|Mapn_open->"mapn_open";;endletlet_syntax="Let_syntax"letlet_syntax~modul:Longident.t=matchmodulwith|None->Lidentlet_syntax|Someid->Ldot(Ldot(id.txt,let_syntax),let_syntax);;letopen_on_rhs~loc~modul=pmod_ident~loc(Located.mk~loc(Longident.Ldot(let_syntax~modul,"Open_on_rhs")));;leteoperator~loc~modulfunc=letlid:Longident.t=Ldot(let_syntax~modul,func)inpexp_ident~loc(Located.mk~loclid);;letexpand_with_tmp_vars~locbindingsexpr~f=matchbindingswith|[_]->f~locbindingsexpr|_->lettmp_vars=List.mapbindings~f:(fun_->gen_symbol~prefix:"__let_syntax"())inlets_rhs_tmp_var(* s/rhs/tmp_var *)=List.map2_exnbindingstmp_vars~f:(funvbvar->letloc={vb.pvb_expr.pexp_locwithloc_ghost=true}in{vbwithpvb_expr=evar~locvar})inlets_lhs_tmp_var(* s/lhs/tmp_var *)=List.map2_exnbindingstmp_vars~f:(funvbvar->letloc={vb.pvb_pat.ppat_locwithloc_ghost=true}in{vbwithpvb_pat=pvar~locvar;pvb_loc={vb.pvb_locwithloc_ghost=true}})inpexp_let~locNonrecursives_lhs_tmp_var(f~locs_rhs_tmp_varexpr);;letexpand_with_op_n_function~loc~modul~op_namebindingsexpr=letn=List.lengthbindingsinletoperator=matchnwith|1->eoperator~loc~modulop_name|n->eoperator~loc~modul(Printf.sprintf"%s%d"op_namen)inletbindings_args=bindings|>List.map~f:(fun{pvb_expr;_}->Nolabel,pvb_expr)inletfunc=List.fold_rightbindings~init:expr~f:(fun{pvb_pat;_}lower->pexp_fun~locNolabelNonepvb_patlower)inletargs=List.appendbindings_args[Labelled"f",func]inpexp_apply~locoperatorargs;;letbind_apply~loc~modulextension_name~arg~fn=pexp_apply~loc(eoperator~loc~modul(Extension_name.operator_nameextension_name))[Nolabel,arg;Labelled"f",fn];;letmaybe_openextension_name~to_open:module_to_openexpr=letloc={expr.pexp_locwithloc_ghost=true}inmatch(extension_name:Extension_name.t)with|Sub|Bind|Map|Mapn|Bindn->expr|Sub_open|Bind_open|Bindn_open|Map_open|Mapn_open->pexp_open~loc(open_infos~loc~override:Override~expr:(module_to_open~loc))expr;;letassert_bindings_length~loc~extension_name~bindings=matchextension_name,List.lengthbindingswith|_,0->invalid_arg"expand_let: list of bindings must be non-empty"|(Extension_name.Sub|Sub_open),nwhenn>1->(* let%sub doesn't allow more than one binding *)Location.raise_errorf~loc"let%%sub cannot be used with 'and'"|_->();;letexpand_letextension_name~loc~modulbindingsbody=assert_bindings_length~loc~extension_name~bindings;(* Build expression [both E1 (both E2 (both ...))] *)letnested_boths=letrev_boths=List.rev_mapbindings~f:(funvb->vb.pvb_expr)inList.reduce_exnrev_boths~f:(funacce->letloc={e.pexp_locwithloc_ghost=true}ineapply~loc(eoperator~loc~modul"both")[e;acc])in(* Build pattern [(P1, (P2, ...))] *)letnested_patterns=letrev_patts=List.rev_mapbindings~f:(funvb->vb.pvb_pat)inList.reduce_exnrev_patts~f:(funaccp->letloc={p.ppat_locwithloc_ghost=true}inppat_tuple~loc[p;acc])inbind_apply~loc~modulextension_name~arg:nested_boths~fn:(pexp_fun~locNolabelNonenested_patternsbody);;letexpand_matchextension_name~loc~modulexprcases=bind_apply~loc~modulextension_name~arg:(maybe_openextension_name~to_open:(open_on_rhs~modul)expr)~fn:(pexp_function~loccases);;letexpand_ifextension_name~locexprthen_else_=expand_matchextension_name~locexpr[case~lhs:(pbool~loctrue)~guard:None~rhs:then_;case~lhs:(pbool~locfalse)~guard:None~rhs:else_];;letexpand_while~loc~modul~cond~body=letloop_name=gen_symbol~prefix:"__let_syntax_loop"()inletploop=pvar~locloop_nameinleteloop=evar~locloop_nameinletloop_call=pexp_apply~loceloop[Nolabel,eunit~loc]inletloop_body=letthen_=bind_apply~loc~modulBind~arg:body~fn:eloopinletelse_=pexp_apply~loc(eoperator~loc~modul"return")[Nolabel,eunit~loc]inexpand_if~modulBind~loccondthen_else_inletloop_func=pexp_fun~locNolabelNone(punit~loc)loop_bodyinpexp_let~locRecursive[value_binding~loc~pat:ploop~expr:loop_func]loop_call;;letexpand~modulextension_nameexpr=letloc={expr.pexp_locwithloc_ghost=true}inletexpansion=matchexpr.pexp_descwith|Pexp_let(Nonrecursive,bindings,expr)->letbindings=List.mapbindings~f:(funvb->letpvb_pat=(* Temporary hack tentatively detecting that the parser
has expanded `let x : t = e` into `let x : t = (e : t)`.
For reference, here is the relevant part of the parser:
https://github.com/ocaml/ocaml/blob/4.07/parsing/parser.mly#L1628 *)matchvb.pvb_pat.ppat_desc,vb.pvb_expr.pexp_descwith|(Ppat_constraint(p,{ptyp_desc=Ptyp_poly([],t1);_}),Pexp_constraint(_,t2))whenphys_equalt1t2||Poly.equalt1t2->p|_->vb.pvb_patin{vbwithpvb_pat;pvb_expr=maybe_openextension_name~to_open:(open_on_rhs~modul)vb.pvb_expr})in(matchextension_namewith|Mapn|Bindn|Mapn_open|Bindn_open->expand_with_tmp_vars~locbindingsexpr~f:(expand_with_op_n_function~modul~op_name:(Extension_name.operator_nameextension_name))|Sub|Sub_open|Bind|Bind_open|Map|Map_open->expand_with_tmp_vars~locbindingsexpr~f:(expand_letextension_name~modul))|Pexp_let(Recursive,_,_)->Location.raise_errorf~loc"'let%%%s' may not be recursive"(Extension_name.to_stringextension_name)|Pexp_match(expr,cases)->(matchextension_namewith|Sub|Sub_open->Location.raise_errorf~loc"match%%sub is not supported"|_->expand_matchextension_name~loc~modulexprcases)|Pexp_ifthenelse(expr,then_,else_)->letelse_=matchelse_with|Someelse_->else_|None->Location.raise_errorf~loc"'if%%%s' must include an else branch"(Extension_name.to_stringextension_name)in(matchextension_namewith|Sub|Sub_open->Location.raise_errorf~loc"if%%sub is not supported"|_->expand_ifextension_name~loc~modulexprthen_else_)|Pexp_while(cond,body)->(match(extension_name:Extension_name.t)with|Map|Map_open|Mapn|Mapn_open->Location.raise_errorf~loc"while%%map is not supported. use while%%bind instead."|Bindn|Bindn_open->Location.raise_errorf~loc"while%%bindn is not supported. use while%%bind instead."|Sub|Sub_open->Location.raise_errorf~loc"while%%sub is not supported"|Bind|Bind_open->expand_while~loc~modul~cond~body)|_->Location.raise_errorf~loc"'%%%s' can only be used with 'let', 'match', 'while', and 'if'"(Extension_name.to_stringextension_name)in{expansionwithpexp_attributes=expr.pexp_attributes@expansion.pexp_attributes};;