diff --git a/lib/elixir/src/elixir_quote.erl b/lib/elixir/src/elixir_quote.erl index 68a8483cb8..5271f676ef 100644 --- a/lib/elixir/src/elixir_quote.erl +++ b/lib/elixir/src/elixir_quote.erl @@ -152,10 +152,7 @@ escape(Expr, Op, Unquote) -> op=Op, unquote=Unquote }, - case Unquote of - true -> do_quote(Expr, Q); - false -> do_escape(Expr, Q) - end + do_escape(Expr, Q) catch Kind:Reason:Stacktrace -> Pruned = lists:dropwhile(fun @@ -165,6 +162,22 @@ escape(Expr, Op, Unquote) -> erlang:raise(Kind, Reason, Pruned) end. +%% Quote - unquote + +do_escape({quote, Meta, Args}, #elixir_quote{unquote=true} = Q) when is_list(Meta), is_list(Args) -> + do_quote({quote, Meta, Args}, Q#elixir_quote{unquote=false}); + +do_escape({unquote, Meta, [Expr]}, #elixir_quote{unquote=true} = Q) when is_list(Meta) -> + do_quote({unquote, Meta, [Expr]}, Q); + +do_escape({{{'.', Meta, [Left, unquote]}, _, [Expr]}, _, Args}, #elixir_quote{unquote=true} = Q) when is_list(Meta) -> + do_escape_call(Left, Meta, Expr, Args, Q); + +do_escape({{'.', Meta, [Left, unquote]}, _, [Expr]}, #elixir_quote{unquote=true} = Q) when is_list(Meta) -> + do_escape_call(Left, Meta, Expr, nil, Q); + +% Tuples + do_escape({Left, Meta, Right}, #elixir_quote{op=escape_and_prune} = Q) when is_list(Meta) -> TM = [{K, V} || {K, V} <- Meta, (K == no_parens) orelse (K == line) orelse (K == delimiter)], TL = do_escape(Left, Q), @@ -250,6 +263,11 @@ do_escape(Fun, _) when is_function(Fun) -> do_escape(Other, _) -> bad_escape(Other). +do_escape_call(Left, Meta, Expr, Args, Q) -> + All = [Left, {unquote, Meta, [Expr]}, Args, Q#elixir_quote.context], + TAll = [do_escape(X, Q) || X <- All], + {{'.', Meta, [elixir_quote, dot]}, Meta, [meta(Meta, Q) | TAll]}. + escape_map_key_value(K, V, Map, Q) -> MaybeRef = if is_reference(V) -> V; diff --git a/lib/elixir/test/elixir/macro_test.exs b/lib/elixir/test/elixir/macro_test.exs index 36eb3ba393..acfe657b5a 100644 --- a/lib/elixir/test/elixir/macro_test.exs +++ b/lib/elixir/test/elixir/macro_test.exs @@ -82,6 +82,9 @@ defmodule MacroTest do contents = quote(unquote: false, do: unquote(x)) assert Macro.escape(contents, unquote: true) == {:x, [], MacroTest} + + contents = %{foo: quote(unquote: false, do: unquote(1))} + assert Macro.escape(contents, unquote: true) == {:%{}, [], [foo: 1]} end test "with generated" do @@ -97,6 +100,8 @@ defmodule MacroTest do test "with remote unquote" do contents = quote(unquote: false, do: Kernel.unquote(:is_atom)(:ok)) assert eval_escaped(contents) == quote(do: Kernel.is_atom(:ok)) + + assert eval_escaped(%{foo: contents}) == %{foo: quote(do: Kernel.is_atom(:ok))} end test "with nested unquote" do @@ -140,6 +145,9 @@ defmodule MacroTest do quote(unquote: false, do: [1, unquote_splicing([2]), 3, unquote_splicing([4]) | [5]]) assert eval_escaped(contents) == [1, 2, 3, 4, 5] + + contents = %{foo: quote(unquote: false, do: [1, 2, unquote_splicing([3, 4, 5])])} + assert eval_escaped(contents) == %{foo: [1, 2, 3, 4, 5]} end test "does not add context to quote" do