Lately I’ve been digging into the elixir AST for learning purposes. There is a section in the elixir docs(Syntax reference — Elixir v1.16.0) 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?