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 2, 2024
1 parent ba3a364 commit 20b8592
Show file tree
Hide file tree
Showing 2 changed files with 78 additions and 38 deletions.
67 changes: 35 additions & 32 deletions lib/compiler/src/v3_core.erl
Original file line number Diff line number Diff line change
Expand Up @@ -1662,46 +1662,47 @@ zip_tq(Line, E, #izip{arg=[#igen{anno=#a{anno=GA}=GAnno,

%% Generate the clauses for the letrec.
AccPats = collect_for_zip(accpats, Generators),
{Cs, St} =
case member(nomatch, AccPats) of
true ->
%% At least one generator will never match.
{[], St3};

TailVars = collect_for_zip(tails, Generators),
Nc = #iapply{anno=GAnno,op=F,args=TailVars},
{Lc,Lps,St4} = lc_tq(Line, E, Qs, Nc, St3),

AccClause = case member(nomatch, AccPats) of
true ->
nomatch;
false ->
make_clause(LA, AccPats, AccGuard, Lps++[Lc])
end,

TailPats = collect_for_zip(tailpats, Generators),
TailClause = make_clause(LA, TailPats, [], [Mc]),

SkipPats = collect_for_zip(skip_pats, Generators),
SkipClause = make_clause(LA, SkipPats, [], [Nc]),

RefillPats0 = collect_for_zip(refillpats, Generators),
RefillClause =
case all(fun(X) -> X =:= nomatch end, RefillPats0) of
true ->
%% There are no map generators.
nomatch;
false ->
TailVars = collect_for_zip(tails, Generators),
Nc = #iapply{anno=GAnno,op=F,args=TailVars},
{Lc,Lps,St4} = lc_tq(Line, E, Qs, Nc, St3),

AccClause = make_clause(LA, AccPats, AccGuard, Lps++[Lc]),

TailPats = collect_for_zip(tailpats, Generators),
TailClause = make_clause(LA, TailPats, [], [Mc]),

RefillPats0 = collect_for_zip(refillpats, Generators),
RefillClause =
case all(fun(X) -> X =:= nomatch end, RefillPats0) of
true ->
%% There are no map generators.
[];
false ->
RefillPats = make_ignored(RefillPats0, TailVars),
RefillAs = collect_for_zip(refillas, Generators),
RefillBody = [C || C <- RefillAs, C =/= ignore],
[make_clause(LA, RefillPats, [], RefillBody++[Nc])]
end,

Cs0 = [AccClause, TailClause | RefillClause],
Cs1 = [C || C <- Cs0, C =/= nomatch],
{Cs1, St4}
RefillPats = make_ignored(RefillPats0, TailVars),
RefillAs = collect_for_zip(refillas, Generators),
RefillBody = [C || C <- RefillAs, C =/= ignore],
make_clause(LA, RefillPats, [], RefillBody++[Nc])
end,

Cs0 = [AccClause, TailClause, SkipClause, RefillClause],
Cs = [C || C <- Cs0, C =/= nomatch],

Fc = bad_generators(FcVars, Arg, lc),
Fun = #ifun{anno=GAnno,id=[],vars=CallVars,clauses=Cs,fc=Fc},
{#iletrec{anno=GAnno#a{anno=[list_comprehension|GA]},
defs=[{{Name,NumGenerators},Fun}],
body=append(collect_for_zip(pres, Generators)) ++
[#iapply{anno=GAnno,op=F,args=collect_for_zip(args, Generators)}]},
[],St}.
[],St4}.

%% bc_tq(Line, Exp, [Qualifier], More, State) -> {LetRec,[PreExp],State}.
%% This TQ from Gustafsson ERLANG'05.
Expand Down Expand Up @@ -1891,7 +1892,9 @@ collect_for_zip(What, Qs) ->
refillas ->
fun(#igen{refill={_, R}}) -> R end;
pres ->
fun(#igen{arg={Pre, _}}) -> Pre end
fun(#igen{arg={Pre, _}}) -> Pre end;
skip_pats ->
fun(#igen{skip_pat=SkipPat}) -> SkipPat end
end,
[F(Q) || #igen{} = Q <- Qs].

Expand Down
49 changes: 43 additions & 6 deletions lib/compiler/test/zlc_SUITE.erl
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ basic(Config) when is_list(Config) ->
mixed_zlc(),
zmc(),
filter_guard(),
filter_pattern(),
cartesian(),
nomatch(),
bad_generators().
Expand Down Expand Up @@ -146,6 +147,27 @@ filter_guard() ->
#{c := 3} = #{X => Y || X <- [a,b,c] && Y <- [1,2,3], Y rem 2 == 1, Y > 1},
#{c := 3,a := 1} = #{X => Y || X <- [a,b,c] && <<Y>> <= <<1,2,3>>, Y rem 2 == 1}.

filter_pattern() ->
[] = do_filter_pat_1([], []),
[] = do_filter_pat_1([a], [a]),
[] = do_filter_pat_1([{ok,a}], [{error,e}]),


[] = do_filter_pat_2([], []),
[] = do_filter_pat_2([a], [b]),
[] = do_filter_pat_2([{a,1}], [{b,1}]),
[{1,7}] = do_filter_pat_2([{a,1}], [{a,7}]),
[{1,7},{10,20}] = do_filter_pat_2([{a,1},{b,9},{x,10}],
[{a,7},{wrong,8},{x,20}]),

ok.

do_filter_pat_1(L1, L2) ->
[{A,B} || {ok,A} <- L1 && {ok,B} <- L2].

do_filter_pat_2(L1, L2) ->
[{A,B} || {Same,A} <- L1 && {Same,B} <- L2].

cartesian() ->
[{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>>],
Expand All @@ -159,13 +181,23 @@ cartesian() ->
ok.

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

id(I) -> I.
%% <<>> = do_nomatch_2([], <<>>),
%% <<>> = do_nomatch_2([a], <<1>>),
{'EXIT',{{bad_generators,{[1,2],<<3>>}},_}} = do_nomatch_2([1,2], <<3>>),

ok.

do_nomatch_1(L1, L2) ->
catch [{X, Y} || a=b=X <- L1 && Y <- L2].

do_nomatch_2(L, Bin) ->
catch << <<(X+Y)/integer>> || a=b=X <- L && <<Y>> <= Bin >>.

bad_generators() ->

Expand Down Expand Up @@ -214,6 +246,11 @@ bad_generators() ->
end,
ok.

%%% Common utilities.

id(I) -> I.


-file("bad_zlc.erl", 1).
bad_generators(L1,L2) -> %Line 2
[{I1, I2} || %Line 3
Expand Down

0 comments on commit 20b8592

Please sign in to comment.