Disclaimer:  I've worked around all these with various helpers (that I 
really should package up into a library sometime...), but they are 
significantly more verbose than if the AST was just regular to begin with, 
so this is mostly bikeshedding as I can keep working that way, but these 
are annoying irritations that bug me on a near daily basis.

On Tuesday, April 16, 2019 at 11:02:23 AM UTC-6, José Valim wrote:
>
> I am sorry but I cannot understand what you are talking about.
>
> If you are saying that having lists and tuples being literals are weird 
> and that they should be regular ASTs (i.e. three elem tuples), then I 
> recommend you to try doing those changes in an Elixir fork and see how it 
> impacts the language.
>

Considering full forms still compile fine:
```elixir
iex(2)> {:{}, [], [{:__block__, [], [:a]}, 42]} |> Macro.to_string 
"{:a, 42}"
```
Then the only thing it would really affect are the consumers of AST, which 
would have a few effects that the major of which include though are not 
limited to:

1. Matching AST nodes would be more simple as they are always 3-tuples of 
the form of `{ASTNodeType, ContextMetadata, ASTNodeData}` instead of 
needing to handle a multitude of different forms, especially the loose ones 
such as `42`, which you have to match with a guard.
2. Taking keyword lists to macro functions would be more verbose, but a 
simple helper such as `Macro.keywordify` or so could take constructs of, as 
a pure example, something like `{:list, [], [{:tuple, [], [{:atom, [], "a"}, 
{:integer, [], 42}]}]}` and return `[a: 42]`, which makes handling 
ast-based keyword lists for compile-time data trivial, it could even have 
the aspect of expanding binding and other things using the `__CALLER__`'s 
environment.

The first is a huge bonus, having the context/metadata information on every 
single node is immensely useful in a variety of situations.  Giving names 
to node such as `{:atom, [], "a"}` and `{:integer, [], 42}` is both more 
regular and standard (both great aspects for an AST) but is also safer for 
those wanting to parse out user data (like say a language server parser), 
while keeping distinct the difference between function calls (which only 
has a list in the data field) and bindings (which only have contextual 
atoms in the data field as far as I've seen so far, but then I'd argue that 
those should be in an `{:binding, [], [{:atom, [], "a"}, {:atom, [], 
"AContextAtom"}]}` setup as well, and thus function calls can be kept top 
level like `{{:atom, [], "funcname"}, [], [{:utf8, [], "an argument"}]}`).  
All of this would be *so* much a huge boon when I'm doing macro work as 
well, so much code would be simplified, so much so that I often convert 
Elixir's non-regular AST format into a regular format, so I convert things 
like `42` into `{:__block__, [], [42]}` so I can attach metadata into the 
middle field for later processing, all without needing to process it back 
because elixir still consumes it all just fine, and this is a pretty 
excessive pattern that I do just because all the loose 'stuff' is so 
irritating to handle and that loose 'stuff' has lost all contextual 
information, line number, column information if that exists, etc... etc... 
etc...  I can 'try' to rebuild it when I need but it is impossible to 
absolutely and fully reproduce the original because the current AST format 
is so lacking.

Compare this to the clang or OCaml AST's, both of which are entirely 
regular as the equivalent of the 3-tuple of elixir's AST (although with 
ADT's instead, which are conceptually tagged tuples anyway, I.E. like an 
erlang record, though I *love* the simplicity of the 3-tuple with one field 
being a keywordlist, or better yet a map, of the metadata, and the other 
two fields being a tag, and the tag-specific data).

If I were designing Elixir's AST from scratch then it would be 
significantly more regular with a number of changes that would make it a 
lot easier to work with, but even as it is now it is pretty easy to make 
regular (if not properly explicit because of hacks like `{:__block__, [], [
:a]}`, and that really is a hack) without any of this weird special casing 
of primitives or 2-tuples or lists or so forth, all of which 'seems' (based 
on usage in the elixir codebase itself) to be purely to make compile-time 
keyword lists simple, which could easily be fixed with a single function to 
do the transformation as-needed (like a `Macro.keywordize/2` function).

Right now macro's are pretty irritating to write because of all these 
inconsistencies, and consuming AST for other purposes like language servers 
or contextual highlighting is even more irritating.

-- 
You received this message because you are subscribed to the Google Groups 
"elixir-lang-core" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/elixir-lang-core/8a5d61af-4daf-40e4-a025-67f1b8a76895%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to