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

chokchit
** (DBConnection.ConnectionError) connection not available and request was dropped from queue after 2733ms. You can configure how long re...
New
tduccuong
Hi, is there any work on GUI with Elixir, that is similar to Electron/Javascript? My idea is to bundle Phoenix and BEAM into a single se...
New
jononomo
I am trying to figure out how Mix knows whether the environment is test, dev, or prod – where is this set? Thanks.
New
shahryarjb
Hello, I get Persian date from my client and convert it to normal calendar like this: def jalali_string_to_miladi_english_number(persi...
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
freewebwithme
Using vs code and installed ElixirLS: support and debugger. And I got an error popped up on start up says Failed to run ‘elixir’ comma...
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
fayddelight
I tried installing elixir 1.11.2 erlang 23.3.4 via asdf in my zsh shell. Enabled the versions locally and globally. When I list them ...
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
JorisKok
I have a server on AWS, and was running a load test using artillery. When looking at the Phoenix dashboard I see the Ports going to 100% ...
New

Other popular topics Top

chrismccord
As promised, the first release candidate of Phoenix 1.3.0 is out! This release focuses on code generators with improved project structure...
New
albydarned
Hello all! I am typing this post from my new MacBook Pro with the M1 chip. I’m loving it so far, and will probably use it as my daily dr...
New
lessless
I believe there are people here who are dealing with CSV files import on the daily basis, and since Excel is a really popular tool there ...
New
AngeloChecked
What learn first? Rust or Elixir Hi Elixir community! I’m here because i want learn a new language. I’m a junior developer and mainly i ...
New
gausby
I asked this very same question on twitter and got some interesting feedback, but I thought it would be a good question to ask here as we...
1207 39523 209
New
aalberti333
As the title describes, I’m trying to run Enum.map() over a list of key/value pairs, where the value is a map. My data looks like this: ...
New
saif
Hello everyone, Long time lurker first time poster here. I’ve recently begun working on Elixir full-time again! :raised_hands: It’s been...
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
dokuzbir
I want to highlight html closing tags when i click a html tag. That works in .html files but doesnt work for html.eex templates. How can...
New
svb
Hi! Currently I want to submit a form by pressing the Enter key. However, since my input field is of type “textarea” this is just adds a...
New

We're in Beta

About us Mission Statement