Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

quote |> Macro.to_string |> Code.string_to_quoted! injects indentation spacing in final quote string #11172

Closed
jiegillet opened this issue Aug 9, 2021 · 1 comment

Comments

@jiegillet
Copy link

Environment

  • Elixir & Erlang/OTP versions (elixir --version):
Erlang/OTP 24 [erts-12.0.1] [source] [64-bit] [smp:4:4] [ds:4:4:10] [async-threads:1] [jit] [dtrace]

Elixir 1.12.0 (compiled with Erlang/OTP 23)
  • Operating system: macOS 11.4

Current behavior

I tried quoting the following function, making it into a string and back into a quote:

def hi(name) do
  "hello\n#{name}" 
end

Currently:

iex(92)> quote do
...(92)>   def hi(name) do
...(92)>     "hello\n#{name}"
...(92)>   end
...(92)> end
{:def, [context: Elixir, import: Kernel],
 [
   {:hi, [context: Elixir], [{:name, [], Elixir}]},
   [
     do: {:<<>>, [],
      [
        "hello\n",       # Note the newline here...
        {:"::", [],
         [
           {{:., [], [Kernel, :to_string]}, [], [{:name, [], Elixir}]},
           {:binary, [], Elixir}
         ]}
      ]}
   ]
 ]}
iex(93)> |> Macro.to_string
"def(hi(name)) do\n  \"hello\n  \#{name}\"\nend"
iex(94)> |> tap(&IO.puts/1)
def(hi(name)) do
  "hello
  #{name}"       # ...is interpreted as an actual newline instead of being escaped...
end
"def(hi(name)) do\n  \"hello\n  \#{name}\"\nend"
iex(95)> |> Code.string_to_quoted!
{:def, [line: 1],
 [
   {:hi, [line: 1], [{:name, [line: 1], nil}]},
   [
     do: {:<<>>, [line: 2],
      [
        "hello\n  ",       # ...and the indentation after the newline is injected into the string
        {:"::", [line: 3],
         [
           {{:., [line: 3], [Kernel, :to_string]}, [line: 3],
            [{:name, [line: 3], nil}]},
           {:binary, [line: 3], nil}
         ]}
      ]}
   ]
 ]}

Expected behavior

I expected iex(95) to be identical to iex(92).

The string interpolation seems necessary to trigger the current behavior.
When I escape the newline as in "hello\\n#{name}", I get the expected behavior, but I can't escape the \n when using a multiline string.

@josevalim
Copy link
Member

This has been fixed in Elixir master since Macro.to_string has been rewritten to use the same code path as the code formatter. Thank you!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

No branches or pull requests

2 participants