-
-
Notifications
You must be signed in to change notification settings - Fork 1.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
The policy on availability of ASTNode methods in macros #3274
Comments
The policy is: all nodes should be able to be traversed. Currently they are not but only because we didn't have time to implement them all. I added the methods that I thought would be most convenient, or that I needed at that moment for some stuff, but all of them should be available. Adding these methods and tests for them should be relatively easy. |
How is the status now four years later? Anybody wants to reevaluate? |
At the minimum it should be possible to reconstruct every AST node from macro interpolation of that node's direct constituents. For example,
|
So I went through the AST node types with
The following subclasses of
|
Another thing worth bringing up is the mutability of certain kinds of nodes. This was touched on a bit within #7109 (comment) but I think it could use some more discussion given that was quite a few years ago. I agree on the sentiment for not wanting to enable additional mutability, and am totally in favor of increasing the functionality of alternate approaches, e.g. annotations. But on the flip side I think their usage is no longer solely used as a means of a registry, which was the original primary concern. Macro logic can get quite complex/involved but also can support very powerful features. In my experience it's not uncommon to work with local hash/namedtuple/array literals as temporary data stores within the scope of a (or multiple)
In such contexts as these the primary reasons for preventing mutability are no longer relevant as there isn't a side affect of it messing with dependency order; not having them only makes the code even more complex due to needing to workaround the lack of some methods , such as #8835 is a related topic that depending on the exact implementation could possibly render this issue moot. |
My current opinion on mutability is: the macro language lacks macro-exclusive sequential and associative collections, or rather, doing so wouldn't bring any substantial benefits over simply reusing real AST nodes, so Now even if #8835 were implemented, there would still be "primitive" methods that must be offered by the compiler, or whose performance would severely degrade without that. For example, unless we get rid of macro hash_delete(hash, key)
{%
copy = hash.map { |k, v| {k, v} }
hash.clear
value = nil
copy.each do |(k, v)|
if k == key
value = v
else
hash[k] = v # quadratic complexity (see note below)
end
end
hash # => {1 => 2, 3 => 4}
value # => 6
%}
end
hash_delete({1 => 2, 3 => 4, 5 => 6}, 5) But of course |
Related: #8849 |
lib LibFoo
fun foo
$bar : Int32
end
def x
{{ LibFoo.methods }} # => [fun foo, , ]
{{ LibFoo.methods.map(&.name) }} # => [foo, bar=, bar]
end
x They inherit from This leaves only |
It seems that the set of methods available on type nodes in macros is inconsistent.
and
andor
can be split to their subexpressions, but with unary!
you can't get the expression it wraps..as
is readable but.is_a?
isn't.def
.case
? Why is it available when many smaller and more frequently used nodes aren't?I think it is important to define a policy on what is available and what isn't, and then proceed to fill the gaps (I can help with that).
I don't see a reason to have arbitrary limits in exploring the structure of expressions passed to macros. Sure, not everything is applicable, at least it's clear that not being able to modify the nodes is part of the current policy, but not much else seems to be well-defined.
So, what is the policy on the availability of these methods?
The text was updated successfully, but these errors were encountered: