Astarno

Astarno

Manipulate the AST before compilation

Hi there,

Is there any way to change/edit the code/ast of a module before it compiles? I am trying to use the Interceptor library to add logging functionality to a module. In order to work, this library requires all functions to be traced to either be wrapped in a special do block or to be annotated.

Now, I would like for the user to be able to just write his regular code without having to worry about this wrapping/annotation at all. As such, my question is if it would be possible to leverage some metaprogramming, module callbacks or something else to automatically make the necessary changes to the code at compile time.

For example, let’s say I want to trace all functions, could I make something such that the code below:

defmodule Stack do
  use GenServer
  require Interceptor, as: I

      def start_link(default) when is_list(default) do
        GenServer.start_link(__MODULE__, default)
      end
  
      @impl true
      def init(stack) do
        {:ok, stack}
      end
  
      @impl true
      def handle_call(:pop, _from, [head | tail]) do
        {:reply, head, tail}
      end
  
      @impl true
      def handle_cast({:push, element}, state) do
        {:noreply, [element | state]}
      end

end

Either gets manipulated to look like this:

defmodule Stack do
  use GenServer
  require Interceptor, as: I

    I.Intercept do 
       def start_link(default) when is_list(default) do
         GenServer.start_link(__MODULE__, default)
       end

       @impl true
       def init(stack) do
         {:ok, stack}
       end

       @impl true
       def handle_call(:pop, _from, [head | tail]) do
         {:reply, head, tail}
       end

       @impl true
       def handle_cast({:push, element}, state) do
         {:noreply, [element | state]}
       end
    end
end

Or gets manipulated to look like this:

defmodule Stack do
  use GenServer
  require Interceptor, as: I

      @intercept true
      def start_link(default) when is_list(default) do
        GenServer.start_link(__MODULE__, default)
      end
  
      @impl true
      @intercept true
      def init(stack) do
        {:ok, stack}
      end
  
      @impl true
      @intercept true
      def handle_call(:pop, _from, [head | tail]) do
        {:reply, head, tail}
      end
  
      @impl true
      @intercept true
      def handle_cast({:push, element}, state) do
        {:noreply, [element | state]}
      end

end

Any help would be greatly appreciated!

Marked As Solved

josevalim

josevalim

Creator of Elixir

By design we don’t allow so. Any transformation in the code has to be explicit. So you have to wrap it with the block yourself. :slight_smile:

Where Next?

Popular in Questions Top

JDanielMartinez
Hi! May someone helps me, please! I have two apps into an umbrella project: the first one is Database, which manages queries, and the se...
New
yawaramin
In the Dialyzer docs ( http://erlang.org/doc/man/dialyzer.html#requesting-or-suppressing-warnings-in-source-files ), there is a way to tu...
New
nsuchy
Hi. I’ve noticed that Windows Powershell has it’s own IEX command and you cannot access Elixir’s IEX due to the conflict. This isn’t a cr...
New
lastday4you
I wanted to check elixir version in phoenix because i found that my elixir is 1.5 but when i use Enum.chunk_by it said the function is un...
New
minhajuddin
I have seen a lot of code which picks the first element from a list using Enum.at(0) instead of List.first. Is there a reason why people ...
New
chensan
I have a User schema with a :from_id field set to type :string: defmodule TweetBot.Repo.Migrations.CreateUsers do use Ecto.Migration ...
New
mathew4509
I have a list say x = ["23gh", "56kh", "97mh"] I would like to pass each element to Val in each iteration. Say, in iteration 1 -------...
New
Patoshizzle
After calling mix ecto.create I get this error: 17:00:32.162 [error] GenServer #PID<0.412.0> terminating ** (Postgrex.Error) FATAL...
New
belgoros
I’m not a pro in using Regex and can’t figure out why the following behaviour happens, especially if we take into account the difference ...
New
lucidguppy
I have a super simple question about elixir - how would I take a file like this foo bar baz and output a new file that enumerates th...
New

Other popular topics Top

Brian
What is the proper way to load a module from a file in to IEX? In the python world, doing something like this pretty standard: from ....
New
sergio
In Ruby, I can go: User.find_by(email: "foobar@email.com").update(email: "hello@email.com") How can I do something similar in Elixir? ...
New
gshaw
What is the idiomatic way of matching for not nil in Elixir? E.g., First way: defp halt_if_not_signed_in(conn, signed_in_account) when...
New
jerry
Good day to you all. I have been struggling to get a query involving like and ilike to work. Can anyone assist me on this, please? pro...
New
ycv005
I have followed this StackOverflow post to install the specific version of Erlang. And When I am running mix ecto.setup then getting fol...
New
mgjohns61585
Could someone help me? I'm making my first elixir program, number guessing game. I can't figure out how to convert the user's guess from ...
New
msaraiva
Surface is an experimental library built on top of Phoenix LiveView and its new LiveComponent API that aims to provide a more declarative...
564 42633 214
New
Qqwy
Original source of discussion: This topic on the Pragmatic Programmers' Functional Web Development with Elixir, OTP, and Phoenix forum. ...
New
lucidguppy
I have a super simple question about elixir - how would I take a file like this foo bar baz and output a new file that enumerates th...
New
AstonJ
by Lance Halvorsen Elixir and Phoenix are generating tremendous excitement as an unbeatable platform for building modern web application...
460 27162 124
New

We're in Beta

About us Mission Statement