diff options
Diffstat (limited to 'lib/stdlib/test/ms_transform_SUITE.erl')
-rw-r--r-- | lib/stdlib/test/ms_transform_SUITE.erl | 730 |
1 files changed, 730 insertions, 0 deletions
diff --git a/lib/stdlib/test/ms_transform_SUITE.erl b/lib/stdlib/test/ms_transform_SUITE.erl new file mode 100644 index 0000000000..cf0926b7fa --- /dev/null +++ b/lib/stdlib/test/ms_transform_SUITE.erl @@ -0,0 +1,730 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2003-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(ms_transform_SUITE). +-author('[email protected]'). + +-include("test_server.hrl"). + +-export([all/1]). +-export([basic_ets/1]). +-export([basic_dbg/1]). +-export([from_shell/1]). +-export([records/1]). +-export([record_index/1]). +-export([multipass/1]). +-export([top_match/1]). +-export([old_guards/1]). +-export([autoimported/1]). +-export([semicolon/1]). +-export([bitsyntax/1]). +-export([record_defaults/1]). +-export([andalso_orelse/1]). +-export([float_1_function/1]). +-export([action_function/1]). +-export([init_per_testcase/2, fin_per_testcase/2]). + +init_per_testcase(_Func, Config) -> + Dog=test_server:timetrap(test_server:seconds(360)), + [{watchdog, Dog}|Config]. + +fin_per_testcase(_Func, Config) -> + Dog=?config(watchdog, Config), + test_server:timetrap_cancel(Dog). + +all(suite) -> [from_shell,basic_ets,basic_dbg,records,record_index,multipass, + bitsyntax, record_defaults, andalso_orelse, + float_1_function, action_function, + top_match, old_guards, autoimported, semicolon]. + +andalso_orelse(suite) -> + []; +andalso_orelse(doc) -> + ["Tests that andalso and orelse are allowed in guards."]; +andalso_orelse(Config) when list(Config) -> + ?line setup(Config), + ?line [{{'$1','$2'}, + [{'and',{is_integer,'$1'},{'>',{'+','$1',5},'$2'}}], + [{'andalso','$1','$2'}]}] = + compile_and_run(<<"ets:fun2ms(fun({A,B}) " + " when is_integer(A) and (A+5 > B) -> " + " A andalso B " + " end)">>), + ?line [{{'$1','$2'}, + [{'or',{is_atom,'$1'},{'>',{'+','$1',5},'$2'}}], + [{'orelse','$1','$2'}]}] = + compile_and_run(<<"ets:fun2ms(fun({A,B}) " + " when is_atom(A) or (A+5 > B) -> " + " A orelse B " + " end)">>), + ?line [{{'$1','$2'}, + [{'andalso',{is_integer,'$1'},{'>',{'+','$1',5},'$2'}}], + ['$1']}] = + compile_and_run( + <<"ets:fun2ms(fun({A,B}) when is_integer(A) andalso (A+5 > B) ->" + " A " + " end)">>), + ?line [{{'$1','$2'}, + [{'orelse',{is_atom,'$1'},{'>',{'+','$1',5},'$2'}}], + ['$1']}] = + compile_and_run( + <<"ets:fun2ms(fun({A,B}) when is_atom(A) orelse (A+5 > B) -> " + " A " + " end)">>), + ok. + + +bitsyntax(suite) -> + []; +bitsyntax(doc) -> + ["Tests that bitsyntax works and does not work where appropriate"]; +bitsyntax(Config) when list(Config) -> + ?line setup(Config), + ?line [{'_',[], + [<<0,27,0,27>>]}] = + compile_and_run(<<"A = 27, " + "ets:fun2ms(fun(_) -> <<A:16,27:16>> end)">>), + ?line [{{<<15,47>>, + '$1', + '$2'}, + [{'=:=','$1', + <<0,27>>}, + {'=:=','$2', + <<27,28,19>>}], + [<<188,0,13>>]}] = + compile_and_run(<<"A = 27, " + "ets:fun2ms(" + " fun({<<15,47>>,B,C}) " + " when B =:= <<A:16>>, C =:= <<27,28,19>> -> " + " <<A:4,12:4,13:16>> " + " end)">>), + ?line expect_failure( + <<>>, + <<"ets:fun2ms(fun({<<15,47>>,B,C}) " + " when B =:= <<16>>, C =:= <<27,28,19>> -> " + " <<B:4,12:4,13:16>> " + " end)">>), + ?line expect_failure( + <<>>, + <<"ets:fun2ms(fun({<<A:15,47>>,B,C}) " + " when B =:= <<16>>, C =:= <<27,28,19>> -> " + " <<B:4,12:4,13:16>> " + " end)">>), + ok. + +record_defaults(suite) -> + []; +record_defaults(doc) -> + ["Tests that record defaults works"]; +record_defaults(Config) when list(Config) -> + ?line setup(Config), + ?line [{{<<27>>,{a,5,'$1',hej,hej}}, + [], + [{{a,hej,{'*','$1',2},flurp,flurp}}]}] = + compile_and_run(<<"-record(a,{a,b,c,d=foppa}).">>, + <<"ets:fun2ms(fun({<<27>>,#a{a=5, b=B,_=hej}}) -> " + "#a{a=hej,b=B*2,_=flurp} " + "end)">>), + ok. + +basic_ets(suite) -> + []; +basic_ets(doc) -> + ["Tests basic ets:fun2ms"]; +basic_ets(Config) when list(Config) -> + ?line setup(Config), + ?line [{{a,b},[],[true]}] = compile_and_run( + <<"ets:fun2ms(fun({a,b}) -> true end)">>), + ?line [{{'$1',foo},[{is_list,'$1'}],[{{{hd,'$1'},'$_'}}]}, + {{'$1','$1'},[{is_tuple,'$1'}],[{{{element,1,'$1'},'$*'}}]}] = + compile_and_run(<<"ets:fun2ms(fun({X,foo}) when is_list(X) -> ", + "{hd(X),object()};", + "({X,X}) when is_tuple(X) ->", + "{element(1,X),bindings()}", + "end)">>), + ?line [{{'$1','$2'},[],[{{'$2','$1'}}]}] = + compile_and_run(<<"ets:fun2ms(fun({A,B}) -> {B,A} end)">>), + ?line [{{'$1','$2'},[],[['$2','$1']]}] = + compile_and_run(<<"ets:fun2ms(fun({A,B}) -> [B,A] end)">>), + ok. + +basic_dbg(suite) -> + []; +basic_dbg(doc) -> + ["Tests basic ets:fun2ms"]; +basic_dbg(Config) when list(Config) -> + ?line setup(Config), + ?line [{[a,b],[],[{message,banan},{return_trace}]}] = + compile_and_run(<<"dbg:fun2ms(fun([a,b]) -> message(banan), ", + "return_trace() end)">>), + ?line [{['$1','$2'],[],[{{'$2','$1'}}]}] = + compile_and_run(<<"dbg:fun2ms(fun([A,B]) -> {B,A} end)">>), + ?line [{['$1','$2'],[],[['$2','$1']]}] = + compile_and_run(<<"dbg:fun2ms(fun([A,B]) -> [B,A] end)">>), + ?line [{['$1','$2'],[],['$*']}] = + compile_and_run(<<"dbg:fun2ms(fun([A,B]) -> bindings() end)">>), + ?line [{['$1','$2'],[],['$_']}] = + compile_and_run(<<"dbg:fun2ms(fun([A,B]) -> object() end)">>), + ok. + +from_shell(suite) -> + []; +from_shell(doc) -> + ["Test calling of ets/dbg:fun2ms from the shell"]; +from_shell(Config) when list(Config) -> + ?line setup(Config), + ?line Fun = do_eval("fun({a,b}) -> true end"), + ?line [{{a,b},[],[true]}] = apply(ets,fun2ms,[Fun]), + ?line [{{a,b},[],[true]}] = do_eval("ets:fun2ms(fun({a,b}) -> true end)"), + ?line Fun2 = do_eval("fun([a,b]) -> message(banan), return_trace() end"), + ?line [{[a,b],[],[{message,banan},{return_trace}]}] + = apply(dbg,fun2ms,[Fun2]), + ?line [{[a,b],[],[{message,banan},{return_trace}]}] = + do_eval( + "dbg:fun2ms(fun([a,b]) -> message(banan), return_trace() end)"), + ok. + +records(suite) -> + []; +records(doc) -> + ["Tests expansion of records in fun2ms"]; +records(Config) when list(Config) -> + ?line setup(Config), + ?line RD = <<"-record(t, {" + "t1 = []," + "t2 = foo," + "t3," + "t4" + "}).">>, + ?line [{{t,'$1','$2',foo,'_'},[{is_list,'$1'}],[{{{hd,'$1'},'$_'}}]}, + {{t,'_','_','_','_'},[{'==',{element,2,'$_'},nisse}],[{{'$*'}}]}] = + compile_and_run(RD,<< + "ets:fun2ms(fun(#t{t1 = X, t2 = Y, t3 = foo}) when is_list(X) -> + {hd(X),object()}; + (#t{}) when (object())#t.t1 == nisse -> + {bindings()} + end)">>), + ?line [{{t,'$1','$2','_',foo}, + [{'==',{element,4,'$_'},7},{is_list,'$1'}], + [{{{hd,'$1'},'$_'}}]}, + {'$1',[{is_record,'$1',t,5}], + [{{{element,2,'$1'}, + {{t,'$1',foo,undefined,undefined}}, + {{t,{element,2,'$1'},{element,3,'$1'},{element,4,'$1'},boooo}}}}]}] = + compile_and_run(RD,<< + "ets:fun2ms(fun(#t{t1 = X, t2 = Y, t4 = foo}) when + (object())#t.t3==7,is_list(X) -> + {hd(X),object()}; + (A) when is_record(A,t) -> + {A#t.t1 + ,#t{t1=A} + ,A#t{t4=boooo} + } + end)" + >>), + ?line [{[{t,'$1','$2',foo,'_'}],[{is_list,'$1'}],[{{{hd,'$1'},'$_'}}]}, + {[{t,'_','_','_','_'}],[{'==',{element,2,{hd,'$_'}},nisse}],[{{'$*'}}]}]= + compile_and_run(RD,<< + "dbg:fun2ms(fun([#t{t1 = X, t2 = Y, t3 = foo}]) when is_list(X) -> + {hd(X),object()}; + ([#t{}]) when (hd(object()))#t.t1 == nisse -> + {bindings()} + end)" + >>), + ok. + + +record_index(suite) -> + []; +record_index(doc) -> + ["Tests expansion of records in fun2ms, part 2"]; +record_index(Config) when list(Config) -> + ?line setup(Config), + ?line RD = <<"-record(a,{a,b}).">>, + ?line [{{2},[],[true]}] = compile_and_run(RD, + <<"ets:fun2ms(fun({#a.a}) -> true end)">>), + ?line [{{2},[],[2]}] = compile_and_run(RD, + <<"ets:fun2ms(fun({#a.a}) -> #a.a end)">>), + ?line [{{2,'$1'},[{'>','$1',2}],[2]}] = compile_and_run(RD, + <<"ets:fun2ms(fun({#a.a,A}) when A > #a.a -> #a.a end)">>), + ok. + +top_match(suite) -> + []; +top_match(doc) -> + ["Tests matching on top level in head to give alias for object()"]; +top_match(Config) when list(Config) -> + ?line setup(Config), + ?line RD = <<"-record(a,{a,b}).">>, + ?line [{{a,3,'_'},[],['$_']}] = + compile_and_run(RD, + <<"ets:fun2ms(fun(A = #a{a=3}) -> A end)">>), + ?line [{{a,3,'_'},[],['$_']}] = + compile_and_run(RD, + <<"ets:fun2ms(fun(#a{a=3} = A) -> A end)">>), + ?line [{[a,b],[],['$_']}] = + compile_and_run(RD, + <<"dbg:fun2ms(fun(A = [a,b]) -> A end)">>), + ?line [{[a,b],[],['$_']}] = + compile_and_run(RD, + <<"dbg:fun2ms(fun([a,b] = A) -> A end)">>), + ?line expect_failure(RD, + <<"ets:fun2ms(fun({a,A = {_,b}}) -> A end)">>), + ?line expect_failure(RD, + <<"dbg:fun2ms(fun([a,A = {_,b}]) -> A end)">>), + ?line expect_failure(RD, + <<"ets:fun2ms(fun(A#a{a = 2}) -> A end)">>), + ok. + +multipass(suite) -> + []; +multipass(doc) -> + ["Tests that multi-defined fields in records give errors."]; +multipass(Config) when list(Config) -> + ?line setup(Config), + ?line RD = <<"-record(a,{a,b}).">>, + ?line expect_failure(RD,<<"ets:fun2ms(fun(A) -> #a{a=2,a=3} end)">>), + ?line expect_failure(RD,<<"ets:fun2ms(fun(A) -> A#a{a=2,a=3} end)">>), + ?line expect_failure(RD,<<"ets:fun2ms(fun(A) when A =:= #a{a=2,a=3} ->", + " true end)">>), + ?line expect_failure(RD,<<"ets:fun2ms(fun({A,B})when A =:= B#a{a=2,a=3}->", + "true end)">>), + ?line expect_failure(RD,<<"ets:fun2ms(fun(#a{a=3,a=3}) -> true end)">>), + ?line compile_and_run(RD,<<"ets:fun2ms(fun(A) -> #a{a=2,b=3} end)">>), + ?line compile_and_run(RD,<<"ets:fun2ms(fun(A) -> A#a{a=2,b=3} end)">>), + ?line compile_and_run(RD,<<"ets:fun2ms(fun(A) when A =:= #a{a=2,b=3} ->", + " true end)">>), + ?line compile_and_run(RD,<<"ets:fun2ms(fun({A,B})when A=:= B#a{a=2,b=3}->", + "true end)">>), + ?line compile_and_run(RD,<<"ets:fun2ms(fun(#a{a=3,b=3}) -> true end)">>), + ok. + + +old_guards(suite) -> + []; +old_guards(doc) -> + ["Tests that old type tests in guards are translated"]; +old_guards(Config) when list(Config) -> + ?line setup(Config), + Tests = [ + {atom,is_atom}, + {constant,is_constant}, + {float,is_float}, + {integer,is_integer}, + {list,is_list}, + {number,is_number}, + {pid,is_pid}, + {port,is_port}, + {reference,is_reference}, + {tuple,is_tuple}, + {binary,is_binary}, + {function,is_function}], + ?line lists:foreach( + fun({Old,New}) -> + Bin = list_to_binary([<<"ets:fun2ms(fun(X) when ">>, + atom_to_list(Old), + <<"(X) -> true end)">>]), + case compile_and_run(Bin) of + [{'$1',[{New,'$1'}],[true]}] -> + ok; + _ -> + exit({bad_result_for, binary_to_list(Bin)}) + end + end, + Tests), + ?line RD = <<"-record(a,{a,b}).">>, + ?line [{'$1',[{is_record,'$1',a,3}],[true]}] = + compile_and_run(RD, + <<"ets:fun2ms(fun(X) when record(X,a) -> true end)">>), + ?line expect_failure + (RD, + <<"ets:fun2ms(fun(X) when integer(X) and constant(X) -> " + "true end)">>), + ?line [{'$1',[{is_integer,'$1'}, + {is_float,'$1'}, + {is_atom,'$1'}, + {is_constant,'$1'}, + {is_list,'$1'}, + {is_number,'$1'}, + {is_pid,'$1'}, + {is_port,'$1'}, + {is_reference,'$1'}, + {is_tuple,'$1'}, + {is_binary,'$1'}, + {is_record,'$1',a,3}], + [true]}] = + compile_and_run(RD, << + "ets:fun2ms(fun(X) when integer(X)," + "float(X), atom(X), constant(X)," + "list(X), number(X), pid(X)," + "port(X), reference(X), tuple(X)," + "binary(X), record(X,a) -> true end)" + >>), + ok. + +autoimported(suite) -> + []; +autoimported(doc) -> + ["Tests use of autoimported bif's used like erlang:'+'(A,B) in guards" + " and body."]; +autoimported(Config) when list(Config) -> + ?line setup(Config), + Allowed = [ + {abs,1}, + {element,2}, + {hd,1}, + {length,1}, + {node,0}, + {node,1}, + {round,1}, + {size,1}, + {tl,1}, + {trunc,1}, + {self,0}, + %{float,1}, see float_1_function/1 + {is_atom,1}, + {is_constant,1}, + {is_float,1}, + {is_integer,1}, + {is_list,1}, + {is_number,1}, + {is_pid,1}, + {is_port,1}, + {is_reference,1}, + {is_tuple,1}, + {is_binary,1}, + {is_function,1}, + {is_record,2,magic}, + {'and',2,infix}, + {'or',2,infix}, + {'xor',2,infix}, + {'not',1}, + %{'andalso',2,infix}, + %{'orelse',2,infix}, + {'+',1}, + {'+',2,infix}, + {'-',1}, + {'-',2,infix}, + {'*',2,infix}, + {'/',2,infix}, + {'div',2,infix}, + {'rem',2,infix}, + {'band',2,infix}, + {'bor',2,infix}, + {'bxor',2,infix}, + {'bnot',1}, + {'bsl',2,infix}, + {'bsr',2,infix}, + {'>',2,infix}, + {'>=',2,infix}, + {'<',2,infix}, + {'=<',2,infix}, + {'==',2,infix}, + {'=:=',2,infix}, + {'/=',2,infix}, + {'=/=',2,infix}], + ?line RD = <<"-record(a,{a,b}).">>, + ?line lists:foreach( + fun({A,0}) -> + L = atom_to_list(A), + Bin1 = list_to_binary( + [ + <<"ets:fun2ms(fun(X) when ">>, + L,<<"() -> ">>, + L,<<"() end)">> + ]), + Bin2 = list_to_binary( + [ + <<"ets:fun2ms(fun(X) when erlang:'">>, + L,<<"'() -> erlang:'">>, + L,<<"'() end)">> + ]), + Res1 = compile_and_run(Bin1), + Res2 = compile_and_run(Bin2), + case Res1 =:= Res2 of + true -> + ok; + false -> + exit({not_equal,{Res1,Res2,A}}) + end; + ({A,1}) -> + L = atom_to_list(A), + Bin1 = list_to_binary( + [ + <<"ets:fun2ms(fun(X) when ">>, + L,<<"(X) -> ">>, + L,<<"(X) end)">> + ]), + Bin2 = list_to_binary( + [ + <<"ets:fun2ms(fun(X) when erlang:'">>, + L,<<"'(X) -> erlang:'">>, + L,<<"'(X) end)">> + ]), + Res1 = compile_and_run(Bin1), + Res2 = compile_and_run(Bin2), + case Res1 =:= Res2 of + true -> + ok; + false -> + exit({not_equal,{Res1,Res2,A}}) + end; + ({A,2}) -> + L = atom_to_list(A), + Bin1 = list_to_binary( + [ + <<"ets:fun2ms(fun({X,Y}) when ">>, + L,<<"(X,Y) -> ">>, + L,<<"(X,Y) end)">> + ]), + Bin2 = list_to_binary( + [ + <<"ets:fun2ms(fun({X,Y}) when erlang:'">>, + L,<<"'(X,Y) -> erlang:'">>, + L,<<"'(X,Y) end)">> + ]), + Res1 = compile_and_run(Bin1), + Res2 = compile_and_run(Bin2), + case Res1 =:= Res2 of + true -> + ok; + false -> + exit({not_equal,{Res1,Res2,A}}) + end; + ({A,2,infix}) -> + L = atom_to_list(A), + Bin1 = list_to_binary( + [ + <<"ets:fun2ms(fun({X,Y}) when X ">>, + L,<<" Y -> X ">>, + L,<<" Y end)">> + ]), + Bin2 = list_to_binary( + [ + <<"ets:fun2ms(fun({X,Y}) when erlang:'">>, + L,<<"'(X,Y) -> erlang:'">>, + L,<<"'(X,Y) end)">> + ]), + Res1 = compile_and_run(Bin1), + Res2 = compile_and_run(Bin2), + case Res1 =:= Res2 of + true -> + ok; + false -> + exit({not_equal,{Res1,Res2,A}}) + end; + ({A,2,magic}) -> %is_record + L = atom_to_list(A), + Bin1 = list_to_binary( + [ + <<"ets:fun2ms(fun(X) when ">>, + L,<<"(X,a) -> ">>, + L,<<"(X,a) end)">> + ]), + Bin2 = list_to_binary( + [ + <<"ets:fun2ms(fun(X) when erlang:'">>, + L,<<"'(X,a) -> erlang:'">>, + L,<<"'(X,a) end)">> + ]), + Res1 = compile_and_run(RD,Bin1), + Res2 = compile_and_run(RD,Bin2), + case Res1 =:= Res2 of + true -> + ok; + false -> + exit({not_equal,{Res1,Res2,A}}) + end + end, + Allowed), + ok. + +semicolon(suite) -> + []; +semicolon(doc) -> + ["Tests semicolon in guards of match_specs."]; +semicolon(Config) when is_list(Config) -> + ?line setup(Config), + ?line Res01 = compile_and_run + (<<"ets:fun2ms(fun(X) when is_integer(X); " + "is_float(X) -> true end)">>), + ?line Res02 = compile_and_run + (<<"ets:fun2ms(fun(X) when is_integer(X) -> true; " + "(X) when is_float(X) -> true end)">>), + ?line Res01 = Res02, + ?line Res11 = compile_and_run + (<<"ets:fun2ms(fun(X) when is_integer(X); " + "is_float(X); atom(X) -> true end)">>), + ?line Res12 = compile_and_run + (<<"ets:fun2ms(fun(X) when is_integer(X) -> true; " + "(X) when is_float(X) -> true; " + "(X) when is_atom(X) -> true end)">>), + ?line Res11 = Res12, + ok. + + +float_1_function(suite) -> + []; +float_1_function(doc) -> + ["OTP-5297. The function float/1."]; +float_1_function(Config) when list(Config) -> + ?line setup(Config), + RunMS = fun(L, MS) -> + ets:match_spec_run(L, ets:match_spec_compile(MS)) + end, + ?line MS1 = compile_and_run + (<<"ets:fun2ms(fun(X) -> float(X) end)">>), + ?line [F1] = RunMS([3], MS1), + ?line true = is_float(F1) and (F1 == 3), + + ?line MS1b = compile_and_run + (<<"dbg:fun2ms(fun(X) -> float(X) end)">>), + ?line [F2] = RunMS([3], MS1b), + ?line true = is_float(F2) and (F2 == 3), + + ?line MS2 = compile_and_run + (<<"ets:fun2ms(fun(X) when is_pid(X) or float(X) -> true end)">>), + ?line [] = RunMS([3.0], MS2), + + ?line MS3 = compile_and_run + (<<"dbg:fun2ms(fun(X) when is_pid(X); float(X) -> true end)">>), + ?line [true] = RunMS([3.0], MS3), + + ?line MS4 = compile_and_run + (<<"ets:fun2ms(fun(X) when erlang:float(X) > 1 -> big;" + " (_) -> small end)">>), + ?line [small,big] = RunMS([1.0, 3.0], MS4), + + ?line MS5 = compile_and_run + (<<"ets:fun2ms(fun(X) when float(X) > 1 -> big;" + " (_) -> small end)">>), + ?line [small,big] = RunMS([1.0, 3.0], MS5), + + %% This is the test from autoimported/1. + ?line [{'$1',[{is_float,'$1'}],[{float,'$1'}]}] = + compile_and_run + (<<"ets:fun2ms(fun(X) when float(X) -> float(X) end)">>), + ?line [{'$1',[{float,'$1'}],[{float,'$1'}]}] = + compile_and_run + (<<"ets:fun2ms(fun(X) when erlang:'float'(X) -> " + "erlang:'float'(X) end)">>), + ok. + + +action_function(suite) -> + []; +action_function(doc) -> + ["Test all 'action functions'."]; +action_function(Config) when is_list(Config) -> + ?line setup(Config), + ?line [{['$1','$2'],[], + [{set_seq_token,label,0}, + {get_seq_token}, + {message,'$1'}, + {return_trace}, + {exception_trace}]}] = + compile_and_run + (<<"dbg:fun2ms(fun([X,Y]) -> " + "set_seq_token(label, 0), " + "get_seq_token(), " + "message(X), " + "return_trace(), " + "exception_trace() end)">>), + ?line [{['$1','$2'],[], + [{process_dump}, + {enable_trace,send}, + {enable_trace,'$2',send}, + {disable_trace,procs}, + {disable_trace,'$2',procs}]}] = + compile_and_run + (<<"dbg:fun2ms(fun([X,Y]) -> " + "process_dump(), " + "enable_trace(send), " + "enable_trace(Y, send), " + "disable_trace(procs), " + "disable_trace(Y, procs) end)">>), + ?line [{['$1','$2'], + [], + [{display,'$1'}, + {caller}, + {set_tcw,{const,16}}, + {silent,true}, + {trace,[send],[procs]}, + {trace,'$2',[procs],[send]}]}] = + compile_and_run + (<<"A = 16, dbg:fun2ms(fun([X,Y]) -> " + "display(X), " + "caller(), " + "set_tcw(A), " + "silent(true), " + "trace([send], [procs]), " + "trace(Y, [procs], [send]) end)">>), + ok. + + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% Helpers +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +setup(Config) -> + put(mts_config,Config), + put(mts_tf_counter,0). + +temp_name() -> + Conf = get(mts_config), + C = get(mts_tf_counter), + put(mts_tf_counter,C+1), + filename:join([?config(priv_dir,Conf), + "tempfile"++integer_to_list(C)++".tmp"]). + + +expect_failure(Recs,Code) -> + case (catch compile_and_run(Recs,Code)) of + {'EXIT',_Foo} -> + %erlang:display(_Foo), + ok; + Other -> + exit({expected,failure,got,Other}) + end. + +compile_and_run(Expr) -> + compile_and_run(<<>>,Expr). +compile_and_run(Records,Expr) -> + Prog = << + "-module(tmp).\n", + "-include_lib(\"stdlib/include/ms_transform.hrl\").\n", + "-export([tmp/0]).\n", + Records/binary,"\n", + "tmp() ->\n", + Expr/binary,".\n">>, + FN=temp_name(), + file:write_file(FN,Prog), + {ok,Forms} = epp:parse_file(FN,"",""), + {ok,tmp,Bin} = compile:forms(Forms), + code:load_binary(tmp,FN,Bin), + tmp:tmp(). + +do_eval(String) -> + {done,{ok,T,_},[]} = erl_scan:tokens( + [], + String++".\n",1), + {ok,Tree} = erl_parse:parse_exprs(T), + {value,Res,[]} = erl_eval:exprs(Tree,[]), + Res. |