DidactMacros

DidactMacros

Regarding AST form with qualified call

I’ve been reading a great AST guide that I really recommend.

One of the examples given in the first part correctly states that…

quote do
  Foo.{Bar, Baz}
end
#=>
{
  {:., [], [{:__aliases__, [], [:Foo]}, :{}]},
  [],
  [{:__aliases__, [], [:Bar]}, {:__aliases__, [], [:Baz]}]
}

There is an explanation given in the guide as to why the form [alias, :{}] is used, but I don’t really understand why there would be ambiguity in using the form below…

quote do
    Foo.{Bar, Baz}
end
#=>
  {
      :., 
      [], 
      [
          {:__alias__, [], [:Foo]}, 
          {:{}, [], [{:__alias__, [], [:Bar]}, {:__alias__, [], [:Baz]}]}
      ]
  }

I put the above hypothetical AST in a Macro.to_string call, and I got the following error.

** (CaseClauseError) no case clause matching: :Bar
    (elixir 1.16.0) lib/code/formatter.ex:2319: Code.Formatter.force_args?/2
    (elixir 1.16.0) lib/code/formatter.ex:1172: Code.Formatter.call_args_to_algebra_no_blocks/6
    (elixir 1.16.0) lib/code/formatter.ex:1109: Code.Formatter.call_args_to_algebra/6
    (elixir 1.16.0) lib/code/formatter.ex:1056: Code.Formatter.local_to_algebra/5
    (elixir 1.16.0) lib/code/formatter.ex:1695: anonymous fn/5 in Code.Formatter.args_to_algebra_with_comments/7
    (elixir 1.16.0) lib/code/formatter.ex:1998: Code.Formatter.each_quoted_to_algebra_without_comments/4
    (elixir 1.16.0) lib/code/formatter.ex:1984: Code.Formatter.quoted_to_algebra_with_comments/6
    iex:33: (file)

Is my AST not correct?

Marked As Solved

al2o3cr

al2o3cr

It’s only normally written in the context of an alias statement, like alias Foo.{Bar, Baz}.

Interestingly, the parser won’t let you write a function named {} explicitly, but one can be created by using a macro to build the AST:

defmodule WeirdMacro do
  defmacro do_fun(name) do
    {:def, [context: Elixir, import: Kernel],
     [
       {name, [context: Elixir],
        [{:x, [if_undefined: :apply], Elixir}, {:y, [if_undefined: :apply], Elixir}]},
       [
         do: {{:., [], [{:__aliases__, [alias: false], [:IO]}, :inspect]}, [],
          [
            {{:x, [if_undefined: :apply], Elixir},
             {:y, [if_undefined: :apply], Elixir}}
          ]}
       ]
     ]}
  end
end

defmodule Foo do
  require WeirdMacro

  WeirdMacro.do_fun(:{})
end

Foo.{:arg1, :arg2}

I’m unsure when such a function would be useful - maybe in a complex DSL? - but it’s neat to see that it’s possible.

Also Liked

al2o3cr

al2o3cr

The AST is expecting :__aliases__; not sure where the singular form has appeared from.

Fixing that in your sample AST and calling Macro.to_string produces:

Foo . {Bar, Baz}

It may help to contemplate this syntax, which expands to identical AST as Foo.{Bar, Baz}:

Foo."{}"(Bar, Baz)

Foo."{}" corresponds to {:., [], [{:__aliases__, [], [:Foo]}, :{}]}.

This is the same shape that a normal function call like Foo.huh(Bar, Baz) would produce, except the function being called has the otherwise-impossible name {}.

Where Next?

Popular in Questions Top

Kurisu
For example for a current url like http://localhost:4000/cosmetic/products?_utf8=✓&query=perfume&page=2, I would like to get: ...
New
nobody
How to bind a phoenix app to a specific ip address? could not find anything about that, nowhere, unfortunately, but for me this is quite...
New
hariharasudhan94
lets say i have a sample like a = 20; b = 10; if (a > b) do {:ok, "a"} end if (a < b) do {:ok, b} end if (a == b) do {:ok, "equa...
New
Tee
can someone please explain to me how Enum.reduce works with maps
New
Emily
I have VueJS GUIs with the project generated using Webpack. I have Elixir modules that will need to be used by the VueJS GUIs. I forese...
New
aadeshere1
I have a another noob question about loop. Since elixir is immutable, while loop is not directly possible. total = 10 while total != 0 ...
New
chrisalley
ExUnit now has describe blocks which is a welcome addition coming from RSpec. In the docs, it states that nested hierarchies of describe ...
New
fireproofsocks
I’m working on defining a simple Ecto schema for a table (in PostGres), but I don’t see where I can define a column as NOT NULL. Conside...
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
New

Other popular topics Top

vertexbuffer
Hello, can anybody help here..? I have a list of players and I what to delete an element, but every for loop the list is reverting to ori...
New
TunkShif
This post is an instruction guide to help you setup your Neovim for Elixir development from scratch. It includes general information on h...
274 42158 114
New
Nvim
Anybody knows a comprehensive comparison of Django and Phoenix, thanks for the help. Where are they similar? Where do they differ the m...
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
JeremM34
Hello, how can I check the Phoenix version ? Thanks !
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
alice
Hey, Just curious what are the main benefits of Elixir compared to Clojure? When is Elixir more useful than Clojure and vice versa? Th...
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
komlanvi
Hi everyone, I was playing with phoenix liveView but I run into an issue. I have a form and want to validate each input text when the te...
New
jaysoifer
Is there a way to rollback a specific migration and only that one (“skipping” all the other ones)? Would mix ecto.rollback -v 200809061...
New

We're in Beta

About us Mission Statement