dorgan
Is there a complete Elixir AST reference?
Lately I’ve been digging into the elixir AST for learning purposes. There is a section in the elixir docs(Syntax reference — Elixir v1.20.2) that describes the ast and gives some examples of it.
It mentions that the ast is made of:
- atoms - such as
:foo- integers - such as
42- floats - such as
13.1- strings - such as
"hello"- lists - such as
[1, 2, 3]- tuples with two elements - such as
{"hello", :world}- tuples with three elements, representing calls or variables
Regarding the last point, it then says:
the first element is an atom (or another tuple), the second element is a list of two-element tuples with metadata (such as line numbers) and the third is a list of arguments.
What I didn’t find so far is what is meant by “or another tuple”. Moreover, when that element is a tuple there seem to be some cases where elixir gives them a special meaning.
For example, consider the “dot syntax”:
quote do
foo.bar(:baz)
end
{{:., [], [{:foo, [], Elixir}, :bar]}, [], [:baz]}
The first element there is the tuple {:., [], [{:foo, [], Elixir}, :bar]} that represents foo . :bar, so here the dot is a binary operator. If that is used as the first element in another three-tuple ast node, then it turns into foo.bar(), and any arguments will be put inside the parens, in this case foo.bar(:baz).
This does not happen with other operators. For example, this node:
{{:+, [], [{:foo, [], Elixir}, :bar]}, [], []}
Gets turned into foo + :bar(). So this tells me the dot expression is a special case. This in itself is not a surprise, but how many other special cases do exist?
By playing around I found another special case with the multi alias syntax. This expression:
Foo.{Bar, Baz}
is represented by this ast:
{{:., [],
[
{:__aliases__, [], [:Foo]},
:{}
]}, [],
[
{:__aliases__, [], [:Bar]},
{:__aliases__, [], [:Baz]}
]}
The first element is again the dot operator tuple:
{:., [], [{:__aliases__, [], [:Foo]}, :{}]}
which in this case means Foo . :{}. The difference is that now if that tuple is used as the first element in another three-element tuple node, the arguments are put inside of the curly braces:
Foo.{Bar, Baz}
No matter how bizarre the arguments are:
{{:., [], [ {:__aliases__, [], [:Foo]}, :{} ]}, [], [ {:__aliases__, [], [:Bar]}, :baz, {:+, [], [1, 2]} ]}
#=> Foo.{Baz, :baz, 1 + 2}
So again, the dot operator when the right hand side is the :{} atom has special meaning.
I’m finding all of this by playing around, since the elixir docs don’t cover these cases.
The question is: is there a reference of the Elixir AST, or some section/comments/issue that documents all the cases where ast nodes are given special meaning?
Most Liked
dorgan
If you’re still interested, I wrote a blog post with everything I learned so far about the AST:
I’ll try and see if I can make a PR to the elixir docs to fill the missing parts in the syntax reference
marciol
I’m subscribing this topic. It’d be interesting to know if such documentation exists.
dorgan
This is correct, the formatter works with an algebra document since quite a lot of data is lost when parsing to the AST
With https://ast.ninja/ you can play around and see both the AST and the albegra document for any given elixir code(click Add and then Code.Formatter.to_algebra/2)
Popular in Discussions
Other popular topics
Categories:
Sub Categories:
Forums
Popular Tags
- #ecto
- #liveview
- #troubleshooting
- #learning-elixir
- #deployment
- #library
- #erlang
- #testing
- #genserver
- #mix
- #absinthe
- #remote-other
- #otp
- #plug
- #how-to-question
- #macros
- #postgres
- #channels
- #elixirconf
- #exunit
- #discussion
- #javascript
- #code-sync
- #podcasts
- #onsite
- #dialyzer
- #docker
- #authentication
- #umbrella
- #full-time-contract
- #podcasts-by-brainlid
- #ecto-query
- #elixir-ls
- #phoenix_html
- #iex
- #blog-post
- #graphql
- #genstage
- #ai
- #websockets
- #supervisor
- #advent-of-code
- #elixirconf-us
- #distillery
- #processes
- #forms
- #api
- #metaprogramming
- #security
- #performance








