Skip to content

Commit 486543c

Browse files
committed
Add minimal changes to adapt to OTP26
* Handle new map comprehension and map generators in power_shell_eval * Add tests for above * (The experimental feature maybe is not handled)
1 parent 69875e5 commit 486543c

File tree

2 files changed

+157
-24
lines changed

2 files changed

+157
-24
lines changed

src/power_shell_eval.erl

Lines changed: 93 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -274,6 +274,8 @@ expr({lc,_,E,Qs}, Bs, Lf, Ef, RBs, FUVs) ->
274274
eval_lc(E, Qs, Bs, Lf, Ef, RBs, FUVs);
275275
expr({bc,_,E,Qs}, Bs, Lf, Ef, RBs, FUVs) ->
276276
eval_bc(E, Qs, Bs, Lf, Ef, RBs, FUVs);
277+
expr({mc,_,E,Qs}, Bs, Lf, Ef, RBs, FUVs) ->
278+
eval_mc(E, Qs, Bs, Lf, Ef, RBs, FUVs);
277279
expr({tuple,_,Es}, Bs0, Lf, Ef, RBs, FUVs) ->
278280
{Vs,Bs} = expr_list(Es, Bs0, Lf, Ef, FUVs),
279281
ret_expr(list_to_tuple(Vs), Bs, RBs);
@@ -523,6 +525,9 @@ expr({bin,_,Fs}, Bs0, Lf, Ef, RBs, FUVs) ->
523525
expr({remote,_,_,_}, _Bs, _Lf, _Ef, _RBs, _FUVs) ->
524526
erlang:raise(error, {badexpr,':'}, ?STACKTRACE).
525527

528+
apply_error(Reason, Stack, _Anno, Bs0, Ef, RBs) ->
529+
do_apply(erlang, raise, [error, Reason, Stack], Bs0, Ef, RBs).
530+
526531
find_maxline(LC) ->
527532
put('$erl_eval_max_line', 0),
528533
F = fun(A) ->
@@ -737,17 +742,15 @@ do_apply(Mod, Func, As, Bs0, Ef, RBs) ->
737742
eval_lc(E, Qs, Bs, Lf, Ef, RBs, FUVs) ->
738743
ret_expr(lists:reverse(eval_lc1(E, Qs, Bs, Lf, Ef, FUVs, [])), Bs, RBs).
739744

740-
eval_lc1(E, [{generate,_,P,L0}|Qs], Bs0, Lf, Ef, FUVs, Acc0) ->
741-
{value,L1,_Bs1} = expr(L0, Bs0, Lf, Ef, none, FUVs),
742-
CompFun = fun(Bs, Acc) -> eval_lc1(E, Qs, Bs, Lf, Ef, FUVs, Acc) end,
743-
eval_generate(L1, P, Bs0, Lf, Ef, CompFun, Acc0);
744-
eval_lc1(E, [{b_generate,_,P,L0}|Qs], Bs0, Lf, Ef, FUVs, Acc0) ->
745-
{value,Bin,_Bs1} = expr(L0, Bs0, Lf, Ef, none, FUVs),
746-
CompFun = fun(Bs, Acc) -> eval_lc1(E, Qs, Bs, Lf, Ef, FUVs, Acc) end,
747-
eval_b_generate(Bin, P, Bs0, Lf, Ef, CompFun, Acc0);
748-
eval_lc1(E, [F|Qs], Bs0, Lf, Ef, FUVs, Acc) ->
749-
CompFun = fun(Bs) -> eval_lc1(E, Qs, Bs, Lf, Ef, FUVs, Acc) end,
750-
eval_filter(F, Bs0, Lf, Ef, CompFun, FUVs, Acc);
745+
eval_lc1(E, [Q|Qs], Bs0, Lf, Ef, FUVs, Acc0) ->
746+
case is_generator(Q) of
747+
true ->
748+
CF = fun(Bs, Acc) -> eval_lc1(E, Qs, Bs, Lf, Ef, FUVs, Acc) end,
749+
eval_generator(Q, Bs0, Lf, Ef, FUVs, Acc0, CF);
750+
false ->
751+
CF = fun(Bs) -> eval_lc1(E, Qs, Bs, Lf, Ef, FUVs, Acc0) end,
752+
eval_filter(Q, Bs0, Lf, Ef, CF, FUVs, Acc0)
753+
end;
751754
eval_lc1(E, [], Bs, Lf, Ef, FUVs, Acc) ->
752755
{value,V,_} = expr(E, Bs, Lf, Ef, none, FUVs),
753756
[V|Acc].
@@ -759,21 +762,67 @@ eval_lc1(E, [], Bs, Lf, Ef, FUVs, Acc) ->
759762
eval_bc(E, Qs, Bs, Lf, Ef, RBs, FUVs) ->
760763
ret_expr(eval_bc1(E, Qs, Bs, Lf, Ef, FUVs, <<>>), Bs, RBs).
761764

762-
eval_bc1(E, [{b_generate,_,P,L0}|Qs], Bs0, Lf, Ef, FUVs, Acc0) ->
763-
{value,Bin,_Bs1} = expr(L0, Bs0, Lf, Ef, none, FUVs),
764-
CompFun = fun(Bs, Acc) -> eval_bc1(E, Qs, Bs, Lf, Ef, FUVs, Acc) end,
765-
eval_b_generate(Bin, P, Bs0, Lf, Ef, CompFun, Acc0);
766-
eval_bc1(E, [{generate,_,P,L0}|Qs], Bs0, Lf, Ef, FUVs, Acc0) ->
767-
{value,List,_Bs1} = expr(L0, Bs0, Lf, Ef, none, FUVs),
768-
CompFun = fun(Bs, Acc) -> eval_bc1(E, Qs, Bs, Lf, Ef, FUVs, Acc) end,
769-
eval_generate(List, P, Bs0, Lf, Ef, CompFun, Acc0);
770-
eval_bc1(E, [F|Qs], Bs0, Lf, Ef, FUVs, Acc) ->
771-
CompFun = fun(Bs) -> eval_bc1(E, Qs, Bs, Lf, Ef, FUVs, Acc) end,
772-
eval_filter(F, Bs0, Lf, Ef, CompFun, FUVs, Acc);
765+
eval_bc1(E, [Q|Qs], Bs0, Lf, Ef, FUVs, Acc0) ->
766+
case is_generator(Q) of
767+
true ->
768+
CF = fun(Bs, Acc) -> eval_bc1(E, Qs, Bs, Lf, Ef, FUVs, Acc) end,
769+
eval_generator(Q, Bs0, Lf, Ef, FUVs, Acc0, CF);
770+
false ->
771+
CF = fun(Bs) -> eval_bc1(E, Qs, Bs, Lf, Ef, FUVs, Acc0) end,
772+
eval_filter(Q, Bs0, Lf, Ef, CF, FUVs, Acc0)
773+
end;
773774
eval_bc1(E, [], Bs, Lf, Ef, FUVs, Acc) ->
774775
{value,V,_} = expr(E, Bs, Lf, Ef, none, FUVs),
775776
<<Acc/bitstring,V/bitstring>>.
776777

778+
779+
%% eval_mc(Expr, [Qualifier], Bindings, LocalFunctionHandler,
780+
%% ExternalFuncHandler, RetBindings) ->
781+
%% {value,Value,Bindings} | Value
782+
783+
eval_mc(E, Qs, Bs, Lf, Ef, RBs, FUVs) ->
784+
L = eval_mc1(E, Qs, Bs, Lf, Ef, FUVs, []),
785+
Map = maps:from_list(L),
786+
ret_expr(Map, Bs, RBs).
787+
788+
eval_mc1(E, [Q|Qs], Bs0, Lf, Ef, FUVs, Acc0) ->
789+
case is_generator(Q) of
790+
true ->
791+
CF = fun(Bs, Acc) -> eval_mc1(E, Qs, Bs, Lf, Ef, FUVs, Acc) end,
792+
eval_generator(Q, Bs0, Lf, Ef, FUVs, Acc0, CF);
793+
false ->
794+
CF = fun(Bs) -> eval_mc1(E, Qs, Bs, Lf, Ef, FUVs, Acc0) end,
795+
eval_filter(Q, Bs0, Lf, Ef, CF, FUVs, Acc0)
796+
end;
797+
eval_mc1({map_field_assoc,Lfa,K0,V0}, [], Bs, Lf, Ef, FUVs, Acc) ->
798+
{value,KV,_} = expr({tuple,Lfa,[K0,V0]}, Bs, Lf, Ef, none, FUVs),
799+
[KV|Acc].
800+
801+
eval_generator({generate,_Anno,P,L0}, Bs0, Lf, Ef, FUVs, Acc0, CompFun) ->
802+
{value,L1,_Bs1} = expr(L0, Bs0, Lf, Ef, none, FUVs),
803+
eval_generate(L1, P, Bs0, Lf, Ef, CompFun, Acc0);
804+
eval_generator({b_generate,_Anno,P,Bin0}, Bs0, Lf, Ef, FUVs, Acc0, CompFun) ->
805+
{value,Bin,_Bs1} = expr(Bin0, Bs0, Lf, Ef, none, FUVs),
806+
eval_b_generate(Bin, P, Bs0, Lf, Ef, CompFun, Acc0);
807+
eval_generator({m_generate,Anno,P,Map0}, Bs0, Lf, Ef, FUVs, Acc0, CompFun) ->
808+
{map_field_exact,_,K,V} = P,
809+
{value,Map,_Bs1} = expr(Map0, Bs0, Lf, Ef, none, FUVs),
810+
Iter = case is_map(Map) of
811+
true ->
812+
maps:iterator(Map);
813+
false ->
814+
%% Validate iterator.
815+
try maps:foreach(fun(_, _) -> ok end, Map) of
816+
_ ->
817+
Map
818+
catch
819+
_:_ ->
820+
apply_error({bad_generator,Map}, ?STACKTRACE,
821+
Anno, Bs0, Ef, none)
822+
end
823+
end,
824+
eval_m_generate(Iter, {tuple,Anno,[K,V]}, Anno, Bs0, Lf, Ef, CompFun, Acc0).
825+
777826
eval_generate([V|Rest], P, Bs0, Lf, Ef, CompFun, Acc) ->
778827
case match(P, V, new_bindings(Bs0), Bs0) of
779828
{match,Bsn} ->
@@ -804,6 +853,22 @@ eval_b_generate(<<_/bitstring>>=Bin, P, Bs0, Lf, Ef, CompFun, Acc) ->
804853
eval_b_generate(Term, _P, _Bs0, _Lf, _Ef, _CompFun, _Acc) ->
805854
erlang:raise(error, {bad_generator,Term}, ?STACKTRACE).
806855

856+
857+
eval_m_generate(Iter0, P, Anno, Bs0, Lf, Ef, CompFun, Acc0) ->
858+
case maps:next(Iter0) of
859+
{K,V,Iter} ->
860+
case match(P, {K,V}, new_bindings(Bs0), Bs0) of
861+
{match,Bsn} ->
862+
Bs2 = add_bindings(Bsn, Bs0),
863+
Acc = CompFun(Bs2, Acc0),
864+
eval_m_generate(Iter, P, Anno, Bs0, Lf, Ef, CompFun, Acc);
865+
nomatch ->
866+
eval_m_generate(Iter, P, Anno, Bs0, Lf, Ef, CompFun, Acc0)
867+
end;
868+
none ->
869+
Acc0
870+
end.
871+
807872
eval_filter(F, Bs0, Lf, Ef, CompFun, FUVs, Acc) ->
808873
case erl_lint:is_guard_test(F) of
809874
true ->
@@ -820,6 +885,11 @@ eval_filter(F, Bs0, Lf, Ef, CompFun, FUVs, Acc) ->
820885
end
821886
end.
822887

888+
is_generator({generate,_,_,_}) -> true;
889+
is_generator({b_generate,_,_,_}) -> true;
890+
is_generator({m_generate,_,_,_}) -> true;
891+
is_generator(_) -> false.
892+
823893
%% eval_map_fields([Field], Bindings, LocalFunctionHandler,
824894
%% ExternalFuncHandler) ->
825895
%% {[{map_assoc | map_exact,Key,Value}],Bindings}
@@ -1692,4 +1762,4 @@ merge_with_1({K, V2, Iterator}, Map1, Map2, Combiner) ->
16921762
merge_with_1(maps:next(Iterator), maps:put(K, V2, Map1), Map2, Combiner)
16931763
end;
16941764
merge_with_1(none, Result, _, _) ->
1695-
Result.
1765+
Result.

test/power_shell_SUITE.erl

Lines changed: 64 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,11 @@
3838
try_side_effect/0, try_side_effect/1,
3939
rebind_var/0, rebind_var/1,
4040
external_fun/0, external_fun/1,
41+
map_comp_from_list/0, map_comp_from_list/1,
42+
map_comp_from_bin/0, map_comp_from_bin/1,
43+
map_gen_to_map/0, map_gen_to_map/1,
44+
map_gen_to_list/0, map_gen_to_list/1,
45+
map_gen_to_bin/0, map_gen_to_bin/1,
4146
catch_apply/0, catch_apply/1,
4247
export/0, export/1,
4348
export_partial/0, export_partial/1,
@@ -65,7 +70,8 @@ test_cases() ->
6570
[echo, self_echo, preloaded, second_clause, undef, undef_local, undef_nested, recursive,
6671
calling_local, throwing, bad_match, function_clause, remote_callback,
6772
callback_local, callback_local_fun_obj, callback_local_make_fun, recursive_eval,
68-
remote_callback_exported, record, try_side_effect, rebind_var, external_fun, catch_apply].
73+
remote_callback_exported, record, try_side_effect, rebind_var, external_fun, catch_apply,
74+
map_comp_from_list, map_comp_from_bin, map_gen_to_map, map_gen_to_list, map_gen_to_bin].
6975

7076
%%--------------------------------------------------------------------
7177
%% Function: groups() -> [Group]
@@ -228,6 +234,11 @@ export_all() ->
228234
local_bad_match(),
229235
rebind([]),
230236
external_filter([]),
237+
map_comprehension_from_list(),
238+
map_comprehension_from_binary(),
239+
map_generator_to_map(),
240+
map_generator_to_list(),
241+
map_generator_to_binary(),
231242
throw_applied(),
232243
try_side({1, 1}).
233244

@@ -265,6 +276,23 @@ throw_applied() ->
265276
throw(expected)
266277
end.
267278

279+
map_comprehension_from_list() ->
280+
#{N => N*N || N <- lists:seq(1, 10), N < 4}.
281+
282+
map_comprehension_from_binary() ->
283+
#{X => Y || <<X,Y>> <= <<"abcdefgh">>}.
284+
285+
map_generator_to_map() ->
286+
#{V => K
287+
|| K := V <- #{1 => 1, 2 => 4, 3 => 9, one => one, two => four},
288+
is_integer(K)}.
289+
290+
map_generator_to_list() ->
291+
lists:sort([{V, K} || K := V <- #{1 => 1, 2 => 4, 3 => 9}]).
292+
293+
map_generator_to_binary() ->
294+
<< <<K, V>> || K := V <- #{$a => $b, $c => $d} >>.
295+
268296
%%--------------------------------------------------------------------
269297
%% Test Cases
270298

@@ -417,6 +445,41 @@ external_fun() ->
417445
external_fun(Config) when is_list(Config) ->
418446
?assertEqual([1, 2], power_shell:eval(?MODULE, external_filter, [[1, atom, 2, atom]])).
419447

448+
map_comp_from_list() ->
449+
[{doc, "Tests handling of map comprehension introduced in OTP26"}].
450+
451+
map_comp_from_list(Config) when is_list(Config) ->
452+
?assertEqual(#{1 => 1, 2 => 4, 3 => 9},
453+
power_shell:eval(?MODULE, map_comprehension_from_list, [])).
454+
455+
map_comp_from_bin() ->
456+
[{doc, "Tests handling of map comprehension introduced in OTP26"}].
457+
458+
map_comp_from_bin(Config) when is_list(Config) ->
459+
?assertEqual(#{$a => $b, $c => $d, $e => $f, $g => $h},
460+
power_shell:eval(?MODULE, map_comprehension_from_binary, [])).
461+
462+
map_gen_to_map() ->
463+
[{doc, "Tests handling of map generator introduced in OTP26"}].
464+
465+
map_gen_to_map(Config) when is_list(Config) ->
466+
?assertEqual(#{1 => 1, 4 => 2, 9 => 3},
467+
power_shell:eval(?MODULE, map_generator_to_map, [])).
468+
469+
map_gen_to_list() ->
470+
[{doc, "Tests handling of map generator introduced in OTP26"}].
471+
472+
map_gen_to_list(Config) when is_list(Config) ->
473+
?assertEqual([{1, 1}, {4, 2}, {9, 3}],
474+
power_shell:eval(?MODULE, map_generator_to_list, [])).
475+
476+
map_gen_to_bin() ->
477+
[{doc, "Tests handling of map generator introduced in OTP26"}].
478+
479+
map_gen_to_bin(Config) when is_list(Config) ->
480+
?assertEqual("abcd",
481+
lists:sort(binary_to_list(power_shell:eval(?MODULE, map_generator_to_binary, [])))).
482+
420483
catch_apply() ->
421484
[{doc, "Tests that cast catch erlang:apply works and throws as expected, not converting it to badarg"}].
422485

0 commit comments

Comments
 (0)