Skip to content

Commit 73eeec2

Browse files
author
José Valim
committed
Keep head|tail format on splice, closes #1393
1 parent d195429 commit 73eeec2

File tree

2 files changed

+25
-19
lines changed

2 files changed

+25
-19
lines changed

lib/elixir/src/elixir_quote.erl

Lines changed: 13 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
%% Implements Elixir quote.
22
-module(elixir_quote).
3-
-export([escape/2, erl_escape/3, erl_quote/4, linify/2, unquote/6]).
3+
-export([escape/2, erl_escape/3, erl_quote/4, linify/2, unquote/6, join/5]).
44
-include("elixir.hrl").
55

66
%% Apply the line from site call on quoted contents.
@@ -55,6 +55,13 @@ unquote(File, Line, _Meta, _Left, Right, _Args) ->
5555
elixir_errors:syntax_error(Line, File, "expected unquote after dot with args to return an atom "
5656
"or a quoted call, got: ~ts", ['Elixir.Macro':to_string(Right)]).
5757

58+
join(_File, _Line, Left, Right, Rest) when is_list(Left), is_list(Right), is_list(Rest) ->
59+
Rest ++ Left ++ Right;
60+
61+
join(_File, _Line, Left, Right, Rest) ->
62+
[H|T] = lists:reverse(Rest ++ Left),
63+
lists:reverse([{ '|', [], [H, Right] }|T]).
64+
5865
%% Escapes the given expression. It is similar to quote, but
5966
%% lines are kept and hygiene mechanisms are disabled.
6067
escape(Expr, Unquote) ->
@@ -235,27 +242,16 @@ keystore(Key, Meta, Value) ->
235242

236243
%% Quote splicing
237244

238-
do_splice([{ '|', _, [{ unquote_splicing, _, [Left] }, Right] }|T], #elixir_quote{unquote=true} = Q, S) ->
245+
do_splice([{ '|', Meta, [{ unquote_splicing, _, [Left] }, Right] }|T], #elixir_quote{unquote=true} = Q, S) ->
239246
%% Process the remaining entries on the list.
240247
%% For [1, 2, 3, unquote_splicing(arg)|tail], this will quote
241248
%% 1, 2 and 3, which could even be unquotes.
242249
{ TT, QT } = do_splice(T, Q, S, [], []),
250+
{ TR, QR } = do_quote(Right, QT, S),
243251

244-
%% Now that we have [1,2,3], join it with the argument spliced.
245-
%% This is done with a ++ operation executed at compilation time.
246-
ListWithoutTail = do_splice_join(TT, Left),
247-
248-
%% Let's add the tail, which is done with a ++ operation at runtime
249-
%% unless Right is a list (which allows us to do it at compile time).
250-
%% Since the LastWithoutTail was already quoted, wrap it inside an
251-
%% unquote so it won't be quoted again.
252-
case is_list(Right) of
253-
true ->
254-
{ TR, QR } = do_quote(Right, QT, S),
255-
{ do_splice_join(ListWithoutTail, TR), QR };
256-
false ->
257-
do_quote(do_splice_join({ unquote, [], [ListWithoutTail] }, Right), QT, S)
258-
end;
252+
%% Do the joining at runtime when we are aware of the values.
253+
Args = [{ '__FILE__', [], nil }, ?line(Meta), Left, TR, TT],
254+
{ { { '.', Meta, [elixir_quote, join] }, Meta, Args }, QR#elixir_quote{unquoted=true} };
259255

260256
do_splice(List, Q, S) ->
261257
do_splice(List, Q, S, [], []).

lib/elixir/test/elixir/kernel/quote_test.exs

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -105,10 +105,10 @@ defmodule Kernel.QuoteTest do
105105
[1, 2, 3, 1, 2, 3]
106106

107107
assert quote(do: [unquote_splicing(contents)|val]) ==
108-
quote(do: :"Elixir.Kernel".++([1, 2, 3], val))
108+
quote(do: [1, 2, 3 | val])
109109

110110
assert quote(do: [unquote_splicing(contents)|unquote([4])]) ==
111-
quote(do: :"Elixir.Kernel".++([1, 2, 3], [4]))
111+
quote(do: [1, 2, 3, 4])
112112
end
113113

114114
test :splice_on_stab do
@@ -121,6 +121,16 @@ defmodule Kernel.QuoteTest do
121121
assert fun.(1, 2, 3) == :ok
122122
end
123123

124+
test :splice_on_definition do
125+
defmodule Hello do
126+
def world([unquote_splicing(["foo", "bar"])|rest]) do
127+
rest
128+
end
129+
end
130+
131+
assert Hello.world(["foo", "bar", "baz"]) == ["baz"]
132+
end
133+
124134
test :when do
125135
assert {:->,_,[{[{:when,_,[1,2,3,4]}],_,5}]} = quote(do: (1, 2, 3 when 4 -> 5))
126136
assert {:->,_,[{[{:when,_,[1,2,3,4]}],_,5}]} = quote(do: ((1, 2, 3) when 4 -> 5))

0 commit comments

Comments
 (0)