-
Notifications
You must be signed in to change notification settings - Fork 9
expr_to_syntaxtree: don't fail when incoming expr is invalid
#103
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
base: main
Are you sure you want to change the base?
Conversation
337f356 to
2c8a478
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixing the problem of unknown heads seems good and necessary, thanks!
I do find it surprising that this gives us mixtures of SyntaxTree and Expr in the intermediate forms and I'm a little concerned this mixed representation will lead to bugs.
How about we slightly change the representation here such that unknown heads still turn into K"expr_syntax" (or maybe K"unknown_head" or some better name?) but we map the children even when the head is unrecognized. The original head can go into an attribute. Actually this is almost what K"extension" currently is - so there's already a half-formed plan to do this kind of thing.
In addition I think we should put the error message for K"expr_syntax" in desugaring so macro expansion of unknown heads isn't an error.
Any potential bugs in mind? I'm actually more worried about case 2 (mapping children) than case 3 (give up and don't convert), since case 2 can have incorrect round-tripping behaviour if an invalid Expr is a valid SyntaxTree with different semantics. Unfortunately the only correct solutions are:
I decided to inch towards (A), where case 2 is incorrect but not problematic in practice. I left unknown "must round-trip" stuff as Expr since it's probably going to be used by an Expr-macro immediately after, and there isn't any provenance to lose. It would eat some CPU cycles, but wouldn't be incorrect to recursively convert the Expr one-to-one under |
Not specifically right now. But having a mixed representation seems more confusing to reason about and feels like fertile ground for such bugs.
hmm ok. Do you have an example of this? Maybe we already have this problem in the existing eager conversion code?
Hmm. I don't love this tradeoff. Though old macros can't even expand to old macrocalls in the existing system and have things generally work so I guess there's precedent in some sense 😅 |
Anywhere SyntaxTree uses a representation that is an invalid Expr ( |
Is the following what you're concerned about: macro blah()
v = Expr(:var, :x)
quote
@process_var $v
@process_var x
end
end
macro process_var(ex)
if ex isa Expr && ex.head == :var
"var node"
else
"something else"
end
end
julia> @macroexpand @blah
quote
#= REPL[11]:4 =#
"var node"
#= REPL[11]:5 =#
"something else"
endThis will indeed produce different results in new macro expansion if we blindly convert between The same thing can happen in reverse if a new macro produces an invalid |
|
Yup, that is the concern |
Currently, we have a pile of assertions in
expr_to_syntaxtreechecking thevalidity of the given Expr. This means JuliaLowering can't handle old macros
calling old or new macros with unrecognized Expr forms---in the "old calling
old" case, this is breakage, and in the "old calling new" case it's still a
downgrade to the macro system.
expr_to_syntaxtreehandles macro input andquoted expressions, so it can't assume anything about the AST structure.
This PR attempts to define
expr_to_syntaxtreeon all inputs in a sane way.eis one of the known forms with a different representation inSyntaxTree, convert it.
e.headcorresponds to a knownJuliaSyntax.Kind, insert thatand recurse on its children.
K"expr_syntax"node witheas its.value. We'llstill get an error as we did before if we try and evaluate this, but a future
expansion is expected to clean it up.
The assertions have been removed, but their contents are generally kept for
deciding between cases (1) and (2) above.