123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630openBaseopenPpxlibopenAst_builder.Defaultletpexp_let~locrec_bindingse=matchbindingswith|[]->e|_::_->pexp_let~locrec_bindingse;;moduleList=structincludeListletreduce_exnl~f=matchlwith|[]->invalid_arg"List.reduce_exn"|hd::tl->fold_lefttl~init:hd~f;;endmoduleExtension_kind=structtypet={do_open:bool;collapse_binds:bool}letdefault={do_open=false;collapse_binds=false}letdefault_open={do_open=true;collapse_binds=false}letn={do_open=false;collapse_binds=true}letn_open={do_open=true;collapse_binds=true}endmoduletypeExt=sig(* The base string of all the related extensions. For example, if the value
is "bind", then other extensions will include "bind_open", "bindn", and
"bindn_open" - all of which start with "bind" *)valname:stringvalwith_location:bool(* Called before each expansion to ensure that the expression being expanded
is supported. *)valdisallow_expression:Extension_kind.t->expression_desc->(unit,string)Result.t(* Called when expanding a let-binding (and indirectly, when expanding a
match-expression) to destructure [rhs]. The resulting expression should
make each variable in [lhs] available for use in [body]. If the result is
[None], then no special destructuring is necessary. *)valdestruct:assume_exhaustive:bool->loc:location->modul:longidentlocoption->lhs:pattern->rhs:expression->body:expression->expressionoption(* Expands any match%[name] expressions. It is also used when expanding
if%[name]. *)valexpand_match:loc:location->modul:longidentlocoption->expression->caselist->expressionendtypet=(moduleExt)letext_full_name(moduleExt:Ext){Extension_kind.do_open;collapse_binds;_}=letresult=Ext.nameinletresult=ifcollapse_bindsthenString.concat[result;"n"]elseresultinifdo_openthenString.concat[result;"_open"]elseresult;;letlet_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);;letqualified_return~loc~modulexpr=pexp_apply~loc(eoperator~loc~modul"return")[Nolabel,expr];;letlocation_arg~loc=Labelled"here",Ppx_here_expander.lift_position~locletbind_apply~op_name~loc~modul~with_location~arg~fn=letargs=ifwith_locationthen[location_arg~loc;Nolabel,arg;Labelled"f",fn]else[Nolabel,arg;Labelled"f",fn]inpexp_apply~loc(eoperator~loc~modulop_name)args;;letexpand_with_tmp_vars~locbindingsexpr~f=matchbindingswith|[_]->f~locbindingsexpr|_->(* s/rhs/tmp_var and s/lhs/tmp_var *)lets_rhs_tmp_var,s_lhs_tmp_var=List.mapbindings~f:(funvb->letvar=gen_symbol~prefix:"__let_syntax"()inletloc={vb.pvb_expr.pexp_locwithloc_ghost=true}inletrhs={vbwithpvb_expr=evar~locvar}inletloc={vb.pvb_pat.ppat_locwithloc_ghost=true}inletlhs={vbwithpvb_pat=pvar~locvar;pvb_loc={vb.pvb_locwithloc_ghost=true}}inrhs,lhs)|>List.unzipinpexp_let~locNonrecursives_lhs_tmp_var(f~locs_rhs_tmp_varexpr);;letcatch_all_case~loc=case~lhs:(ppat_any~loc)~guard:None~rhs:(pexp_assert~loc(ebool~locfalse));;letmaybe_destruct~destruct~loc~modul~lhs~body=letwhole_value_var=gen_symbol~prefix:"__pattern_syntax"()inletwhole_value_pattern=ppat_var~loc{txt=whole_value_var;loc}inletwhole_value_expr=pexp_ident~loc{txt=Lidentwhole_value_var;loc}inmatchdestruct~assume_exhaustive:true~loc~modul~lhs~rhs:whole_value_expr~bodywith|Somedestruction->pexp_fun~locNolabelNonewhole_value_patterndestruction|None->pexp_fun~locNolabelNonelhsbody;;letexpand_letn(moduleExt:Ext)~loc~modulbindingsbody=letn=List.lengthbindingsinletoperator=matchnwith|1->eoperator~loc~modulExt.name|n->eoperator~loc~modul(Printf.sprintf"%s%d"Ext.namen)inletbindings_args=bindings|>List.map~f:(fun{pvb_expr;_}->Nolabel,pvb_expr)inletfunc=List.fold_rightbindings~init:body~f:(fun{pvb_pat;_}lower->maybe_destruct~destruct:Ext.destruct~modul~loc~lhs:pvb_pat~body:lower)inletargs=bindings_args@ifExt.with_locationthen[location_arg~loc;Labelled"f",func]else[Labelled"f",func]inpexp_apply~locoperatorargs;;letmaybe_open~extension_kind~to_open:module_to_openexpr=letloc={expr.pexp_locwithloc_ghost=true}inifextension_kind.Extension_kind.do_openthenpexp_open~loc(open_infos~loc~override:Override~expr:(module_to_open~loc))exprelseexpr;;letexpand_let(moduleExt:Ext)~loc~modulbindingsbody=ifList.lengthbindings=0theninvalid_arg"expand_let: list of bindings must be non-empty";(* 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])inletfn=maybe_destruct~destruct:Ext.destruct~loc~modul~lhs:nested_patterns~bodyinbind_apply~op_name:Ext.name~loc~modul~with_location:Ext.with_location~arg:nested_boths~fn;;letexpand_match(moduleExt:Ext)~extension_kind~loc~modulexprcases=letexpr=maybe_open~extension_kind~to_open:(open_on_rhs~modul)exprinExt.expand_match~loc~modulexprcases;;letexpand_ift~extension_kind~loc~modulexprthen_else_=expand_matcht~extension_kind~loc~modulexpr[case~lhs:(pbool~loctrue)~guard:None~rhs:then_;case~lhs:(pbool~locfalse)~guard:None~rhs:else_];;letexpand_while(moduleExt:Ext)~extension_kind~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~op_name:Ext.name~loc~modul~with_location:Ext.with_location~arg:body~fn:eloopinletelse_=qualified_return~loc~modul(eunit~loc)inexpand_if(moduleExt)~extension_kind~modul~loccondthen_else_inletloop_func=pexp_fun~locNolabelNone(punit~loc)loop_bodyinpexp_let~locRecursive[value_binding~loc~pat:ploop~expr:loop_func]loop_call;;moduleMap:Ext=structletname="map"letwith_location=falseletdisallow_expression_=function|Pexp_while(_,_)->Error"while%%map is not supported. use while%%bind instead."|_->Ok();;letdestruct~assume_exhaustive:_~loc:_~modul:_~lhs:_~rhs:_~body:_=Noneletexpand_match~loc~modulexprcases=bind_apply~loc~modul~with_location~op_name:name~arg:expr~fn:(pexp_function~loccases);;endmoduleBind:Ext=structletname="bind"letwith_location=falseletdisallow_expression{Extension_kind.collapse_binds;_}=function|Pexp_while(_,_)whencollapse_binds->Error"while%%bindn is not supported. use while%%bind instead."|_->Ok();;letdestruct~assume_exhaustive:_~loc:_~modul:_~lhs:_~rhs:_~body:_=Noneletexpand_match~loc~modulexprcases=bind_apply~loc~modul~with_location~op_name:name~arg:expr~fn:(pexp_function~loccases);;endletvariables_of=objectinherit[stringPpxlib.loclist]Ast_traverse.foldassupermethod!patternpacc=letacc=super#patternpaccinmatchp.ppat_descwith|Ppat_varvar->var::acc|Ppat_alias(_,var)->var::acc|_->accend;;letpattern_variablespattern=List.dedup_and_sort~compare:(funxy->String.comparex.txty.txt)(variables_of#patternpattern[]);;typepat_exh={pat:pattern;assume_exhaustive:bool}letreplace_variable~f=letreplacer=objectinheritAst_traverse.mapassupermethod!patternp=letp=super#patternpinletloc={p.ppat_locwithloc_ghost=true}inmatchp.ppat_descwith|Ppat_varv->(matchfvwith|`Renametmpvar->ppat_var~loc{txt=tmpvar;loc=v.loc}|`Remove->ppat_any~loc)|Ppat_alias(sub,v)->(matchfvwith|`Renametmpvar->ppat_alias~locsub{txt=tmpvar;loc=v.loc}|`Remove->sub)|_->pendinreplacer#pattern;;letwith_warning_attributestrexpr=letloc=expr.pexp_locin{exprwithpexp_attributes=attribute~loc~name:(Loc.make~loc"ocaml.warning")~payload:(PStr[pstr_eval~loc(estring~locstr)[]])::expr.pexp_attributes};;letproject_bound_var~loc~modul~with_locationexp~pat:{pat;assume_exhaustive}var=letproject_the_var=(* We use a fresh var name because the compiler conflates all definitions with the
name * location, for the purpose of emitting warnings. *)lettmpvar=gen_symbol~prefix:"__pattern_syntax"()inletpattern=replace_variablepat~f:(funv->ifString.equalv.txtvar.txtthen`Renametmpvarelse`Remove)incase~lhs:pattern~guard:None~rhs:(evar~loctmpvar)inletfn=ifassume_exhaustivethenpexp_function~loc[project_the_var]elsewith_warning_attribute"-11"(* unused case warning *)(pexp_function~loc[project_the_var;catch_all_case~loc])inbind_apply~op_name:Map.name~loc~modul~with_location~arg:exp~fn;;letproject_bound_vars~loc~modul~with_locationexp~lhs=letloc={locwithloc_ghost=true}inletvariables=pattern_variableslhs.patinList.mapvariables~f:(funvar->{txt=(letexpr=project_bound_var~loc~modul~with_locationexp~pat:lhsvarinvalue_binding~loc~pat:(ppat_var~loc:var.locvar)~expr:(Merlin_helpers.hide_expressionexpr));loc});;letproject_pattern_variables~assume_exhaustive~modul~with_locationvbs=List.concat_mapvbs~f:(funvb->letloc={vb.pvb_locwithloc_ghost=true}inproject_bound_vars~loc~modul~with_locationvb.pvb_expr~lhs:{pat=vb.pvb_pat;assume_exhaustive});;letname_exprexpr=(* to avoid duplicating non-value expressions *)matchexpr.pexp_descwith|Pexp_ident_->[],expr|_->letloc={expr.pexp_locwithloc_ghost=true}inletvar=gen_symbol~prefix:"__pattern_syntax"()in[value_binding~loc~pat:(pvar~locvar)~expr],evar~locvar;;letcase_number~loc~modulexpindexed_cases=with_warning_attribute"-26-27"(* unused variable warnings *)(expand_match(moduleMap)~extension_kind:Extension_kind.default~loc~modulexp(List.mapindexed_cases~f:(fun(idx,case)->{casewithpc_rhs=eint~locidx})));;letexpand_case~destructexpr(idx,match_case)=letloc={match_case.pc_lhs.ppat_locwithloc_ghost=true}inletrhs=destruct~lhs:match_case.pc_lhs~rhs:expr~body:match_case.pc_rhs|>Option.value~default:(pexp_let~locNonrecursive[value_binding~loc~pat:match_case.pc_lhs~expr]match_case.pc_rhs)incase~lhs:(pint~locidx)~guard:None~rhs;;letcase_number_cases~loc~destructexpindexed_cases=List.mapindexed_cases~f:(expand_case~destructexp)@[catch_all_case~loc];;letindexed_match~loc~modul~destruct~switchexprcases=letexpr_binding,expr=name_exprexprinletindexed_cases=List.mapicases~f:(funidxcase->idx,case)inletcase_number=case_number~loc~modulexprindexed_casesinletassume_exhaustive=List.lengthcases<=1inletdestruct=destruct~assume_exhaustive~loc~modulinletcase_number_cases=case_number_cases~loc~destructexprindexed_casesinpexp_let~locNonrecursiveexpr_binding(switch~loc~modulcase_numbercase_number_cases);;moduleSub:Ext=structletname="sub"letwith_location=trueletdisallow_expression_=function(* It is worse to use let%sub...and instead of multiple let%sub in a row,
so disallow it. *)|Pexp_let(Nonrecursive,_::_::_,_)->Error"let%sub should not be used with 'and'."|Pexp_while(_,_)->Error"while%sub is not supported"|_->Ok();;letsub_return~loc~modul~lhs~rhs~body=letreturned_rhs=qualified_return~loc~modulrhsinbind_apply~op_name:name~loc~modul~with_location~arg:returned_rhs~fn:(pexp_funNolabelNone~loclhsbody);;letdestruct~assume_exhaustive~loc~modul~lhs~rhs~body=matchlhs.ppat_descwith|Ppat_var_->None|_->letbindings=[value_binding~loc~pat:lhs~expr:rhs]inletpattern_projections=project_pattern_variables~assume_exhaustive~modul~with_location:Map.with_locationbindingsinSome(matchpattern_projectionswith(* We handle the special case of having no pattern projections (which
means there were no variables to be projected) by projecting the
whole pattern once, just to ensure that the expression being
projected matches the pattern. We only do this when the pattern is
exhaustive, because otherwise the pattern matching is already
happening inside the [switch] call. *)|[]whenassume_exhaustive->letprojection_case=case~lhs~guard:None~rhs:(eunit~loc)inletfn=pexp_function~loc[projection_case]inletrhs=bind_apply~op_name:Map.name~loc~modul~with_location:Map.with_location~arg:rhs~fninsub_return~loc~modul~lhs:(ppat_any~loc)~rhs~body|_->List.foldpattern_projections~init:body~f:(funexpr{txt=binding;loc}->sub_return~loc~modul~lhs:binding.pvb_pat~rhs:binding.pvb_expr~body:expr));;letswitch~loc~modulcase_numbercase_number_cases=Merlin_helpers.hide_expression(pexp_apply~loc(eoperator~loc~modul"switch")[Labelled"match_",case_number;Labelled"branches",eint~loc(List.lengthcase_number_cases-1);Labelled"with_",pexp_function~loccase_number_cases]);;letexpand_match~loc~modulexpr=function|[]->assertfalse|[(case:case)]->letreturned_expr=qualified_return~loc~modulexprinletfn=maybe_destruct~destruct~loc~modul~lhs:case.pc_lhs~body:case.pc_rhsinbind_apply~op_name:name~loc~modul~with_location~arg:returned_expr~fn|cases->letvar_name=gen_symbol~prefix:"__pattern_syntax"()inletvar_expression=evar~locvar_nameinletvar_pattern=pvar~locvar_nameinletbody=indexed_match~loc~modul~destruct~switchvar_expressioncasesinsub_return~loc~modul~lhs:var_pattern~rhs:expr~body;;endmoduleArr:Ext=structletname="arr"letwith_location=trueletdisallow_expression_=function|Pexp_while(_,_)->Error"while%%arr is not supported."|_->Ok();;letdestruct~assume_exhaustive:_~loc:_~modul:_~lhs:_~rhs:_~body:_=Noneletexpand_match~loc~modulexprcases=bind_apply~loc~modul~with_location~op_name:name~arg:expr~fn:(pexp_function~loccases);;endletexpand(moduleExt:Ext)extension_kind~modulexpr=letloc={expr.pexp_locwithloc_ghost=true}inletexpansion=letexpr_desc=matchExt.disallow_expressionextension_kindexpr.pexp_descwith|Errormessage->Location.raise_errorf~loc"%s"message|Ok()->expr.pexp_descinmatchexpr_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_open~extension_kind~to_open:(open_on_rhs~modul)vb.pvb_expr})inletf=ifextension_kind.collapse_bindsthenexpand_letn(moduleExt)~modulelseexpand_let(moduleExt)~modulinexpand_with_tmp_vars~locbindingsexpr~f|Pexp_let(Recursive,_,_)->letext_full_name=ext_full_name(moduleExt)extension_kindinLocation.raise_errorf~loc"'let%%%s' may not be recursive"ext_full_name|Pexp_match(expr,cases)->expand_match(moduleExt)~extension_kind~loc~modulexprcases|Pexp_functioncases->lettemp_var=gen_symbol~prefix:"__let_syntax"()inlettemp_pattern=ppat_var~loc{txt=temp_var;loc}inlettemp_expr=pexp_ident~loc{txt=Lidenttemp_var;loc}inletmatch_expr=expand_match(moduleExt)~extension_kind~loc~modultemp_exprcasesinpexp_fun~locNolabelNonetemp_patternmatch_expr|Pexp_ifthenelse(expr,then_,else_)->letelse_=matchelse_with|Someelse_->else_|None->letext_full_name=ext_full_name(moduleExt)extension_kindinLocation.raise_errorf~loc"'if%%%s' must include an else branch"ext_full_nameinexpand_if(moduleExt)~extension_kind~loc~modulexprthen_else_|Pexp_while(cond,body)->expand_while(moduleExt)~extension_kind~loc~modul~cond~body|_->Location.raise_errorf~loc"'%%%s' can only be used with 'let', 'match', 'while', and 'if'"(ext_full_name(moduleExt)extension_kind)in{expansionwithpexp_attributes=expr.pexp_attributes@expansion.pexp_attributes};;letsub=(moduleSub:Ext)letmap=(moduleMap:Ext)letbind=(moduleBind:Ext)letarr=(moduleArr:Ext)