Practical Binary Pattern Matching
Pascal Brisset
pascal.brisset-ml@REDACTED
Wed Dec 4 16:20:29 CET 2002
Eric Newhuis writes:
> <<Attribute:2/big-unsigned-integer-unit:8, Length,
> Raw:Length/binary, Rest/binary>> -> ...
For some reason this is supported in the Erlang shell but not in
compiled modules.
Here is a quick hack which removes this limitation. We are using
it to compile an application with lots of <<Len, Val:Len/binary>>
patterns.
Hopefully this functionality will be added properly in a future
release.
-- Pascal Brisset [pascal.brisset@REDACTED] --
-- Cellicium | 157 r des Blains | F-92220 Bagneux --
diff -aur otp_src_P9-20020302-SNAPSHOT.orig/lib/compiler/src/v3_kernel.erl otp_src_P9-20020302-SNAPSHOT/lib/compiler/src/v3_kernel.erl
--- otp_src_P9-20020302-SNAPSHOT.orig/lib/compiler/src/v3_kernel.erl Mon Nov 12 15:02:43 2001
+++ otp_src_P9-20020302-SNAPSHOT/lib/compiler/src/v3_kernel.erl Mon Mar 4 12:55:12 2002
@@ -1046,26 +1046,45 @@
%% aliases as well.
match_clause([U|Us], T, Cs0, Def, St0) ->
- {Match,Vs,St1} = get_match(get_con(Cs0), St0),
+ %% FIXME: Not really sure how to get the substitution from Cs0.
+ BinSub = case Cs0 of
+ [#iclause{sub=BinSub_} | _] -> BinSub_;
+ _ -> []
+ end,
+ {Match,Vs,St1} = get_match(BinSub, get_con(Cs0), St0),
{Cs1,St2} = new_clauses(Cs0, U, St1),
{B,St3} = match(Vs ++ Us, Cs1, Def, St2),
{#k_val_clause{val=Match,body=B},St3}.
get_con([C|Cs]) -> arg_arg(clause_arg(C)). %Get the constructor
-get_match(#k_cons{}, St0) ->
+get_match(BinSub, #k_cons{}, St0) ->
{[H,T],St1} = new_vars(2, St0),
{#k_cons{hd=H,tl=T},[H,T],St1};
-get_match(M=#k_binary{}, St0) ->
+get_match(BinSub, M=#k_binary{}, St0) ->
{[V]=Mes,St1} = new_vars(1, St0),
{#k_binary{segs=V},Mes,St1};
-get_match(#k_bin_seg{}=Seg, St0) ->
+get_match(BinSub, #k_bin_seg{}=Seg, St0) ->
{[S,N]=Mes,St1} = new_vars(2, St0),
- {Seg#k_bin_seg{seg=S,next=N},Mes,St1};
-get_match(#k_tuple{es=Es}, St0) ->
+ %% Substitute the size if it is a var from a previous bin segment.
+ case Seg#k_bin_seg.size of
+ #k_var{name=SizeName}=Size ->
+ case lists:keysearch(SizeName, 1, BinSub) of
+ {value,{_,SizeName1}} ->
+ io:format("** Using the result of a previous pattern "
+ "in size=~p (experimental)~n", [SizeName]),
+ Size1 = Size#k_var{name=SizeName1},
+ {Seg#k_bin_seg{size=Size1,seg=S,next=N},Mes,St1};
+ _ ->
+ {Seg#k_bin_seg{seg=S,next=N},Mes,St1}
+ end;
+ _ ->
+ {Seg#k_bin_seg{seg=S,next=N},Mes,St1}
+ end;
+get_match(BinSub, #k_tuple{es=Es}, St0) ->
{Mes,St1} = new_vars(length(Es), St0),
{#k_tuple{es=Mes},Mes,St1};
-get_match(M, St) ->
+get_match(BinSub, M, St) ->
{M,[],St}.
new_clauses(Cs0, U, St) ->
diff -aur otp_src_P9-20020302-SNAPSHOT.orig/lib/stdlib/src/erl_lint.erl otp_src_P9-20020302-SNAPSHOT/lib/stdlib/src/erl_lint.erl
--- otp_src_P9-20020302-SNAPSHOT.orig/lib/stdlib/src/erl_lint.erl Thu Dec 20 13:28:41 2001
+++ otp_src_P9-20020302-SNAPSHOT/lib/stdlib/src/erl_lint.erl Mon Mar 4 09:52:08 2002
@@ -1549,7 +1549,10 @@
{[{V,{bound,binsize}}],
add_warning(Line, {exported_var,V,From}, St)};
error ->
- {[{V,{bound,used}}],add_error(Line, {unbound_var,V}, St)}
+ io:format("** Ignoring unbound variable ~p at line ~p in order"
+ " to allow extended bin patterns."
+ " Please fix erl_lint.~n", [V,Line]),
+ {[{V,{bound,used}}],St}
end.
%% expr_var(Variable, LineNo, VarTable, State) ->
More information about the erlang-questions
mailing list