Skip to content
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
104 changes: 104 additions & 0 deletions lib/elixir/lib/macro.ex
Original file line number Diff line number Diff line change
Expand Up @@ -2674,6 +2674,69 @@ defmodule Macro do
end
end

defp dbg_ast_to_debuggable({:with, meta, args} = ast, _env) do
{opts, clauses} =
List.pop_at(args, -1)

modified_clauses =
Enum.flat_map(clauses, fn
{:<-, _meta, [left, right]} = clause ->
quote do
[
line = Keyword.get(unquote(meta), :line),
code = unquote(Macro.escape(clause)),
value = unquote(right),
unquote(:<-)({{line, code, value}, unquote(left)}, {{line, code, value}, value})
]
end

# Other expressions are omitted.
expr ->
[expr]
end)

modified_opts =
case opts do
[do: do_code] ->
else_code =
quote do
[
unquote(:->)(
[{unquote({:unmatched_ast, [], Elixir}), unquote({:result, [], Elixir})}],
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FYI: You typically want to use unique_var for this, there are other examples in the dbg code around.

{:__else__, unquote({:unmatched_ast, [], Elixir}),
unquote({:result, [], Elixir})}
)
]
end

[do: {:__matched__, do_code}, else: else_code]

[do: do_code, else: else_code] ->
else_code =
Enum.map(else_code, fn
{:->, meta, [[left], right]} = else_clause ->
quote do
unquote(:->)(
[{unquote({:unmatched_ast, [], Elixir}), unquote(left)}],
{:__else__, unquote({:unmatched_ast, [], Elixir}),
{Keyword.get(unquote(meta), :line), unquote(Macro.escape(else_clause))},
unquote(right)}
)
end
end)

[do: {:__matched__, do_code}, else: else_code]
end

modified = modified_clauses ++ [modified_opts]
modified_with_ast = {:with, meta, modified}

quote do
value = unquote(modified_with_ast)
{:with, unquote(Macro.escape(ast)), [], value}
end
end

# Any other AST.
defp dbg_ast_to_debuggable(ast, _env) do
quote do: {:value, unquote(escape(ast)), unquote(ast)}
Expand Down Expand Up @@ -2828,6 +2891,47 @@ defmodule Macro do
{formatted, result}
end

defp dbg_format_ast_to_debug({:with, _ast, [], {:__matched__, value}}, options) do
formatted = [
dbg_maybe_underline("All with clauses matched, result:", options),
?\n,
inspect(value, options),
?\n
]

{formatted, value}
end

defp dbg_format_ast_to_debug(
{:with, _ast, [], {:__else__, {line, clause_ast, _}, value}},
options
) do
formatted = [
dbg_maybe_underline("With clause unmatched on line #{line}", options),
?\n,
dbg_format_ast_with_value(clause_ast, value, options)
]

{formatted, value}
end

defp dbg_format_ast_to_debug(
{:with, _ast, [],
{:__else__, {line, clause_ast, clause_result}, {else_line, else_ast}, value}},
options
) do
formatted = [
dbg_maybe_underline("With clause unmatched on line #{line}", options),
?\n,
dbg_format_ast_with_value(clause_ast, clause_result, options),
dbg_maybe_underline("Then else clause matched on line #{else_line}", options),
?\n,
dbg_format_ast_with_value(else_ast, value, options)
]

{formatted, value}
end

defp dbg_format_ast_to_debug({:value, code_ast, value}, options) do
{dbg_format_ast_with_value(code_ast, value, options), value}
end
Expand Down
63 changes: 63 additions & 0 deletions lib/elixir/test/elixir/macro_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -652,6 +652,69 @@ defmodule MacroTest do
"""
end

test "with with/1 (all clauses match)" do
opts = %{width: 10, height: 15}

{result, formatted} =
dbg_format(
with {:ok, width} <- Map.fetch(opts, :width),
double_width = width * 2,
IO.puts("just a side effect"),
{:ok, height} <- Map.fetch(opts, :height) do
{:ok, double_width * height}
end
)

assert result == {:ok, 300}

assert formatted =~ "macro_test.exs"

assert formatted =~ """
All with clauses matched, result:
{:ok, 300}
"""
end

test "with with/1 (no else)" do
opts = %{width: 10}

{result, formatted} =
dbg_format(
with {:ok, width} <- Map.fetch(opts, :width),
{:ok, height} <- Map.fetch(opts, :height) do
{:ok, width * height}
end
)

assert result == :error

assert formatted =~ "macro_test.exs"
assert formatted =~ "With clause unmatched on line"
assert formatted =~ "{:ok, height} <- Map.fetch(opts, :height) #=> :error"
end

test "with with/1 (else clause)" do
opts = %{width: 10}

{result, formatted} =
dbg_format(
with {:ok, width} <- Map.fetch(opts, :width),
{:ok, height} <- Map.fetch(opts, :height) do
width * height
else
:error -> 0
end
)

assert result == 0

assert formatted =~ "macro_test.exs"
assert formatted =~ "With clause unmatched on line"
assert formatted =~ "{:ok, height} <- Map.fetch(opts, :height) #=> :error"
assert formatted =~ "Then else clause matched on line"
assert formatted =~ "->(:error, 0) #=> 0"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is being formatted incorrectly.

end

test "with \"syntax_colors: []\" it doesn't print any color sequences" do
{_result, formatted} = dbg_format("hello")
refute formatted =~ "\e["
Expand Down