KoviRobi

KoviRobi

Debug function call macro

Hi,

I’ve written the following to debug function calls, not sure if it’s useful for anyone else, and if so should I put it somewhere?

iex(1)> require Debug; import Debug
Debug

iex(2)> inspect_call(round(2.3*4.5))
round(10.35) -> 10

iex(3)> inspect_call(inspect({:foo, 1+2}))
inspect({:foo, 3}) -> "{:foo, 3}"
"{:foo, 3}"

iex(4)> inspect_call(IO.inspect(1) + IO.inspect(2))
1
2
+(1, 2) -> 3
3

It’s hopefully a fairly easily understandable piece of macro, though only evaluating the arguments once did make it more complicated. The first pattern-matching is taken from the Macro.decompose_call/1 function.

defmodule Debug do
  defmacro inspect_call(block) do
    {name, args, rebuild} =
      case block do
        {:{}, _metadata_a, args} when is_list(args) ->
          raise CompileError,
            description: "Using inspect_call on a map literal is not supported",
            file: __CALLER__.file,
            line: __CALLER__.line

        {{:., metadata_a, [remote, function]}, metadata_b, args}
        when is_tuple(remote) or is_atom(remote) ->
          {
            Macro.to_string({{:., metadata_a, [remote, function]}, [no_parens: true], []}),
            args,
            fn new_args -> {{:., metadata_a, [remote, function]}, metadata_b, new_args} end
          }

        {name, metadata_a, args} when is_atom(name) and is_atom(args) ->
          {to_string(name), [], fn _new_args -> {name, metadata_a, args} end}

        {name, metadata_a, args} when is_atom(name) and is_list(args) ->
          {to_string(name), args, fn new_args -> {name, metadata_a, new_args} end}

        _ ->
          raise CompileError,
            description:
              "Cannot understand function call #{Macro.to_string(block)}",
            file: __CALLER__.file,
            line: __CALLER__.line
      end

    eval_args =
      for n <- 1..length(args) do
        Macro.unique_var(:"eval_arg_#{n}", __MODULE__)
      end

    return_value = Macro.unique_var(:return_value, __MODULE__)

    quote do
      unquote_splicing(
        for {e_a, a} <- Enum.zip(eval_args, args) do
          quote do
            unquote(e_a) = unquote(a)
          end
        end
      )

      IO.write(
        unquote(name) <>
          "(" <>
          (unquote(eval_args)
           |> Enum.map(&inspect/1)
           |> Enum.join(", ")) <>
          ")"
      )

      unquote(return_value) = unquote(rebuild.(eval_args))

      IO.puts(" -> " <> inspect(unquote(return_value)))

      unquote(return_value)
    end
  end
end

Most Liked

sabiwara

sabiwara

Elixir Core Team

Good news: starting from Elixir 1.15, prying for dbg in IEx becomes opt-in :tada:.

hauleth

hauleth

There is already such macro in Kernel

Last Post!

Sebb

Sebb

this will be the best feature since dbg

Where Next?

Popular in Guides/Tuts Top

smpallen99
Some advice for Elixir programmers. I was reviewing someone’s Elixir Code yesterday and found a deadlock condition bug in a GenServer im...
New
jswny
Hello everyone, I recently redesigned my entire deployment process for Phoenix apps based on Docker. I really like the strategy that I ca...
New
njwest
Greetings: I just wrote a step-by-step guide on building a Phoenix 1.3 JWT Auth API with Guardian JWTs and Comeonin password hashing. I ...
New
siever
I just wrote a simple guide on how you can setup a productive elixir development environment in vim. Its really easy, just a few steps. ...
New
1player
A question I had when first learning contexts and Ecto was how to expand the default context API to support more flexible queries. Usuall...
New
sergio
Wrote this guide on how to integrate DropzoneJS with Phoenix Liveview. Hope it helps someone out! Woah read that title again, what a ...
New
caspg
Hi everyone, I recently implemented a real-time search feature in a Phoenix application using LiveView and Tailwind, and I wanted to sha...
New

Other popular topics Top

JeremM34
Hello, how can I check the Phoenix version ? Thanks !
New
New
vonH
In asking this question I am more interested about the expressiveness of the language itself and less concerned about the availability of...
New
dogweather
I wrote this comment on r/haskell, and it’s not popular there. :wink: But I think I’m on to something… Haskell reminds me of Java, and e...
New
sergio_101
I am VERY much an elixir newbie. I have taken one elixir course and one phoenix course on Udemy. During that course, I saw the instructor...
New
shijith.k
I am trying to start a new phoenix project with elixir 1.9, but mix phx.new does not work. It says that ** (Mix) The task "phx.new" could...
New

We're in Beta

About us Mission Statement