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 includes three changes:
1. Previously, the parallel compiler released at once all processes
depending on a particular module. This commit ensures they are
released according to the number of cores available. This ensures
we have fewer modules being compiled at once
2. Garbage collect the current process every time we are waiting
for another module to be compiled
3. Do not compile a module for files that simply define modules
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 mechanism of lazily customizing message/1 was very
dangerous, as you could have errors while calculating the message
and those would shop up just when the exception is printed, leading
to further breakage.
Closes#1747