summaryrefslogtreecommitdiff
path: root/lib/stdlib/test/ms_transform_SUITE.erl
diff options
context:
space:
mode:
Diffstat (limited to 'lib/stdlib/test/ms_transform_SUITE.erl')
-rw-r--r--lib/stdlib/test/ms_transform_SUITE.erl99
1 files changed, 94 insertions, 5 deletions
diff --git a/lib/stdlib/test/ms_transform_SUITE.erl b/lib/stdlib/test/ms_transform_SUITE.erl
index a28de19372..c34c7e9e69 100644
--- a/lib/stdlib/test/ms_transform_SUITE.erl
+++ b/lib/stdlib/test/ms_transform_SUITE.erl
@@ -30,12 +30,19 @@
-export([from_shell/1]).
-export([records/1]).
-export([record_index/1]).
--export([multipass/1]).
+-export([map_pattern/1]).
+-export([map_expr_in_head/1]).
+-export([map_pattern_from_shell/1]).
+-export([map_expr_in_head_from_shell/1]).
+-export([map_exprs/1]).
+-export([map_exprs_from_shell/1]).
-export([top_match/1]).
+-export([multipass/1]).
-export([old_guards/1]).
-export([autoimported/1]).
-export([semicolon/1]).
-export([bitsyntax/1]).
+-export([binary_bifs/1]).
-export([record_defaults/1]).
-export([andalso_orelse/1]).
-export([float_1_function/1]).
@@ -59,10 +66,13 @@ suite() ->
all() ->
[from_shell, basic_ets, basic_dbg, records,
- record_index, multipass, bitsyntax, record_defaults,
+ record_index, multipass, bitsyntax, binary_bifs, record_defaults,
andalso_orelse, float_1_function, action_function,
warnings, no_warnings, top_match, old_guards, autoimported,
- semicolon, eep37, otp_14454, otp_16824, unused_record].
+ semicolon, eep37, otp_14454, otp_16824, unused_record,
+ map_pattern, map_expr_in_head,
+ map_pattern_from_shell, map_expr_in_head_from_shell,
+ map_exprs, map_exprs_from_shell].
groups() ->
[].
@@ -257,6 +267,32 @@ bitsyntax(Config) when is_list(Config) ->
" end)">>),
ok.
+
+%% Test that binary BIFs byte_size/1, binary_part/2, binary_part/3 are accepted
+binary_bifs(Config) when is_list(Config) ->
+ setup(Config),
+ TestSet = [{<<"hello">>, <<"world">>}, {<<"souldn't">>, <<"match">>}],
+ RunMS = fun(MS) -> ets:match_spec_run(TestSet, ets:match_spec_compile(MS)) end,
+ % check byte_size/1
+ MS1 = compile_and_run(<<"ets:fun2ms(fun({A, B}) when byte_size(A) == 5 -> {A, byte_size(B)} end)">>),
+ [{{'$1','$2'},
+ [{'==',{byte_size,'$1'},5}],
+ [{{'$1',{byte_size,'$2'}}}]}] = MS1,
+ [{<<"hello">>, 5}] = RunMS(MS1),
+ % check binary_part/2
+ MS2 = compile_and_run(<<"ets:fun2ms(fun({A, B}) when binary_part(A, {1, 2}) == <<\"el\">> -> binary_part(B, {2, 3}) end)">>),
+ [{{'$1','$2'},
+ [{'==',{binary_part,'$1',{{1,2}}},<<"el">>}],
+ [{binary_part,'$2',{{2,3}}}]}] = MS2,
+ [<<"rld">>] = RunMS(MS2),
+ % check binary_part/3
+ MS3 = compile_and_run(<<"ets:fun2ms(fun({A, B}) when binary_part(A, 1, 2) == <<\"el\">> -> binary_part(B, 2, 3) end)">>),
+ [{{'$1','$2'},
+ [{'==',{binary_part,'$1',1,2},<<"el">>}],
+ [{binary_part,'$2',2,3}]}] = MS3,
+ [<<"rld">>] = RunMS(MS3),
+ ok.
+
%% Test that record defaults works.
record_defaults(Config) when is_list(Config) ->
setup(Config),
@@ -289,7 +325,7 @@ basic_ets(Config) when is_list(Config) ->
compile_and_run(<<"ets:fun2ms(fun({\"foo\" ++ _, X}) -> X end)">>),
ok.
-%% Tests basic ets:fun2ms.
+%% Tests basic dbg:fun2ms.
basic_dbg(Config) when is_list(Config) ->
setup(Config),
[{[a,b],[],[{message,banan},{return_trace}]}] =
@@ -382,6 +418,59 @@ record_index(Config) when is_list(Config) ->
<<"ets:fun2ms(fun({#a.a,A}) when A > #a.a -> #a.a end)">>),
ok.
+map_pattern(Config) when is_list(Config) ->
+ setup(Config),
+ MS = [{{key, #{foo => '$1'}},[],['$1']}],
+ MS = compile_and_run(<<"ets:fun2ms(fun({key, #{foo := V}}) -> V end)">>),
+ ok.
+
+map_expr_in_head(Config) when is_list(Config) ->
+ setup(Config),
+ MS = [{{key, #{foo => '$1'}},[],['$1']}],
+ %% Accidentally it is possible to use => instead of := in the fun head,
+ %% in compiled code.
+ %% Although this is not an intended behaviour it is kept to
+ %% maintain backwards compatibility.
+ MS = compile_and_run(<<"ets:fun2ms(fun({key, #{foo => V}}) -> V end)">>),
+ ok.
+
+map_pattern_from_shell(Config) when is_list(Config) ->
+ MS = [{{key, #{foo => '$1'}},[],['$1']}],
+ MS = do_eval("ets:fun2ms(fun({key, #{foo := V}}) -> V end)"),
+ ok.
+
+map_expr_in_head_from_shell(Config) when is_list(Config) ->
+ setup(Config),
+ MS = [{{key, #{foo => '$1'}},[],['$1']}],
+ %% Accidentally it is possible to use => instead of := in the fun head,
+ %% in compiled code. This behaviour is kept for backwards compatibility.
+
+ %% As a side-effect, it is also possible to do the same with
+ %% `transform_from_shell/3', if the AST of the shell fun is
+ %% created bypassing the linter. (The linter would prevent
+ %% constructing such invalid syntax, so normally this is not
+ %% possible in the Erlang shell)
+ MS = do_eval("ets:fun2ms(fun({key, #{foo => V}}) -> V end)"),
+ ok.
+
+map_exprs(Config) when is_list(Config) ->
+ setup(Config),
+ MSGuard = [{{key,'$1','$2'}, [{'=:=','$1',#{foo => '$2'}}], ['$1']}],
+ MSGuard = compile_and_run(
+ <<"ets:fun2ms(fun({key, V1, V2}) when V1 =:= #{foo => V2} -> V1 end)">>),
+ MSBody = [{{key,'$1'}, [], [#{foo => '$1'}]}],
+ MSBody = compile_and_run(
+ <<"ets:fun2ms(fun({key, V}) -> #{foo => V} end)">>),
+ ok.
+
+map_exprs_from_shell(Config) when is_list(Config) ->
+ setup(Config),
+ MSGuard = [{{key,'$1','$2'}, [{'=:=','$1',#{foo => '$2'}}], ['$1']}],
+ MSGuard = do_eval("ets:fun2ms(fun({key, V1, V2}) when V1 =:= #{foo => V2} -> V1 end)"),
+ MSBody = [{{key,'$1'}, [], [#{foo => '$1'}]}],
+ MSBody = do_eval("ets:fun2ms(fun({key, V}) -> #{foo => V} end)"),
+ ok.
+
%% Tests matching on top level in head to give alias for object().
top_match(Config) when is_list(Config) ->
setup(Config),
@@ -897,5 +986,5 @@ do_eval(String) ->
[],
String++".\n",1),
{ok,Tree} = erl_parse:parse_exprs(T),
- {value,Res,[]} = erl_eval:exprs(Tree,[]),
+ {value,Res,[]} = erl_eval:exprs(Tree,[],none,none),
Res.