aboutsummaryrefslogtreecommitdiffstats
path: root/lib/compiler/test/bs_match_SUITE.erl
diff options
context:
space:
mode:
authorErlang/OTP <[email protected]>2009-11-20 14:54:40 +0000
committerErlang/OTP <[email protected]>2009-11-20 14:54:40 +0000
commit84adefa331c4159d432d22840663c38f155cd4c1 (patch)
treebff9a9c66adda4df2106dfd0e5c053ab182a12bd /lib/compiler/test/bs_match_SUITE.erl
downloadotp-84adefa331c4159d432d22840663c38f155cd4c1.tar.gz
otp-84adefa331c4159d432d22840663c38f155cd4c1.tar.bz2
otp-84adefa331c4159d432d22840663c38f155cd4c1.zip
The R13B03 release.OTP_R13B03
Diffstat (limited to 'lib/compiler/test/bs_match_SUITE.erl')
-rw-r--r--lib/compiler/test/bs_match_SUITE.erl991
1 files changed, 991 insertions, 0 deletions
diff --git a/lib/compiler/test/bs_match_SUITE.erl b/lib/compiler/test/bs_match_SUITE.erl
new file mode 100644
index 0000000000..5c2797170b
--- /dev/null
+++ b/lib/compiler/test/bs_match_SUITE.erl
@@ -0,0 +1,991 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2005-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+-module(bs_match_SUITE).
+-compile(nowarn_shadow_vars).
+
+-export([all/1,init_per_testcase/2,fin_per_testcase/2,
+ fun_shadow/1,int_float/1,otp_5269/1,null_fields/1,wiger/1,
+ bin_tail/1,save_restore/1,shadowed_size_var/1,
+ partitioned_bs_match/1,function_clause/1,
+ unit/1,shared_sub_bins/1,bin_and_float/1,
+ dec_subidentifiers/1,skip_optional_tag/1,
+ wfbm/1,degenerated_match/1,bs_sum/1,coverage/1,
+ multiple_uses/1,zero_label/1,followed_by_catch/1,
+ matching_meets_construction/1,simon/1,matching_and_andalso/1,
+ otp_7188/1,otp_7233/1,otp_7240/1,otp_7498/1,
+ match_string/1,zero_width/1,bad_size/1,haystack/1]).
+
+-export([coverage_id/1]).
+
+-include("test_server.hrl").
+
+
+all(suite) ->
+ test_lib:recompile(?MODULE),
+ [fun_shadow,int_float,otp_5269,null_fields,wiger,bin_tail,save_restore,
+ shadowed_size_var,partitioned_bs_match,function_clause,unit,
+ shared_sub_bins,bin_and_float,dec_subidentifiers,skip_optional_tag,
+ wfbm,degenerated_match,bs_sum,coverage,multiple_uses,zero_label,
+ followed_by_catch,matching_meets_construction,simon,matching_and_andalso,
+ otp_7188,otp_7233,otp_7240,otp_7498,match_string,zero_width,bad_size,
+ haystack].
+
+init_per_testcase(Case, Config) when is_atom(Case), is_list(Config) ->
+ Dog = test_server:timetrap(?t:minutes(1)),
+ [{watchdog,Dog}|Config].
+
+fin_per_testcase(Case, Config) when is_atom(Case), is_list(Config) ->
+ Dog = ?config(watchdog, Config),
+ ?t:timetrap_cancel(Dog),
+ ok.
+
+fun_shadow(Config) when is_list(Config) ->
+ %% OTP-5270
+ ?line 7 = fun_shadow_1(),
+ ?line 7 = fun_shadow_2(8),
+ ?line 7 = fun_shadow_3(),
+ ?line no = fun_shadow_4(8),
+ ok.
+
+fun_shadow_1() ->
+ L = 8,
+ F = fun(<<L:L,B:L>>) -> B end,
+ F(<<16:8, 7:16>>).
+
+fun_shadow_2(L) ->
+ F = fun(<<L:L,B:L>>) -> B end,
+ F(<<16:8, 7:16>>).
+
+fun_shadow_3() ->
+ L = 8,
+ F = fun(<<L:L,B:L,L:L>>) -> B end,
+ F(<<16:8, 7:16,16:16>>).
+
+fun_shadow_4(L) ->
+ F = fun(<<L:L,B:L,L:L>>) -> B;
+ (_) -> no end,
+ F(<<16:8, 7:16,15:16>>).
+
+int_float(Config) when is_list(Config) ->
+ %% OTP-5323
+ ?line <<103133.0:64/float>> = <<103133:64/float>>,
+ ?line <<103133:64/float>> = <<103133:64/float>>,
+ ok.
+
+%% Stolen from erl_eval_SUITE and modified.
+%% OTP-5269. Bugs in the bit syntax.
+otp_5269(Config) when is_list(Config) ->
+ ?line check(fun() -> L = 8,
+ F = fun(<<A:L,B:A>>) -> B end,
+ F(<<16:8, 7:16>>)
+ end,
+ 7),
+ ?line check(fun() -> L = 8, <<A:L,B:A>> = <<16:8, 7:16>>, B end,
+ 7),
+ ?line check(fun() -> U = 8, (fun(<<U:U>>) -> U end)(<<32:8>>) end,
+ 32),
+ ?line check(fun() -> U = 8, [U || <<U:U>> <- [<<32:8>>]] end,
+ [32]),
+ ?line check(fun() -> [X || <<A:8,
+ B:A>> <- [<<16:8,19:16>>],
+ <<X:8>> <- [<<B:8>>]] end,
+ [19]),
+ ?line check(fun() -> A = 4, B = 28, bit_size(<<13:(A+(X=B))>>), X end,
+ 28),
+ ?line check(fun() ->
+ <<Size,B:Size/binary,Rest/binary>> = <<2,"AB","CD">>,
+ {Size,B,Rest}
+ end,
+ {2,<<"AB">>,<<"CD">>}),
+ ?line check(fun() -> X = 32,
+ [X || <<X:X>> <- [<<1:32>>,<<2:32>>,<<3:8>>]] end,
+ %% "binsize variable" ^
+ [1,2]),
+
+ ok.
+
+null_fields(Config) when is_list(Config) ->
+ ?line check(fun() ->
+ W = id(0),
+ F = fun(<<_:W>>) -> tail;
+ (<<>>) -> empty
+ end,
+ F(<<>>)
+ end, tail),
+ ?line check(fun() ->
+ F = fun(<<_/binary>>) -> tail;
+ (<<>>) -> empty
+ end,
+ F(<<>>)
+ end, tail),
+ ok.
+
+wiger(Config) when is_list(Config) ->
+ ?line ok1 = wcheck(<<3>>),
+ ?line ok2 = wcheck(<<1,2,3>>),
+ ?line ok3 = wcheck(<<4>>),
+ ?line {error,<<1,2,3,4>>} = wcheck(<<1,2,3,4>>),
+ ?line {error,<<>>} = wcheck(<<>>),
+ ok.
+
+wcheck(<<A>>) when A==3->
+ ok1;
+wcheck(<<_,_:2/binary>>) ->
+ ok2;
+wcheck(<<_>>) ->
+ ok3;
+wcheck(Other) ->
+ {error,Other}.
+
+bin_tail(Config) when is_list(Config) ->
+ S = <<"abcde">>,
+ ?line $a = bin_tail_c(S, 0),
+ ?line $c = bin_tail_c(S, 2),
+ ?line $e = bin_tail_c(S, 4),
+ ?line {'EXIT',_} = (catch bin_tail_c(S, 5)),
+ ?line {'EXIT',_} = (catch bin_tail_c_var(S, 5)),
+
+ ?line $a = bin_tail_d(S, 0),
+ ?line $b = bin_tail_d(S, 8),
+ ?line $d = bin_tail_d(S, 3*8),
+ ?line {'EXIT',_} = (catch bin_tail_d_dead(S, 1)),
+ ?line {'EXIT',_} = (catch bin_tail_d_dead(S, 9)),
+ ?line {'EXIT',_} = (catch bin_tail_d_dead(S, 5*8)),
+ ?line {'EXIT',_} = (catch bin_tail_d_var(S, 1)),
+
+ ?line ok = bin_tail_e(<<2:2,0:1,1:5>>),
+ ?line ok = bin_tail_e(<<2:2,1:1,1:5,42:64>>),
+ ?line error = bin_tail_e(<<3:2,1:1,1:5,42:64>>),
+ ?line error = bin_tail_e(<<>>),
+ ok.
+
+bin_tail_c(Bin, Offset) ->
+ Res = bin_tail_c_dead(Bin, Offset),
+ <<_:Offset/binary,_,Tail/binary>> = Bin,
+ {Res,Tail} = bin_tail_c_var(Bin, Offset),
+ Res.
+
+bin_tail_c_dead(Bin, Offset) ->
+ <<_:Offset/binary,C,_/binary>> = Bin,
+ C.
+
+bin_tail_c_var(Bin, Offset) ->
+ <<_:Offset/binary,C,Tail/binary>> = Bin,
+ {C,Tail}.
+
+
+bin_tail_d(Bin, BitOffset) ->
+ Res = bin_tail_d_dead(Bin, BitOffset),
+ <<_:BitOffset,_:8,Tail/binary>> = Bin,
+ {Res,Tail} = bin_tail_d_var(Bin, BitOffset),
+ Res.
+
+bin_tail_d_dead(Bin, BitOffset) ->
+ <<_:BitOffset,C,_/binary>> = Bin,
+ C.
+
+bin_tail_d_var(Bin, BitOffset) ->
+ <<_:BitOffset,C,Tail/binary>> = Bin,
+ {C,Tail}.
+
+bin_tail_e(Bin) ->
+ case bin_tail_e_dead(Bin) of
+ ok ->
+ <<_,Tail/binary>> = Bin,
+ Tail = bin_tail_e_var(Bin),
+ ok;
+ error ->
+ bin_tail_e_var(Bin)
+ end.
+
+bin_tail_e_dead(Bin) ->
+ case Bin of
+ %% The binary is aligned at the end; neither the bs_skip_bits2 nor
+ %% bs_test_tail2 instructions are needed.
+ <<2:2,_:1,1:5,_/binary>> -> ok;
+ _ -> error
+ end.
+
+bin_tail_e_var(Bin) ->
+ case Bin of
+ %% The binary is aligned at the end; neither the bs_skip_bits2 nor
+ %% bs_test_tail2 instructions are needed.
+ <<2:2,_:1,1:5,Tail/binary>> -> Tail;
+ _ -> error
+ end.
+
+save_restore(Config) when is_list(Config) ->
+ ?line 0 = save_restore_1(<<0:2,42:6>>),
+ ?line {1,3456} = save_restore_1(<<1:2,3456:14>>),
+ ?line {2,7981234} = save_restore_1(<<2:2,7981234:30>>),
+ ?line {3,763967493838} = save_restore_1(<<0:2,763967493838:62>>),
+
+ A = <<" x">>,
+ B = <<".x">>,
+ C = <<"-x">>,
+
+ ?line {" ",<<"x">>} = lll(A),
+ ?line {" ",<<"x">>} = mmm(A),
+ ?line {" ",<<"x">>} = nnn(A),
+ ?line {" ",<<"x">>} = ooo(A),
+
+ ?line {".",<<"x">>} = lll(B),
+ ?line {".",<<"x">>} = mmm(B),
+ ?line {".",<<"x">>} = nnn(B),
+ ?line {".",<<"x">>} = ooo(B),
+
+ ?line {"-",<<"x">>} = lll(C),
+ ?line {"-",<<"x">>} = mmm(C),
+ ?line {"-",<<"x">>} = nnn(C),
+ ?line {"-",<<"x">>} = ooo(C),
+
+ Bin = <<-1:64>>,
+ case bad_float_unpack_match(Bin) of
+ -1 -> ok;
+ _Other -> ?line ?t:fail(bad_return_value_probably_NaN)
+ end.
+
+save_restore_1(Bin) ->
+ case Bin of
+ <<0:2,_:6>> -> 0;
+ <<1:2,A:14>> -> {1,A};
+ <<2:2,A:30>> -> {2,A};
+ <<A:64>> -> {3,A}
+ end.
+
+lll(<<Char, Tail/binary>>) -> {[Char],Tail}.
+
+mmm(<<$.,$.,$., Tail/binary>>) -> Tail;
+mmm(<<$\s,$-,$\s, Tail/binary>>) -> Tail;
+mmm(<<Char, Tail/binary>>) -> {[Char],Tail}. %% Buggy Tail!
+
+nnn(<<"...", Tail/binary>>) -> Tail;
+nnn(<<" - ", Tail/binary>>) -> Tail;
+nnn(<<Char, Tail/binary>>) -> {[Char],Tail}. %% Buggy Tail!
+
+ooo(<<" - ", Tail/binary>>) -> Tail;
+ooo(<<Char, Tail/binary>>) -> {[Char],Tail}.
+
+bad_float_unpack_match(<<F:64/float>>) -> F;
+bad_float_unpack_match(<<I:64/integer-signed>>) -> I.
+
+
+shadowed_size_var(Config) when is_list(Config) ->
+ ?line PrivDir = ?config(priv_dir, Config),
+ ?line Dir = filename:dirname(code:which(?MODULE)),
+ ?line Core = filename:join(Dir, "bs_shadowed_size_var"),
+ ?line Opts = [from_core,{outdir,PrivDir}|test_lib:opt_opts(?MODULE)],
+ ?line io:format("~p", [Opts]),
+ ?line {ok,Mod} = c:c(Core, Opts),
+ ?line [42|<<"abcde">>] = Mod:filter_essentials([<<42:32>>|<<5:32,"abcde">>]),
+ ok.
+
+partitioned_bs_match(Config) when is_list(Config) ->
+ ?line <<1,2,3>> = partitioned_bs_match(blurf, <<42,1,2,3>>),
+ ?line error = partitioned_bs_match(10, <<7,8,15,13>>),
+ ?line error = partitioned_bs_match(100, {a,tuple,is,'not',a,binary}),
+ ?line ok = partitioned_bs_match(0, <<>>),
+ ?line {'EXIT',{function_clause,[{?MODULE,partitioned_bs_match,[-1,blurf]}|_]}} =
+ (catch partitioned_bs_match(-1, blurf)),
+ ?line {'EXIT',{function_clause,[{?MODULE,partitioned_bs_match,[-1,<<1,2,3>>]}|_]}} =
+ (catch partitioned_bs_match(-1, <<1,2,3>>)),
+
+ ?line {17,<<1,2,3>>} = partitioned_bs_match_2(1, <<17,1,2,3>>),
+ ?line {7,<<1,2,3>>} = partitioned_bs_match_2(7, <<17,1,2,3>>),
+ ?line {'EXIT',{function_clause,[{?MODULE,partitioned_bs_match_2,[4,<<0:17>>]}|_]}} =
+ (catch partitioned_bs_match_2(4, <<0:17>>)),
+ ok.
+
+partitioned_bs_match(_, <<42:8,T/binary>>) ->
+ T;
+partitioned_bs_match(N, _) when N > 0 ->
+ error;
+partitioned_bs_match(_, <<>>) ->
+ ok.
+
+partitioned_bs_match_2(1, <<B:8,T/binary>>) ->
+ {B,T};
+partitioned_bs_match_2(Len, <<_:8,T/binary>>) ->
+ {Len,T}.
+
+function_clause(Config) when is_list(Config) ->
+ ?line ok = function_clause_1(<<0,7,0,7,42>>),
+ ?line {'EXIT',{function_clause,
+ [{?MODULE,function_clause_1,[<<0,1,2,3>>]}|_]}} =
+ (catch function_clause_1(<<0,1,2,3>>)),
+ ?line {'EXIT',{function_clause,
+ [{?MODULE,function_clause_1,[<<0,1,2,3>>]}|_]}} =
+ (catch function_clause_1(<<0,7,0,1,2,3>>)),
+ ok.
+
+function_clause_1(<<0:8,7:8,T/binary>>) ->
+ function_clause_1(T);
+function_clause_1(<<_:8>>) ->
+ ok.
+
+unit(Config) when is_list(Config) ->
+ ?line 42 = peek1(<<42>>),
+ ?line 43 = peek1(<<43,1,2>>),
+ ?line 43 = peek1(<<43,1,2,(-1):1>>),
+ ?line 43 = peek1(<<43,1,2,(-1):2>>),
+ ?line 43 = peek1(<<43,1,2,(-1):7>>),
+
+ ?line 99 = peek8(<<99>>),
+ ?line 100 = peek8(<<100,101>>),
+ ?line {'EXIT',{function_clause,[{?MODULE,peek8,[<<100,101,0:1>>]}|_]}} =
+ (catch peek8(<<100,101,0:1>>)),
+
+ ?line 37484 = peek16(<<37484:16>>),
+ ?line 37489 = peek16(<<37489:16,5566:16>>),
+ ?line {'EXIT',{function_clause,[{?MODULE,peek16,[<<8>>]}|_]}} =
+ (catch peek16(<<8>>)),
+ ?line {'EXIT',{function_clause,[{?MODULE,peek16,[<<42:15>>]}|_]}} =
+ (catch peek16(<<42:15>>)),
+ ?line {'EXIT',{function_clause,[{?MODULE,peek16,[<<1,2,3,4,5>>]}|_]}} =
+ (catch peek16(<<1,2,3,4,5>>)),
+
+ ?line 127 = peek7(<<127:7>>),
+ ?line 100 = peek7(<<100:7,19:7>>),
+ ?line {'EXIT',{function_clause,[{?MODULE,peek7,[<<1,2>>]}|_]}} =
+ (catch peek7(<<1,2>>)),
+ ok.
+
+peek1(<<B:8,_/bitstring>>) -> B.
+
+peek7(<<B:7,_/binary-unit:7>>) -> B.
+
+peek8(<<B:8,_/binary>>) -> B.
+
+peek16(<<B:16,_/binary-unit:16>>) -> B.
+
+shared_sub_bins(Config) when is_list(Config) ->
+ ?line {15,[<<>>,<<5>>,<<4,5>>,<<3,4,5>>,<<2,3,4,5>>]} = sum(<<1,2,3,4,5>>, [], 0),
+ ok.
+
+sum(<<B,T/binary>>, Acc, Sum) ->
+ sum(T, [T|Acc], Sum+B);
+sum(<<>>, Last, Sum) -> {Sum,Last}.
+
+
+bin_and_float(Config) when is_list(Config) ->
+ ?line 14.0 = bin_and_float(<<1.0/float,2.0/float,3.0/float>>, 0.0),
+ ok.
+
+bin_and_float(<<X/float,Y/float,Z/float,T/binary>>, Sum) when is_float(X),
+ is_float(Y),
+ is_float(Z) ->
+ bin_and_float(T, Sum+X*X+Y*Y+Z*Z);
+bin_and_float(<<>>, Sum) -> Sum.
+
+dec_subidentifiers(Config) when is_list(Config) ->
+ ?line {[],<<1,2,3>>} =
+ do_dec_subidentifiers(<<1:1,42:7,1:1,99:7,1,2,3>>, 0, [], 2),
+ ?line {[5389],<<1,2,3>>} = do_dec_subidentifiers(<<1:1,42:7,0:1,13:7,1,2,3>>, 0, [], 2),
+ ?line {[3,2,1],not_a_binary} = dec_subidentifiers(not_a_binary, any, [1,2,3], 0),
+ ok.
+
+do_dec_subidentifiers(Buffer, Av, Al, Len) ->
+ Res = dec_subidentifiers(Buffer, Av, Al, Len),
+ Res = dec_subidentifiers2(Buffer, Av, Al, Len),
+ Res = dec_subidentifiers4(Buffer, Av, Al, Len),
+ Res = dec_subidentifiers3(Buffer, Av, Al, Len).
+
+dec_subidentifiers(Buffer, _Av, Al, 0) ->
+ {lists:reverse(Al),Buffer};
+dec_subidentifiers(<<1:1,H:7,T/binary>>, Av, Al, Len) ->
+ dec_subidentifiers(T, (Av bsl 7) bor H, Al, Len-1);
+dec_subidentifiers(<<H,T/binary>>, Av, Al, Len) ->
+ dec_subidentifiers(T, 0, [((Av bsl 7) bor H)|Al], Len-1).
+
+dec_subidentifiers2(<<Buffer/binary>>, _Av, Al, 0) ->
+ {lists:reverse(Al),Buffer};
+dec_subidentifiers2(<<1:1,H:7,T/binary>>, Av, Al, Len) ->
+ dec_subidentifiers2(T, (Av bsl 7) bor H, Al, Len-1);
+dec_subidentifiers2(<<H,T/binary>>, Av, Al, Len) ->
+ dec_subidentifiers2(T, 0, [((Av bsl 7) bor H)|Al], Len-1).
+
+dec_subidentifiers3(Buffer, _Av, Al, 0) when is_binary(Buffer) ->
+ {lists:reverse(Al),Buffer};
+dec_subidentifiers3(<<1:1,H:7,T/binary>>, Av, Al, Len) ->
+ dec_subidentifiers3(T, (Av bsl 7) bor H, Al, Len-1);
+dec_subidentifiers3(<<H,T/binary>>, Av, Al, Len) ->
+ dec_subidentifiers3(T, 0, [((Av bsl 7) bor H)|Al], Len-1).
+
+dec_subidentifiers4(<<1:1,H:7,T/binary>>, Av, Al, Len) when Len =/= 0 ->
+ dec_subidentifiers4(T, (Av bsl 7) bor H, Al, Len-1);
+dec_subidentifiers4(<<H,T/binary>>, Av, Al, Len) when Len =/= 0 ->
+ dec_subidentifiers4(T, 0, [((Av bsl 7) bor H)|Al], Len-1);
+dec_subidentifiers4(Buffer, _Av, Al, 0) ->
+ {lists:reverse(Al),Buffer}.
+
+
+skip_optional_tag(Config) when is_list(Config) ->
+ {ok,<<>>} = skip_optional_tag(<<42>>, <<42>>),
+ {ok,<<>>} = skip_optional_tag(<<42,1>>, <<42,1>>),
+ {ok,<<1,2,3>>} = skip_optional_tag(<<42>>, <<42,1,2,3>>),
+ missing = skip_optional_tag(<<2:3>>, blurf),
+ ok.
+
+skip_optional_tag(<<>>, Binary) ->
+ {ok,Binary};
+skip_optional_tag(<<Tag,RestTag/binary>>, <<Tag,Rest/binary>>) ->
+ skip_optional_tag(RestTag, Rest);
+skip_optional_tag(_, _) -> missing.
+
+-define(DATELEN, 16).
+
+wfbm(Config) when is_list(Config) ->
+ %% check_for_dot_or_space and get_tail is from wfbm4 by Steve Vinoski,
+ %% with modifications.
+ ?line {nomatch,0} = check_for_dot_or_space(<<" ">>),
+ ?line {nomatch,0} = check_for_dot_or_space(<<" abc">>),
+ ?line {ok,<<"abcde">>} = check_for_dot_or_space(<<"abcde 34555">>),
+ ?line {nomatch,0} = check_for_dot_or_space(<<".gurka">>),
+ ?line {nomatch,1} = check_for_dot_or_space(<<"g.urka">>),
+
+ ?line nomatch = get_tail(<<>>),
+ ?line {ok,<<"2007/10/23/blurf">>} = get_tail(<<"200x/2007/10/23/blurf ">>),
+ ?line {skip,?DATELEN+5} = get_tail(<<"200x/2007/10/23/blurf.">>),
+ ?line nomatch = get_tail(<<"200y.2007.10.23.blurf ">>),
+ ?line {'EXIT',_} = (catch get_tail({no,binary,at,all})),
+ ?line {'EXIT',_} = (catch get_tail(no_binary)),
+ ok.
+
+check_for_dot_or_space(Bin) ->
+ check_for_dot_or_space(Bin, 0).
+
+check_for_dot_or_space(<<$\s, _/binary>>, 0) ->
+ {nomatch,0};
+check_for_dot_or_space(Bin, Len) ->
+ case Bin of
+ <<Front:Len/binary, $\s, _/binary>> ->
+ {ok,Front};
+ <<_:Len/binary, $., _/binary>> ->
+ {nomatch,Len};
+ _ ->
+ check_for_dot_or_space(Bin, Len+1)
+ end.
+
+get_tail(<<>>) ->
+ nomatch;
+get_tail(Bin) ->
+ <<Front:?DATELEN/binary, Tail/binary>> = Bin,
+ case Front of
+ <<_:3/binary,"x/",Y:4/binary,$/,M:2/binary,$/,D:2/binary,$/>> ->
+ case check_for_dot_or_space(Tail) of
+ {ok,Match} ->
+ {ok,<<Y/binary,$/,M/binary,$/,D/binary,$/, Match/binary>>};
+ {nomatch,Skip} -> {skip,?DATELEN + Skip}
+ end;
+ _ -> nomatch
+ end.
+
+degenerated_match(Config) when is_list(Config) ->
+ ?line error = degenerated_match_1(<<>>),
+ ?line 1 = degenerated_match_1(<<1:1>>),
+ ?line 2 = degenerated_match_1(<<42,43>>),
+
+ ?line error = degenerated_match_2(<<>>),
+ ?line no_split = degenerated_match_2(<<1,2>>),
+ ?line {<<1,2,3,4>>,<<5>>} = degenerated_match_2(<<1,2,3,4,5>>),
+
+ ok.
+
+degenerated_match_1(<<>>) -> error;
+degenerated_match_1(Bin) -> byte_size(Bin).
+
+degenerated_match_2(<<>>) -> error;
+degenerated_match_2(Bin) ->
+ case byte_size(Bin) > 4 of
+ true ->
+ split_binary(Bin, 4);
+ false ->
+ no_split
+ end.
+
+bs_sum(Config) when is_list(Config) ->
+ ?line 0 = bs_sum_1([]),
+ ?line 0 = bs_sum_1(<<>>),
+ ?line 42 = bs_sum_1([42]),
+ ?line 1 = bs_sum_1(<<1>>),
+ ?line 10 = bs_sum_1([1,2,3,4]),
+ ?line 15 = bs_sum_1(<<1,2,3,4,5>>),
+ ?line 21 = bs_sum_1([1,2,3|<<4,5,6>>]),
+ ?line 15 = bs_sum_1([1,2,3|{4,5}]),
+ ?line 6 = bs_sum_1([1,2,3|zero]),
+ ?line 6 = bs_sum_1([1,2,3|0]),
+ ?line 7 = bs_sum_1([1,2,3|one]),
+
+ ?line {'EXIT',{function_clause,_}} = (catch bs_sum_1({too,big,tuple})),
+ ?line {'EXIT',{function_clause,_}} = (catch bs_sum_1([1,2,3|{too,big,tuple}])),
+
+ ?line [] = sneaky_alias(<<>>),
+ ?line [559,387655] = sneaky_alias(id(<<559:32,387655:32>>)),
+ ?line {'EXIT',{function_clause,[{?MODULE,sneaky_alias,[<<1>>]}|_]}} =
+ (catch sneaky_alias(id(<<1>>))),
+ ?line {'EXIT',{function_clause,[{?MODULE,sneaky_alias,[[1,2,3,4]]}|_]}} =
+ (catch sneaky_alias(lists:seq(1, 4))),
+ ok.
+
+bs_sum_1(<<H,T/binary>>) -> H+bs_sum_1(T);
+bs_sum_1([H|T]) -> H+bs_sum_1(T);
+bs_sum_1({A,B}=_Tuple=_AliasForNoGoodReason) -> A+B;
+bs_sum_1(0) -> 0;
+bs_sum_1(zero=_Zero) -> 0;
+bs_sum_1(one) -> 1;
+bs_sum_1([]) -> 0;
+bs_sum_1(<<>>) -> 0.
+
+sneaky_alias(<<>>=L) -> binary_to_list(L);
+sneaky_alias(<<From:32,L/binary>>) -> [From|sneaky_alias(L)].
+
+coverage(Config) when is_list(Config) ->
+ ?line 0 = coverage_fold(fun(B, A) -> A+B end, 0, <<>>),
+ ?line 6 = coverage_fold(fun(B, A) -> A+B end, 0, <<1,2,3>>),
+ ?line {'EXIT',{function_clause,_}} = (catch coverage_fold(fun(B, A) ->
+ A+B
+ end, 0, [a,b,c])),
+
+ ?line {<<>>,not_a_tuple} = coverage_build(<<>>, <<>>, not_a_tuple),
+ ?line {<<16#76,"abc",16#A9,"abc">>,{x,42,43}} =
+ coverage_build(<<>>, <<16#7,16#A>>, {x,y,z}),
+
+ ?line {x,<<"abc">>,z} = coverage_setelement(<<2,"abc">>, {x,y,z}),
+
+ ?line [42] = coverage_apply(<<42>>, [coverage_id]),
+
+ ?line do_coverage_bin_to_term_list([]),
+ ?line do_coverage_bin_to_term_list([lists:seq(0, 10),{a,b,c},<<23:42>>]),
+ ?line {'EXIT',{function_clause,
+ [{?MODULE,coverage_bin_to_term_list,[<<0,0,0,7>>]}|_]}} =
+ (catch do_coverage_bin_to_term_list_1(<<7:32>>)),
+
+ ?line <<>> = coverage_per_key(<<4:32>>),
+ ?line <<$a,$b,$c>> = coverage_per_key(<<7:32,"abc">>),
+
+ ok.
+
+coverage_fold(Fun, Acc, <<H,T/binary>>) ->
+ IdFun = fun id/1,
+ coverage_fold(Fun, Fun(IdFun(H), IdFun(Acc)), T);
+coverage_fold(Fun, Acc, <<>>) when is_function(Fun, 2) -> Acc.
+
+coverage_build(Acc0, <<H,T/binary>>, Tuple0) ->
+ Str = id(<<H:(id(4)),(H-1):4,"abc">>),
+ Acc = id(<<Acc0/bitstring,Str/bitstring>>),
+ Tuple = setelement(2, setelement(3, Tuple0, 43), 42),
+ if
+ byte_size(Acc) > 0 ->
+ coverage_build(Acc, T, Tuple)
+ end;
+coverage_build(Acc, <<>>, Tuple) -> {Acc,Tuple}.
+
+coverage_setelement(<<H,T1/binary>>, Tuple) when element(1, Tuple) =:= x ->
+ setelement(H, Tuple, T1).
+
+coverage_apply(<<H,T/binary>>, [F|Fs]) ->
+ [?MODULE:F(H)|coverage_apply(T, Fs)];
+coverage_apply(<<>>, []) -> [].
+
+coverage_id(I) -> id(I).
+
+do_coverage_bin_to_term_list(L) ->
+ Bin = << <<(begin BinTerm = term_to_binary(Term),
+ <<(byte_size(BinTerm)):32,BinTerm/binary>> end)/binary>> ||
+ Term <- L >>,
+ L = do_coverage_bin_to_term_list_1(Bin),
+ L = do_coverage_bin_to_term_list_1(<<Bin/binary,7:32,"garbage">>),
+ L = do_coverage_bin_to_term_list_1(<<7:32,"garbage",Bin/binary>>).
+
+do_coverage_bin_to_term_list_1(Bin) ->
+ Res = coverage_bin_to_term_list(Bin),
+ Res = coverage_bin_to_term_list(Bin, []),
+ Res = coverage_bin_to_term_list_catch(Bin),
+ Res = coverage_bin_to_term_list_catch(Bin, []).
+
+coverage_bin_to_term_list(<<Sz:32,BinTerm:Sz/binary,T/binary>>) ->
+ try binary_to_term(BinTerm) of
+ Term -> [Term|coverage_bin_to_term_list(T)]
+ catch
+ error:badarg -> coverage_bin_to_term_list(T)
+ end;
+coverage_bin_to_term_list(<<>>) -> [].
+
+coverage_bin_to_term_list(<<Sz:32,BinTerm:Sz/binary,T/binary>>, Acc) ->
+ try binary_to_term(BinTerm) of
+ Term -> coverage_bin_to_term_list(T, [Term|Acc])
+ catch
+ error:badarg -> coverage_bin_to_term_list(T, Acc)
+ end;
+coverage_bin_to_term_list(<<>>, Acc) -> lists:reverse(Acc).
+
+coverage_bin_to_term_list_catch(<<Sz:32,BinTerm:Sz/binary,T/binary>>) ->
+ case catch binary_to_term(BinTerm) of
+ {'EXIT',_} -> coverage_bin_to_term_list_catch(T);
+ Term -> [Term|coverage_bin_to_term_list_catch(T)]
+ end;
+coverage_bin_to_term_list_catch(<<>>) -> [].
+
+coverage_bin_to_term_list_catch(<<Sz:32,BinTerm:Sz/binary,T/binary>>, Acc) ->
+ case catch binary_to_term(BinTerm) of
+ {'EXIT',_} -> coverage_bin_to_term_list_catch(T, Acc);
+ Term -> coverage_bin_to_term_list_catch(T, [Term|Acc])
+ end;
+coverage_bin_to_term_list_catch(<<>>, Acc) -> lists:reverse(Acc).
+
+coverage_per_key(<<BinSize:32,Bin/binary>> = B) ->
+ true = (byte_size(B) =:= BinSize),
+ Bin.
+
+multiple_uses(Config) when is_list(Config) ->
+ ?line {344,62879,345,<<245,159,1,89>>} = multiple_uses_1(<<1,88,245,159,1,89>>),
+ ?line true = multiple_uses_2(<<0,0,197,18>>),
+ ?line <<42,43>> = multiple_uses_3(<<0,0,42,43>>, fun id/1),
+ ok.
+
+multiple_uses_1(<<X:16,Tail/binary>>) ->
+ %% NOT OPTIMIZED: sub binary is matched or used in more than one place
+ {Y,Z} = multiple_uses_match(Tail),
+ {X,Y,Z,Tail}.
+
+multiple_uses_2(<<_:16,Tail/binary>>) ->
+ %% NOT OPTIMIZED: sub binary is matched or used in more than one place
+ multiple_uses_cmp(Tail, Tail).
+
+multiple_uses_3(<<_:16,Tail/binary>>, Fun) ->
+ %% NOT OPTIMIZED: sub binary is used or returned
+ Fun(Tail).
+
+multiple_uses_match(<<Y:16,Z:16>>) ->
+ {Y,Z}.
+
+multiple_uses_cmp(<<Y:16>>, <<Y:16>>) -> true;
+multiple_uses_cmp(<<_:16>>, <<_:16>>) -> false.
+
+zero_label(Config) when is_list(Config) ->
+ ?line <<"nosemouth">> = read_pols(<<"FACE","nose","mouth">>),
+ ?line <<"CE">> = read_pols(<<"noFACE">>),
+ ok.
+
+read_pols(Data) ->
+ <<PolygonType:4/binary,Rest/binary>> = Data,
+ %% Intentional warning.
+ (PolygonType == <<"FACE">>) or (PolygonType == <<"PTCH">>),
+ Rest.
+
+followed_by_catch(Config) when is_list(Config) ->
+ ok = handle(<<0,1,2,3,4,5>>).
+
+-record(rec,{field}).
+handle(<<>>) -> ok;
+handle(Msg) ->
+ <<_DataLen:16, Rest/binary>> = Msg,
+ case catch fooX:func() of
+ [X] ->
+ X#rec.field;
+ _ ->
+ ok
+ end,
+ handle(Rest).
+
+matching_meets_construction(Config) when is_list(Config) ->
+ Bin = id(<<"abc">>),
+ Len = id(2),
+ Tail0 = id(<<1,2,3,4,5>>),
+ ?line <<_:Len/binary,Tail/binary>> = Tail0,
+ ?line Res = <<Tail/binary,Bin/binary>>,
+ ?line <<3,4,5,"abc">> = Res,
+ ?line {'EXIT',{badarg,_}} = (catch matching_meets_construction_1(<<"Abc">>)),
+ ?line {'EXIT',{badarg,_}} = (catch matching_meets_construction_2(<<"Abc">>)),
+ ?line <<"Bbc">> = matching_meets_construction_3(<<"Abc">>),
+
+ ?line <<1,2>> = encode_octet_string(<<1,2,3>>, 2),
+ ok.
+
+matching_meets_construction_1(<<"A",H/binary>>) -> <<"B",H>>.
+
+matching_meets_construction_2(<<"A",H/binary>>) -> <<"B",H/float>>.
+
+matching_meets_construction_3(<<"A",H/binary>>) -> <<"B",H/binary>>.
+
+encode_octet_string(<<OctetString/binary>>, Len) ->
+ <<OctetString:Len/binary-unit:8>>.
+
+simon(Config) when is_list(Config) ->
+ ?line one = simon(blurf, <<>>),
+ ?line two = simon(0, <<42>>),
+ ?line {'EXIT',{function_clause,[{?MODULE,simon,[17,<<1>>]}|_]}} = (catch simon(17, <<1>>)),
+ ?line {'EXIT',{function_clause,[{?MODULE,simon,[0,<<1,2,3>>]}|_]}} = (catch simon(0, <<1,2,3>>)),
+
+ ?line one = simon2(blurf, <<9>>),
+ ?line two = simon2(0, <<9,1>>),
+ ?line {'EXIT',{function_clause,[{?MODULE,simon2,[0,<<9,10,11>>]}|_]}} =
+ (catch simon2(0, <<9,10,11>>)),
+ ok.
+
+simon(_, <<>>) -> one;
+simon(0, <<_>>) -> two.
+
+simon2(_, <<9>>) -> one;
+simon2(0, <<_:16>>) -> two.
+
+
+%% OTP-7113: Crash in v3_codegen.
+matching_and_andalso(Config) when is_list(Config) ->
+ ?line ok = matching_and_andalso_1(<<1,2,3>>, 3),
+ ?line {'EXIT',{function_clause,_}} = (catch matching_and_andalso_1(<<1,2,3>>, -8)),
+ ?line {'EXIT',{function_clause,_}} = (catch matching_and_andalso_1(<<1,2,3>>, blurf)),
+ ?line {'EXIT',{function_clause,_}} = (catch matching_and_andalso_1(<<1,2,3>>, 19)),
+ ok.
+
+matching_and_andalso_1(<<Bitmap/binary>>, K)
+ when is_integer(K) andalso size(Bitmap) >= K andalso 0 < K ->
+ ok.
+
+%% Thanks to Tomas Stejskal.
+otp_7188(Config) when is_list(Config) ->
+ MP3 = <<84,65,71,68,117,154,105,232,107,121,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,68,97,110,105,101,108,32,76,
+ 97,110,100,97,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,66,
+ 101,115,116,32,79,102,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,50,48,48,48,50,48,48,48,32,45,32,66,101,115,
+ 116,32,79,102,32,32,32,32,32,32,32,32,32,32,32,32,32,32,
+ 32,32,12>>,
+ ?line {ok,{"ID3v1",
+ [{title,<<68,117,154,105,232,107,121>>},
+ {artist,<<"Daniel Landa">>},
+ {album,<<"Best Of">>}]}} = parse_v1_or_v11_tag(MP3).
+
+parse_v1_or_v11_tag(<<"TAG", Title:30/binary,
+ Artist:30/binary, Album:30/binary,
+ _Year:4/binary, _Comment:28/binary,
+ 0:8, Track:8, _Genre:8>>) ->
+ {ok,
+ {"ID3v1.1",
+ [{track, Track}, {title, trim(Title)},
+ {artist, trim(Artist)}, {album, trim(Album)}]}};
+parse_v1_or_v11_tag(<<"TAG", Title:30/binary,
+ Artist:30/binary, Album:30/binary,
+ _Year:4/binary, _Comment:30/binary,
+ _Genre:8>>) ->
+ {ok,
+ {"ID3v1",
+ [{title, trim(Title)},
+ {artist, trim(Artist)},
+ {album, trim(Album)}]}};
+parse_v1_or_v11_tag(_) ->
+ error.
+
+trim(Bin) ->
+ list_to_binary(trim_blanks(binary_to_list(Bin))).
+
+trim_blanks(L) ->
+ lists:reverse(skip_blanks_and_zero(lists:reverse(L))).
+
+skip_blanks_and_zero([$\s|T]) ->
+ skip_blanks_and_zero(T);
+skip_blanks_and_zero([0|T]) ->
+ skip_blanks_and_zero(T);
+skip_blanks_and_zero(L) ->
+ L.
+
+%% OTP-7233. Record and binary matching optimizations clashed.
+%% Thanks to Vladimir Klebansky.
+
+-record(rec_otp_7233, {key, val}).
+
+otp_7233(Config) when is_list(Config) ->
+ ?line otp_7233_1(#rec_otp_7233{key = <<"XXabcde">>,val=[{"xxxxxxxx",42}]}),
+ ?line [<<"XXabcde">>,{"xxxxxxxx",42}] = get(io_format),
+ erase(io_format),
+ ?line otp_7233_1(#rec_otp_7233{key = <<"XXabcde">>,val=[]}),
+ ?line undefined = get(io_format),
+ ok.
+
+otp_7233_1(Rec) ->
+ <<K:2/binary,_Rest:5/binary>> = Rec#rec_otp_7233.key,
+ case K of
+ <<"XX">> ->
+ Value = Rec#rec_otp_7233.val,
+ case lists:keysearch("xxxxxxxx", 1, Value) of
+ {value,T} -> put(io_format, [Rec#rec_otp_7233.key,T]);
+ false -> ok
+ end;
+ _ -> ok
+ end.
+
+
+otp_7240(Config) when is_list(Config) ->
+ ?line a = otp_7240_a(0, <<>>),
+ ?line b = otp_7240_a(1, 2),
+
+ ?line a = otp_7240_b(anything, <<>>),
+ ?line b = otp_7240_b(1, {x,y}),
+
+ ?line a = otp_7240_c(anything, <<>>),
+ ?line b = otp_7240_c(1, <<2>>),
+
+ ?line a = otp_7240_d(anything, <<>>),
+ ?line b = otp_7240_d(again, <<2>>),
+
+ ?line a = otp_7240_e(anything, <<>>),
+ ?line b = otp_7240_e(1, 41),
+
+ ?line a = otp_7240_f(anything, <<>>),
+ ?line b = otp_7240_f(1, {}),
+
+ ok.
+
+otp_7240_a(_, <<>>) -> a;
+otp_7240_a(1, 2) -> b.
+
+otp_7240_b(_, <<>>) -> a;
+otp_7240_b(1, {_,_}) -> b.
+
+otp_7240_c(_, <<>>) -> a;
+otp_7240_c(1, <<2>>) -> b.
+
+otp_7240_d(_, <<>>) -> a;
+otp_7240_d(_, <<2>>) -> b.
+
+otp_7240_e(_, <<>>) -> a;
+otp_7240_e(1, B) when B < 42 -> b.
+
+otp_7240_f(_, <<>>) -> a;
+otp_7240_f(1, B) when is_tuple(B) -> b.
+
+otp_7498(Config) when is_list(Config) ->
+ ?line <<1,2,3>> = otp_7498_foo(<<1,2,3>>, 0),
+ ?line <<2,3>> = otp_7498_foo(<<1,2,3>>, 1),
+ ?line <<1,2,3>> = otp_7498_foo(<<1,2,3>>, 2),
+
+ ?line <<1,2,3>> = otp_7498_bar(<<1,2,3>>, 0),
+ ?line <<2,3>> = otp_7498_bar(<<1,2,3>>, 1),
+ ?line <<1,2,3>> = otp_7498_bar(<<1,2,3>>, 2),
+ ?line <<>> = otp_7498_bar(<<>>, 2),
+ ?line <<1,2,3>> = otp_7498_bar(<<1,2,3>>, 3),
+
+ ok.
+
+otp_7498_foo(Bin, 0) ->
+ otp_7498_foo(Bin, 42);
+otp_7498_foo(<<_A, Rest/bitstring>>, 1) ->
+ otp_7498_foo(Rest, 43);
+otp_7498_foo(Bin, _I) ->
+ Bin.
+
+otp_7498_bar(Bin, 0) ->
+ otp_7498_bar(Bin, 42);
+otp_7498_bar(<<_A, Rest/bitstring>>, 1) ->
+ otp_7498_bar(Rest, 43);
+otp_7498_bar(<<>>, 2) ->
+ otp_7498_bar(<<>>, 44);
+otp_7498_bar(Bin, _I) ->
+ Bin.
+
+
+match_string(Config) when is_list(Config) ->
+ %% To make sure that native endian really is handled correctly
+ %% (i.e. that the compiler does not attempt to use bs_match_string/4
+ %% instructions for native segments), running this test is not enough.
+ %% Either examine the generated for do_match_string_native/1 or
+ %% check the coverage for the v3_kernel module.
+ case erlang:system_info(endian) of
+ little ->
+ ?line do_match_string_native(<<$a,0,$b,0>>);
+ big ->
+ ?line do_match_string_native(<<0,$a,0,$b>>)
+ end,
+
+ ?line do_match_string_big(<<0,$a,0,$b>>),
+ ?line do_match_string_little(<<$a,0,$b,0>>),
+
+ ?line do_match_string_big_signed(<<255,255>>),
+ ?line do_match_string_little_signed(<<255,255>>),
+
+ ?line plain = no_match_string_opt(<<"abc">>),
+ ?line strange = no_match_string_opt(<<$a:9,$b:9,$c:9>>),
+
+ ok.
+
+do_match_string_native(<<$a:16/native,$b:16/native>>) -> ok.
+
+do_match_string_big(<<$a:16/big,$b:16/big>>) -> ok.
+
+do_match_string_little(<<$a:16/little,$b:16/little>>) -> ok.
+
+do_match_string_big_signed(<<(-1):16/signed>>) -> ok.
+
+do_match_string_little_signed(<<(-1):16/little-signed>>) -> ok.
+
+no_match_string_opt(<<"abc">>) -> plain;
+no_match_string_opt(<<$a:9,$b:9,$c:9>>) -> strange.
+
+
+%% OTP-7591: A zero-width segment in matching would crash the compiler.
+
+zero_width(Config) when is_list(Config) ->
+ ?line <<Len:16/little, Str:Len/binary, 0:0>> = <<2, 0, $h, $i, 0:0>>,
+ ?line 2 = Len,
+ ?line Str = <<"hi">>,
+
+ %% Match sure that values that cannot fit in a segment will not match.
+ case id(<<0:8>>) of
+ <<256:8>> -> ?line ?t:fail();
+ _ -> ok
+ end,
+ ok.
+
+
+%% OTP_7650: A invalid size for binary segments could crash the compiler.
+bad_size(Config) when is_list(Config) ->
+ Tuple = {a,b,c},
+ ?line {'EXIT',{{badmatch,<<>>},_}} = (catch <<32:Tuple>> = id(<<>>)),
+ Binary = <<1,2,3>>,
+ ?line {'EXIT',{{badmatch,<<>>},_}} = (catch <<32:Binary>> = id(<<>>)),
+ ok.
+
+haystack(Config) when is_list(Config) ->
+ ?line <<0:10/unit:8>> = haystack_1(<<0:10/unit:8>>),
+ ?line [<<0:10/unit:8>>,
+ <<0:20/unit:8>>] = haystack_2(<<1:8192>>),
+ ok.
+
+%% Used to crash the compiler.
+haystack_1(Haystack) ->
+ Subs = [10],
+ [begin
+ <<B:Y/binary>> = Haystack,
+ B
+ end || Y <- Subs],
+ Haystack.
+
+%% There would be an incorrect badmatch exception.
+haystack_2(Haystack) ->
+ Subs = [{687,10},{369,20}],
+ [begin
+ <<_:X/binary,B:Y/binary,_/binary>> = Haystack,
+ B
+ end || {X,Y} <- Subs ].
+
+check(F, R) ->
+ R = F().
+
+id(I) -> I.