Legend:
Page
Library
Module
Module type
Parameter
Class
Class type
Source
Source file ppx_pattern_bind.ml
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506openBaseopenPpxlibopenAst_builder.DefaultopenPpx_let_expanderletlocality=`globalletpexp_let~locrec_bindingse=matchbindingswith|[]->e|_::_->pexp_let~locrec_bindingse;;letrecswap_constrained_alias_with_constrained_var_if_needed(pattern:pattern)=matchpattern.ppat_descwith|Ppat_alias(_,var)|Ppat_varvar->Some(ppat_var~loc:{pattern.ppat_locwithloc_ghost=true}var,var)|Ppat_constraint(inner,t)->(matchswap_constrained_alias_with_constrained_var_if_neededinnerwith|Some(inner,var)->Some(ppat_constraint~loc:{inner.ppat_locwithloc_ghost=true}innert,var)|None->None)|_->None;;letvariables_of=objectinherit[(pattern*stringloc)list]Ast_traverse.foldassupermethod!patternpacc=letacc=matchp.ppat_descwith|Ppat_varvar->(p,var)::acc|Ppat_alias(_,var)->(ppat_var~loc:var.locvar,var)::acc|Ppat_constraint_->(matchswap_constrained_alias_with_constrained_var_if_neededpwith|None->acc|Some(p,var)->(p,var)::acc)|_->accinsuper#patternpaccend;;letpattern_variablespattern=List.dedup_and_sort~compare:(fun(_,x)(_,y)->String.comparex.txty.txt)(variables_of#patternpattern[]);;letrecremove_constraint_from_var_or_aliaspattern=matchpattern.ppat_descwith|Ppat_constraint(({ppat_desc=Ppat_var_|Ppat_alias_;_}asinner),_)->Someinner|Ppat_constraint(inner,_)->(matchremove_constraint_from_var_or_aliasinnerwith|Someinner->Someinner|None->None)|_->None;;letconstraint_remover=objectinheritAst_traverse.mapassupermethod!patternpattern=letpattern=matchremove_constraint_from_var_or_aliaspatternwith|Somepattern->pattern|None->patterninsuper#patternpatternend;;letcatch_all_case~loc=case~lhs:(ppat_any~loc)~guard:None~rhs:(pexp_assert~loc(ebool~locfalse));;typepat_exh={pat:pattern;assume_exhaustive:bool}letextract_var_or_alias_pattern(pattern:pattern)~f=letrechelperpattern=matchpattern.ppat_descwith|Ppat_varvar|Ppat_alias(_,var)->Some(pattern,var)|Ppat_constraint(inner,_)->helperinner|_->Noneinmatchhelperpatternwith|Some(inner,x)->(matchfxwith|`Rename_->pattern|`Remove->inner)|None->pattern;;letreplace_variable~fx=letreplacer=objectinheritAst_traverse.mapassupermethod!patternp=letp=extract_var_or_alias_patternp~finletp=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#patternx;;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};;letcase_number~loc~modulexpindexed_cases=with_warning_attribute"-26-27"(* unused variable warnings *)(expand_matchPpx_let_expander.map~extension_kind:Extension_kind.default~loc~modul~localityexp(List.mapindexed_cases~f:(fun(idx,case)->{casewithpc_rhs=eint~locidx})));;letexpand_case~destructexpr(idx,match_case)=letrhs=letloc=expr.pexp_locindestruct~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](Merlin_helpers.focus_expressionmatch_case.pc_rhs))incase~lhs:(Merlin_helpers.hide_pattern(pint~loc:match_case.pc_lhs.ppat_locidx))~guard:None~rhs;;letcase_number_cases~loc~destructexpindexed_cases=List.mapindexed_cases~f:(expand_case~destructexp)@[catch_all_case~loc];;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[do_not_enter_value(value_binding~loc~pat:(pvar~locvar)~expr)],evar~locvar;;letindexed_match~loc~modul~destruct~switchexprcases=letfirst_case=List.hd_exncasesinletfirst_case_loc=first_case.pc_lhs.ppat_locinletswitch_loc={loc_ghost=true;loc_start=first_case_loc.loc_start;loc_end=loc.loc_end}inletexpr_binding,expr=name_exprexprinletindexed_cases=List.mapicases~f:(funidxcase->idx,case)inlethider=objectinheritAst_traverse.mapassupermethod!locationloc=super#location{locwithloc_ghost=true}endinletcase_number=hider#expression(constraint_remover#expression(case_number~loc~modulexprindexed_cases))inletassume_exhaustive=List.lengthcases<=1inletdestruct=destruct~assume_exhaustive~loc~modulinletcase_number_cases=case_number_cases~loc~destructexprindexed_casesinpexp_let~locNonrecursiveexpr_binding(switch~loc~switch_loc~modulcase_numbercase_number_cases);;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:{patternwithppat_loc={pattern.ppat_locwithloc_ghost=true}}~guard:None~rhs:(evar~loctmpvar)inletfn=ifassume_exhaustivethenpexp_function_cases~loc[project_the_var]elsewith_warning_attribute"-11"(* unused case warning *)(pexp_function_cases~loc[project_the_var;catch_all_case~loc])inletfn=constraint_remover#expressionfninbind_apply~prevent_tail_call:false~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:(fun(_,var)->{txt=(letexpr=project_bound_var~loc~modul~with_locationexp~pat:lhsvar()invalue_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});;moduletypeExt=sig(* The part that goes after [let%] and [match%]. If the name is
"pattern_bind", then [let%pattern_bind] and [match%pattern_bind] are
what get expanded. *)valname:string(* Given a list of variables bound to their corresponding "projection expression" (the
expression that maps the original expression to the variable's component),
[bind_pattern_projections] returns [rhs], possibly as the body of a [let] expression
bringing the input variables in scope. *)valbind_pattern_projections:loc:location->modul:longidentlocoption->value_bindinglist->rhs:expression->expression(* Produces a match-like expression (indeed, it could just be a [match] expression).
This function is not expected to destructure or transform the list of cases. *)valswitch:loc:location->switch_loc:location->modul:longidentlocoption->expression->caselist->expressionendtypet=(moduleExt)letgen_symbol_prefix="__pattern_syntax"letname_exprexpr=(* to avoid duplicating non-value expressions *)matchexpr.pexp_descwith|Pexp_ident_->[],expr|_->letloc={expr.pexp_locwithloc_ghost=true}inletvar=gen_symbol~prefix:gen_symbol_prefix()in[do_not_enter_value(value_binding~loc~pat:(pvar~locvar)~expr)],evar~locvar;;letswitch~loc~switch_loc:_~modulvaluecases=Ppx_let_expander.expandPpx_let_expander.bindPpx_let_expander.Extension_kind.default~modul~locality(Merlin_helpers.hide_expression(pexp_match~locvaluecases));;moduleBind:Ext=structletname="pattern_bind"letbind_pattern_projections~loc~modul:_projection_bindings~rhs=letloc={locwithloc_ghost=true}in(* For [let%pattern_bind], we don't bind on the match case, so nothing
constrains the resulting expression to be an incremental. We used to
generate [if false then return (assert false) else <expr>] to
compensate, but that causes problems with the defunctorized interface
of incremental, as [return] takes an extra argument. [if false then
map (assert false) ~f:Fn.id else <expr>] avoids that but causes type
errors in bonsai where they sort of abuse this preprocessor by using
this with this thing that's not a monad (see legacy_api.ml). *)pexp_let~locNonrecursiveprojection_bindingsrhs;;letswitch=switchendmoduleMap:Ext=structletname="pattern_map"letbind_pattern_projections~loc~modulprojection_bindings~rhs=letloc={locwithloc_ghost=true}inletlet_=pexp_let~locNonrecursiveprojection_bindingsrhsinmatchprojection_bindingswith|[]->Ppx_let_expander.qualified_return~loc~modulrhs|_::_->Ppx_let_expander.expandPpx_let_expander.mapPpx_let_expander.Extension_kind.default~modul~localitylet_;;letswitch=switchendletbind=(moduleBind:Ext)letmap=(moduleMap:Ext)leterror_if_invalid_pattern(moduleExt:Ext)pattern=letfinder=objectinheritAst_traverse.iterassupermethod!patternp=super#patternp;matchp.ppat_descwith|Ppat_unpack_->Location.raise_errorf~loc:p.ppat_loc"%%%s cannot be used with (module ..) patterns."Ext.name|Ppat_exception_->Location.raise_errorf~loc:p.ppat_loc"%%%s cannot be used with exception patterns."Ext.name|_->()endinfinder#patternpattern;;(* Translations for let%pattern_bind
let%pattern_bind (x, y, _) = e1
and { z; _} = e2
in exp
===>
let v1 = e1
and v2 = e2
in
let x = let%map (x, _, _) = v1 in x
and y = let%map (_, y, _) = v1 in y
and z = let%map { z; _} = v2 in z
in
exp
*)letsave_rhs_of_bindingsvbs=letsave_bindings,vbs=List.unzip(List.mapvbs~f:(funvb->letb,expr=name_exprvb.pvb_exprinb,{vbwithpvb_expr=expr}))inList.concatsave_bindings,vbs;;letexpand_let(moduleExt:Ext)~assume_exhaustive~loc~modulvbsrhs=List.itervbs~f:(funvb->error_if_invalid_pattern(moduleExt)vb.pvb_pat);letsave_bindings,vbs=save_rhs_of_bindingsvbsinvbs|>project_pattern_variables~assume_exhaustive~modul~with_location:false|>List.map~f:Loc.txt|>Ext.bind_pattern_projections~loc~modul~rhs|>pexp_letNonrecursive~locsave_bindings;;(* Translations for match%pattern_bind
{[
match%pattern_bind e with
| A x -> render_a x
| B (y, z) -> render_b (y, z)
]}
===>
{[
let exp = e in
match%bind
match%map exp with
| A _ -> 0
| B (_, _) -> 1
with
| 0 ->
let x =
match%map exp with
| A x -> x
| _ -> assert false
in
render_a x
| 1 ->
let y =
match%map exp with
| B (y, _) -> y
| _ -> assert false
and z =
match%map exp with
| B (_, z) -> z
| _ -> assert false
in
render_b (y, z)
| _ -> assert false
]}
and match%pattern_map is the same thing where the inner [lets] like
[let y = .. and z = ..] are let%map.
*)letexpand_match~modul(moduleExt:Ext)~locexprcases=letloc={locwithloc_ghost=true}inList.itercases~f:(fun{pc_lhs;pc_guard;_}->error_if_invalid_pattern(moduleExt)pc_lhs;matchpc_guardwith|None->()|Somev->(* We tried to support this, but ending up reverting (in 189712731a6): it seems
hard/impossible to have the desired warning and performance. *)Location.raise_errorf~loc:v.pexp_loc"%%%s cannot be used with `when`."Ext.name);letdestruct~assume_exhaustive~loc~modul~lhs~rhs~body=letbindings=[value_binding~loc~pat:lhs~expr:rhs]inSome(expand_let(moduleExt)~assume_exhaustive~loc~modulbindingsbody)inindexed_match~loc~modul~destruct~switch:Ext.switchexprcases;;letexpand(moduleExt:Ext)~modul~locexpr=matchexpr.pexp_descwith|Pexp_let(rec_flag,vbs,exp)->(matchrec_flagwith|Nonrecursive->()|Recursive->Location.raise_errorf~loc"%%%s cannot be used with 'let rec'"Ext.name);expand_let(moduleExt)~assume_exhaustive:true~loc~modulvbsexp|Pexp_match(expr,cases)->expand_match(moduleExt)~loc~modulexprcases|_->Location.raise_errorf~loc"'%%%s can only be used with 'let' and 'match'"Ext.name;;letextension(moduleExt:Ext)=Extension.declare_with_path_argExt.nameExtension.Context.expressionAst_pattern.(single_expr_payload__)(fun~loc~path:_~argexpr->expand(moduleExt)~modul:arg~locexpr);;let()=Driver.register_transformation"pattern"~extensions:[extensionbind;extensionmap];;