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