The previous representation was very hard to compose
and very often required the AST nodes to be created
manually.
The current approach is easier to compose because
the node is represented as any other operator as long
as it is wrapped in parentheses.
For example, imagine we have pairs of patterns and
the code to be executed for that pattern, and we want
to inject them into a case. It can now be writen as:
pairs = Enum.map pairs, fn { pattern, expr } ->
quote do: (unquote(pattern) -> unquote(expr))
end
quote do
case unquote(condition), do: unquote(pairs)
end
Compare to the previous implementation:
pairs = Enum.map pairs, fn { pattern, expr } ->
{ [pattern], [], expr }
end
pairs = { :->, [], pairs }
quote do
case unquote(condition), do: unquote(pairs)
end
This commit also simplifies macro expansion for both imports and aliases
to always give higher preference to the macro environment rather than
the caller one, if such is available. The deal is to simplify both the
code and understanding of how macros work.
The previous AST came from the fact `fn -> end` was a shortcut
for `function do ... end`. But now since the original no longer
exists, it seems saner to update `fn -> end` AST.
We also rename Binary.Chars to String.Chars.
As Binary.Chars was the protocol used for interpolation,
it is semantically correct to have a protocol that works
on strings, instead of raw binaries.
Prior to this commit, Elixir allowed too many ambiguous calls
by ommitting the parentheses:
do_something 1, is_list [], 3
[1, is_atom :foo, 3]
Both cases above would lead to a compilation error, as an attempt
to call is_list/2 and is_atom/2 would happen. Those examples will
now raise a syntax error, pointing to the ambiguous location.
We have disallowed such examples throughout the language with
the exception of one argument calls:
assert is_list []
Examples as above are extremely frequent and were kept as is.