Skip to content

Commit

Permalink
fixup! compiler: Add zip generators for comprehensions
Browse files Browse the repository at this point in the history
  • Loading branch information
bjorng committed Oct 10, 2024
1 parent bb39599 commit e94bae3
Show file tree
Hide file tree
Showing 4 changed files with 151 additions and 109 deletions.
85 changes: 45 additions & 40 deletions lib/compiler/test/zlc_SUITE.erl
Original file line number Diff line number Diff line change
Expand Up @@ -94,19 +94,25 @@ ifelse(Tests, Xs, Ys) -> % Simulate R's ifelse(,,)
mixed_zlc(Config) when is_list(Config) ->
[{a, 2}, {b, 4}, {c, 6}] = [{X,Y} || X <- [a,b,c] && <<Y>> <= <<2,4,6>>],
[{a, 2}, {b, 4}, {c, 6}] = [{X,Y} || <<Y>> <= <<2,4,6>> && X <- [a,b,c]],
[{a,c,1,3}, {b,d,2,4}] = [{K1,K2,V1,V2}|| K1 := V1 <- maps:iterator(#{a=>1, b=>2}, ordered) &&
K2 := V2 <- maps:iterator(#{c=>3, d=>4}, ordered)],
[{a,1,2}, {b,2,4}] = [{K1,V1,Y} || K1 := V1 <- maps:iterator(#{a=>1, b=>2}, ordered) &&
<<Y>> <= <<2,4>>],
[{a,1,2}, {b,2,4}] = [{K1,V1,Y} || K1 := V1 <- maps:iterator(#{a=>1, b=>2}, ordered) &&
<<Y>> <= <<2,4>>],
[{a,c,1,3}, {b,d,2,4}] = [{K1,K2,V1,V2}||
K1 := V1 <- maps:iterator(#{a=>1, b=>2}, ordered) &&
K2 := V2 <- maps:iterator(#{c=>3, d=>4}, ordered)],
[{a,1,2}, {b,2,4}] =
[{K1,V1,Y} || K1 := V1 <- maps:iterator(#{a=>1, b=>2}, ordered) &&
<<Y>> <= <<2,4>>],
[{a,1,2}, {b,2,4}] = [{K1,V1,Y} ||
K1 := V1 <- maps:iterator(#{a=>1, b=>2}, ordered) &&
<<Y>> <= <<2,4>>],
<<3,4,5>> = << <<(X+Y)/integer>> || X <- [1,2,3] && Y <- [2,2,2]>>,
<<3,4,5>> = << <<(X+V1)/integer>> || X <- [1,2,3] &&
_K1 := V1 <- maps:iterator(#{a=>2, b=>2, c=>2}, ordered)>>,
<<3,4,5>> = << <<(X+V1)/integer>> || <<X>> <= <<1,2,3>> &&
_K1 := V1 <- maps:iterator(#{a=>2, b=>2, c=>2}, ordered)>>,
<<3,4,5>> = << <<(V1+V2)/integer>> || _K1 := V1 <- maps:iterator(#{a=>1, b=>2, c=>3}, ordered) &&
_K2 := V2 <- maps:iterator(#{a=>2, b=>2, c=>2}, ordered)>>,
<<3,4,5>> = << <<(X+V1)/integer>> ||
X <- [1,2,3] &&
_K1 := V1 <- maps:iterator(#{a=>2, b=>2, c=>2}, ordered)>>,
<<3,4,5>> = << <<(X+V1)/integer>> ||
<<X>> <= <<1,2,3>> &&
_K1 := V1 <- maps:iterator(#{a=>2, b=>2, c=>2}, ordered)>>,
<<3,4,5>> = << <<(V1+V2)/integer>> ||
_K1 := V1 <- maps:iterator(#{a=>1, b=>2, c=>3}, ordered) &&
_K2 := V2 <- maps:iterator(#{a=>2, b=>2, c=>2}, ordered)>>,
#{c := 3,b := 2,a := 1} = #{X => Y || X <- [a,b,c] && Y <- [1,2,3]},
#{c := 3,b := 2,a := 1} = #{X => Y || X <- [a,b,c] && <<Y>> <= <<1,2,3>>},
ok.
Expand Down Expand Up @@ -168,15 +174,19 @@ do_filter_pat_2(L1, L2) ->
Res.

cartesian(Config) when is_list(Config) ->
[{a,3}, {b,5}, {c,7}, {a,4}, {b,6}, {c,8}] = [{X, W+Y} || W <- [1,2],
X <- [a,b,c] && <<Y>> <= <<2,4,6>>],
[{a,3}, {a,4}, {b,5}, {b,6}, {c,7}, {c,8}] = [{X, W+Y} || X <- [a,b,c] &&
<<Y>> <= <<2,4,6>>, W <- [1,2]],
[{a,4}, {b,6}, {c,8}] = [{X, W+Y} || X <- [a,b,c] &&
<<Y>> <= <<2,4,6>>, W <- [1,2], (W + Y) rem 2 == 0],
<<4,2,5,3,6,4>> = << <<(X+V1+Y)/integer>> || X <- [1,2,3] &&
_K1 := V1 <- maps:iterator(#{a=>2, b=>2, c=>2}, ordered),
<<Y>> <= <<1,-1>> >>,
[{a,3}, {b,5}, {c,7}, {a,4}, {b,6}, {c,8}] =
[{X, W+Y} || W <- [1,2],
X <- [a,b,c] && <<Y>> <= <<2,4,6>>],
[{a,3}, {a,4}, {b,5}, {b,6}, {c,7}, {c,8}] =
[{X, W+Y} || X <- [a,b,c] &&
<<Y>> <= <<2,4,6>>, W <- [1,2]],
[{a,4}, {b,6}, {c,8}] =
[{X, W+Y} || X <- [a,b,c] &&
<<Y>> <= <<2,4,6>>, W <- [1,2], (W + Y) rem 2 == 0],
<<4,2,5,3,6,4>> = << <<(X+V1+Y)/integer>> ||
X <- [1,2,3] &&
_K1 := V1 <- maps:iterator(#{a=>2, b=>2, c=>2}, ordered),
<<Y>> <= <<1,-1>> >>,
ok.

nomatch(Config) when is_list(Config) ->
Expand All @@ -199,21 +209,16 @@ do_nomatch_2(L, Bin) ->

bad_generators(Config) when is_list(Config) ->

{'EXIT',{{bad_generators,{x,[1,2]}},_}} = (catch
[{X,Y} || X <- x &&
Y <- [1,2]]),
{'EXIT',{{bad_generators,{[],[4]}},_}} = (catch
[{X,Y} || X <- [1,2,3] &&
Y <- [1,2,3,4]]),
{'EXIT',{{bad_generators,{[3,4],[]}},_}} = (catch
[{X,Y} || X <- [1,2,3,4] &&
Y <- [1,2], X < 3]),
{'EXIT',{{bad_generators,{[3,4],[]}},_}} = (catch
<< <<(X+Y)/integer>> || X <- [1,2,3,4] &&
Y <- [1,2], X < 3>>),
{'EXIT',{{bad_generators,{[d],[]}},_}} = (catch
#{X => Y || X <- [a,b,c,d] &&
Y <- [1,2,3], Y > 1}),
{'EXIT',{{bad_generators,{x,[1,2]}},_}} =
catch [{X,Y} || X <- x && Y <- [1,2]],
{'EXIT',{{bad_generators,{[],[4]}},_}} =
catch [{X,Y} || X <- [1,2,3] && Y <- [1,2,3,4]],
{'EXIT',{{bad_generators,{[3,4],[]}},_}} =
catch [{X,Y} || X <- [1,2,3,4] && Y <- [1,2], X < 3],
{'EXIT',{{bad_generators,{[3,4],[]}},_}} =
catch << <<(X+Y)/integer>> || X <- [1,2,3,4] && Y <- [1,2], X < 3>>,
{'EXIT',{{bad_generators,{[d],[]}},_}} =
catch #{X => Y || X <- [a,b,c,d] && Y <- [1,2,3], Y > 1},

%% Make sure that line numbers point out the generator.
case ?MODULE of
Expand All @@ -224,23 +229,23 @@ bad_generators(Config) when is_list(Config) ->
{'EXIT',{{bad_generators,{[],[4]}},
[{?MODULE,_,_,
[{file,"bad_zlc.erl"},{line,4}]}|_]}} =
(catch bad_generators([1,2,3],[1,2,3,4])),
catch bad_generators([1,2,3],[1,2,3,4]),

{'EXIT',{{bad_generators,{a,[2,3]}},
[{?MODULE,_,_,
[{file,"bad_zlc.erl"},{line,7}]}|_]}} =
(catch bad_generators_bc(a,[2,3])),
catch bad_generators_bc(a,[2,3]),

{'EXIT',{{bad_generators,{[2],[]}},
[{?MODULE,_,_,
[{file,"bad_zlc.erl"},{line,10}]}|_]}} =
(catch bad_generators_mc([1,2],[1])),
catch bad_generators_mc([1,2],[1]),

%% List comprehensions with improper lists.
{'EXIT',{{bad_generators,{d,[d]}},
[{?MODULE,_,_,
[{file,"bad_zlc.erl"},{line,4}]}|_]}} =
(catch bad_generators([a,b,c|d],[a,b,c,d]))
catch bad_generators([a,b,c|d],[a,b,c,d])
end,
ok.

Expand Down
34 changes: 24 additions & 10 deletions lib/debugger/src/dbg_ieval.erl
Original file line number Diff line number Diff line change
Expand Up @@ -1166,15 +1166,20 @@ convert_gen_values([], Acc, Bs0, _Ieval) ->
bind_all_generators(Gens, Bs0, Ieval) ->
bind_all_generators1(Gens, [], erl_eval:new_bindings(Bs0), Ieval, continue).

bind_all_generators1([{b_generate, Anno, P, <<_/bitstring>>=Bin}|Qs], Acc, Bs0, Ieval, continue) ->
bind_all_generators1([{b_generate, Anno, P, <<_/bitstring>>=Bin}|Qs],
Acc, Bs0, Ieval, continue) ->
Mfun = match_fun(Bs0),
Efun = fun(Exp, Bs) -> expr(Exp, Bs, #ieval{}) end,
case eval_bits:bin_gen(P, Bin, erl_eval:new_bindings(Bs0), Bs0, Mfun, Efun) of
{match, Rest, Bs1} ->
Bs2 = zip_add_bindings(Bs1, Bs0),
case Bs2 of
nomatch -> bind_all_generators1(Qs,[{b_generate, Anno, P, Rest}|Acc], Bs0, Ieval, skip);
_ -> bind_all_generators1(Qs,[{b_generate, Anno, P, Rest}|Acc], Bs2, Ieval, continue)
nomatch ->
bind_all_generators1(Qs, [{b_generate, Anno, P, Rest}|Acc],
Bs0, Ieval, skip);
_ ->
bind_all_generators1(Qs, [{b_generate, Anno, P, Rest}|Acc],
Bs2, Ieval, continue)
end;
{nomatch, Rest} ->
bind_all_generators1(Qs, [{b_generate, Anno, P, Rest}|Acc], Bs0, Ieval, skip);
Expand All @@ -1197,8 +1202,10 @@ bind_all_generators1([{generate, Anno, P, [H|T]}|Qs], Acc, Bs0, Ieval, continue)
{match,Bsn} ->
Bs2 = zip_add_bindings(Bsn, Bs0),
case Bs2 of
nomatch -> bind_all_generators1(Qs,[{generate, Anno, P, T}|Acc], Bs0, Ieval, skip);
_ -> bind_all_generators1(Qs,[{generate, Anno, P, T}|Acc], Bs2, Ieval, continue)
nomatch ->
bind_all_generators1(Qs,[{generate, Anno, P, T}|Acc], Bs0, Ieval, skip);
_ ->
bind_all_generators1(Qs,[{generate, Anno, P, T}|Acc], Bs2, Ieval, continue)
end;
nomatch ->
%% match/6 returns nomatch. Skip this value
Expand All @@ -1213,11 +1220,16 @@ bind_all_generators1([{m_generate, Anno, P, Iter0}|Qs], Acc, Bs0, Ieval, continu
{match,Bsn} ->
Bs2 = zip_add_bindings(Bsn, Bs0),
case Bs2 of
nomatch -> bind_all_generators1(Qs,[{m_generate, Anno, P, Iter}|Acc], Bs0, Ieval, skip);
_ -> bind_all_generators1(Qs,[{m_generate, Anno, P, Iter}|Acc], Bs2, Ieval, continue)
nomatch ->
bind_all_generators1(Qs,[{m_generate, Anno, P, Iter}|Acc],
Bs0, Ieval, skip);
_ ->
bind_all_generators1(Qs,[{m_generate, Anno, P, Iter}|Acc],
Bs2, Ieval, continue)
end;
nomatch ->
bind_all_generators1(Qs, [{m_generate, Anno, P, Iter}|Acc], Bs0, Ieval, skip)
bind_all_generators1(Qs, [{m_generate, Anno, P, Iter}|Acc],
Bs0, Ieval, skip)
end;
none ->
{[], done}
Expand All @@ -1227,9 +1239,11 @@ bind_all_generators1([{m_generate, Anno, P, Iter0}|Qs], Acc, Bs0, Ieval, skip) -
{K,V,Iter} ->
case catch match1(P, {K,V}, erl_eval:new_bindings(Bs0), Bs0) of
{match,_} ->
bind_all_generators1(Qs, [{m_generate, Anno, P, Iter}|Acc], Bs0, Ieval, skip);
bind_all_generators1(Qs, [{m_generate, Anno, P, Iter}|Acc],
Bs0, Ieval, skip);
nomatch ->
bind_all_generators1(Qs, [{m_generate, Anno, P, Iter}|Acc], Bs0, Ieval, skip)
bind_all_generators1(Qs, [{m_generate, Anno, P, Iter}|Acc],
Bs0, Ieval, skip)
end;
none ->
{[], skip}
Expand Down
92 changes: 48 additions & 44 deletions lib/debugger/test/zlc_SUITE.erl
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ init_per_suite(Config) when is_list(Config) ->
true = lists:member(?MODULE, int:interpreted()),
Config.

end_per_suite(Config) when is_list(Config) ->
end_per_suite(_Config) ->
ok.

init_per_group(_GroupName, Config) ->
Expand All @@ -59,11 +59,10 @@ end_per_group(_GroupName, Config) ->
Config.


init_per_testcase(_Case, Config) ->
test_lib:interpret(?MODULE),
init_per_testcase(Case, Config) when is_atom(Case), is_list(Config) ->
Config.

end_per_testcase(_Case, _Config) ->
end_per_testcase(Case, Config) when is_atom(Case), is_list(Config) ->
ok.

basic(Config) when is_list(Config) ->
Expand Down Expand Up @@ -94,19 +93,25 @@ ifelse(Tests, Xs, Ys) -> % Simulate R's ifelse(,,)
mixed_zlc(Config) when is_list(Config) ->
[{a, 2}, {b, 4}, {c, 6}] = [{X,Y} || X <- [a,b,c] && <<Y>> <= <<2,4,6>>],
[{a, 2}, {b, 4}, {c, 6}] = [{X,Y} || <<Y>> <= <<2,4,6>> && X <- [a,b,c]],
[{a,c,1,3}, {b,d,2,4}] = [{K1,K2,V1,V2}|| K1 := V1 <- maps:iterator(#{a=>1, b=>2}, ordered) &&
K2 := V2 <- maps:iterator(#{c=>3, d=>4}, ordered)],
[{a,1,2}, {b,2,4}] = [{K1,V1,Y} || K1 := V1 <- maps:iterator(#{a=>1, b=>2}, ordered) &&
<<Y>> <= <<2,4>>],
[{a,1,2}, {b,2,4}] = [{K1,V1,Y} || K1 := V1 <- maps:iterator(#{a=>1, b=>2}, ordered) &&
<<Y>> <= <<2,4>>],
[{a,c,1,3}, {b,d,2,4}] = [{K1,K2,V1,V2}||
K1 := V1 <- maps:iterator(#{a=>1, b=>2}, ordered) &&
K2 := V2 <- maps:iterator(#{c=>3, d=>4}, ordered)],
[{a,1,2}, {b,2,4}] =
[{K1,V1,Y} || K1 := V1 <- maps:iterator(#{a=>1, b=>2}, ordered) &&
<<Y>> <= <<2,4>>],
[{a,1,2}, {b,2,4}] = [{K1,V1,Y} ||
K1 := V1 <- maps:iterator(#{a=>1, b=>2}, ordered) &&
<<Y>> <= <<2,4>>],
<<3,4,5>> = << <<(X+Y)/integer>> || X <- [1,2,3] && Y <- [2,2,2]>>,
<<3,4,5>> = << <<(X+V1)/integer>> || X <- [1,2,3] &&
_K1 := V1 <- maps:iterator(#{a=>2, b=>2, c=>2}, ordered)>>,
<<3,4,5>> = << <<(X+V1)/integer>> || <<X>> <= <<1,2,3>> &&
_K1 := V1 <- maps:iterator(#{a=>2, b=>2, c=>2}, ordered)>>,
<<3,4,5>> = << <<(V1+V2)/integer>> || _K1 := V1 <- maps:iterator(#{a=>1, b=>2, c=>3}, ordered) &&
_K2 := V2 <- maps:iterator(#{a=>2, b=>2, c=>2}, ordered)>>,
<<3,4,5>> = << <<(X+V1)/integer>> ||
X <- [1,2,3] &&
_K1 := V1 <- maps:iterator(#{a=>2, b=>2, c=>2}, ordered)>>,
<<3,4,5>> = << <<(X+V1)/integer>> ||
<<X>> <= <<1,2,3>> &&
_K1 := V1 <- maps:iterator(#{a=>2, b=>2, c=>2}, ordered)>>,
<<3,4,5>> = << <<(V1+V2)/integer>> ||
_K1 := V1 <- maps:iterator(#{a=>1, b=>2, c=>3}, ordered) &&
_K2 := V2 <- maps:iterator(#{a=>2, b=>2, c=>2}, ordered)>>,
#{c := 3,b := 2,a := 1} = #{X => Y || X <- [a,b,c] && Y <- [1,2,3]},
#{c := 3,b := 2,a := 1} = #{X => Y || X <- [a,b,c] && <<Y>> <= <<1,2,3>>},
ok.
Expand Down Expand Up @@ -168,15 +173,19 @@ do_filter_pat_2(L1, L2) ->
Res.

cartesian(Config) when is_list(Config) ->
[{a,3}, {b,5}, {c,7}, {a,4}, {b,6}, {c,8}] = [{X, W+Y} || W <- [1,2],
X <- [a,b,c] && <<Y>> <= <<2,4,6>>],
[{a,3}, {a,4}, {b,5}, {b,6}, {c,7}, {c,8}] = [{X, W+Y} || X <- [a,b,c] &&
<<Y>> <= <<2,4,6>>, W <- [1,2]],
[{a,4}, {b,6}, {c,8}] = [{X, W+Y} || X <- [a,b,c] &&
<<Y>> <= <<2,4,6>>, W <- [1,2], (W + Y) rem 2 == 0],
<<4,2,5,3,6,4>> = << <<(X+V1+Y)/integer>> || X <- [1,2,3] &&
_K1 := V1 <- maps:iterator(#{a=>2, b=>2, c=>2}, ordered),
<<Y>> <= <<1,-1>> >>,
[{a,3}, {b,5}, {c,7}, {a,4}, {b,6}, {c,8}] =
[{X, W+Y} || W <- [1,2],
X <- [a,b,c] && <<Y>> <= <<2,4,6>>],
[{a,3}, {a,4}, {b,5}, {b,6}, {c,7}, {c,8}] =
[{X, W+Y} || X <- [a,b,c] &&
<<Y>> <= <<2,4,6>>, W <- [1,2]],
[{a,4}, {b,6}, {c,8}] =
[{X, W+Y} || X <- [a,b,c] &&
<<Y>> <= <<2,4,6>>, W <- [1,2], (W + Y) rem 2 == 0],
<<4,2,5,3,6,4>> = << <<(X+V1+Y)/integer>> ||
X <- [1,2,3] &&
_K1 := V1 <- maps:iterator(#{a=>2, b=>2, c=>2}, ordered),
<<Y>> <= <<1,-1>> >>,
ok.

nomatch(Config) when is_list(Config) ->
Expand All @@ -199,40 +208,35 @@ do_nomatch_2(L, Bin) ->

bad_generators(Config) when is_list(Config) ->

{'EXIT',{{bad_generators,{x,[1,2]}},_}} = (catch
[{X,Y} || X <- x &&
Y <- [1,2]]),
{'EXIT',{{bad_generators,{[],[4]}},_}} = (catch
[{X,Y} || X <- [1,2,3] &&
Y <- [1,2,3,4]]),
{'EXIT',{{bad_generators,{[3,4],[]}},_}} = (catch
[{X,Y} || X <- [1,2,3,4] &&
Y <- [1,2], X < 3]),
{'EXIT',{{bad_generators,{[3,4],[]}},_}} = (catch
<< <<(X+Y)/integer>> || X <- [1,2,3,4] &&
Y <- [1,2], X < 3>>),
{'EXIT',{{bad_generators,{[d],[]}},_}} = (catch
#{X => Y || X <- [a,b,c,d] &&
Y <- [1,2,3], Y > 1}),
{'EXIT',{{bad_generators,{x,[1,2]}},_}} =
catch [{X,Y} || X <- x && Y <- [1,2]],
{'EXIT',{{bad_generators,{[],[4]}},_}} =
catch [{X,Y} || X <- [1,2,3] && Y <- [1,2,3,4]],
{'EXIT',{{bad_generators,{[3,4],[]}},_}} =
catch [{X,Y} || X <- [1,2,3,4] && Y <- [1,2], X < 3],
{'EXIT',{{bad_generators,{[3,4],[]}},_}} =
catch << <<(X+Y)/integer>> || X <- [1,2,3,4] && Y <- [1,2], X < 3>>,
{'EXIT',{{bad_generators,{[d],[]}},_}} =
catch #{X => Y || X <- [a,b,c,d] && Y <- [1,2,3], Y > 1},

%% Make sure that line numbers point out the generator.

{'EXIT',{{bad_generators,{[],[4]}},
[{?MODULE,_,_,_}|_]}} =
(catch bad_generators([1,2,3],[1,2,3,4])),
catch bad_generators([1,2,3],[1,2,3,4]),

{'EXIT',{{bad_generators,{a,[2,3]}},
[{?MODULE,_,_,_}|_]}} =
(catch bad_generators_bc(a,[2,3])),
catch bad_generators_bc(a,[2,3]),

{'EXIT',{{bad_generators,{[2],[]}},
[{?MODULE,_,_,_}|_]}} =
(catch bad_generators_mc([1,2],[1])),
catch bad_generators_mc([1,2],[1]),

%% List comprehensions with improper lists.
{'EXIT',{{bad_generators,{d,[d]}},
[{?MODULE,_,_,_}|_]}} =
(catch bad_generators([a,b,c|d],[a,b,c,d])),
catch bad_generators([a,b,c|d],[a,b,c,d]),

ok.

Expand Down
Loading

0 comments on commit e94bae3

Please sign in to comment.