Bypass SyntaxNode in JuliaLowering; fix kw bug#60162
Bypass SyntaxNode in JuliaLowering; fix kw bug#60162topolarity merged 3 commits intoJuliaLang:masterfrom
SyntaxNode in JuliaLowering; fix kw bug#60162Conversation
Fix JuliaLang#60152, which impacted both lowering implementations. `remove-argument-side-effects` assumes all `kw` arguments from a `parameters` block had already been dumped into the argument list. In addition: - JuliaLowering hit a MethodError in the dumped-`kw` case regardless. There are other issues with `kw` which I'm ignoring in this PR: see JuliaLang#60162 - Delete some ancient history: `&` [used to be a valid argument](JuliaLang@a378b75#diff-5d79463faae0f7f19454c7f9888498d9f876082e258ab3efdca36a0ee64b0c87L72) head sometime in 2012 apparently!
Fix JuliaLang#60152, which impacted both lowering implementations. `remove-argument-side-effects` assumed all `kw` arguments from a `parameters` block had already been dumped into the argument list, which is not true in some cases. In addition: - JuliaLowering hit a MethodError in the dumped-`kw` case regardless. There are other issues with `kw` which I'm ignoring in this PR (see JuliaLang#60162) - Delete some ancient history: `&` [used to be a valid argument](JuliaLang@a378b75#diff-5d79463faae0f7f19454c7f9888498d9f876082e258ab3efdca36a0ee64b0c87L72) head sometime in 2012 apparently!
Fix #60152, which impacted both lowering implementations. `remove-argument-side-effects` assumed all `kw` arguments from a `parameters` block had already been dumped into the argument list, which is not true in some cases. In addition: - JuliaLowering hit a MethodError in the dumped-`kw` case regardless. There are other issues with `kw` which I'm ignoring in this PR (see #60162) - Delete some ancient history: `&` [used to be a valid argument](a378b75#diff-5d79463faae0f7f19454c7f9888498d9f876082e258ab3efdca36a0ee64b0c87L72) head sometime in 2012 apparently!
f962f9e to
a813d18
Compare
There was a problem hiding this comment.
Not familiar enough yet to review the details of the transform, so it would be good to get review from @Keno or @c42f w.r.t. the more intimate JuliaSyntax / JuliaLowering bits. Nonetheless I like the direction of the changes and will merge soon (today) barring feedback.
This might be too adventurous, but in a world where Expr / SyntaxTree are 1:1, it would be nice to converge to a pipeline like:
(source text)
|
|
v
[JS] RawGreenNode
|
v
[JS] SyntaxTree0 ----> Expr
| ^ |
| | |
| \--(lossy)---/
|
v
[JL] SyntaxTree1
|
|
v
(desugaring and beyond)
which has one less "path" to Expr (so hopefully less room for unique bugs)
|
|
||
| #------------------------------------------------------------------------------- | ||
| # Conversion from the raw parsed tree | ||
| # TODO: move to JuliaSyntax. Replace SyntaxNode? |
There was a problem hiding this comment.
Is it viable to replace node_to_expr with this new pipeline + SyntaxTree -> Expr conversion?
(maybe this is already what you meant by "feed them through the same generic code"?)
Would be nice to be able to reduce some of the special conversion pathways here.
There was a problem hiding this comment.
Yes, if SyntaxTree and Expr have the same structure, then it would make sense to have node_to_expr handle both (RawGreenNode->x) if possible. They aren't the same now, though, and I think duplicating conversion code is the only way to bring them closer incrementally rather than all at once.
a813d18 to
5611a24
Compare
Looks about right! |
…nsion (#60170) On top of #60162. This simplification lets macro expansion handle the macro name as an identifier rather than the nonterminal `K"macro_name"` node. That and the old `MacroName` node (as well as `CmdMacroName`, `StrMacroName`) are mainly the result of restrictions on raw parser output: we can't parse `@Base.x` to a non-contiguous `@x`, even though that's what we want in the AST in almost every case.
Fix #60152, which impacted both lowering implementations. `remove-argument-side-effects` assumed all `kw` arguments from a `parameters` block had already been dumped into the argument list, which is not true in some cases. In addition: - JuliaLowering hit a MethodError in the dumped-`kw` case regardless. There are other issues with `kw` which I'm ignoring in this PR (see #60162) - Delete some ancient history: `&` [used to be a valid argument](a378b75#diff-5d79463faae0f7f19454c7f9888498d9f876082e258ab3efdca36a0ee64b0c87L72) head sometime in 2012 apparently! (cherry picked from commit 2be8847)
Fix #60152, which impacted both lowering implementations. `remove-argument-side-effects` assumed all `kw` arguments from a `parameters` block had already been dumped into the argument list, which is not true in some cases. In addition: - JuliaLowering hit a MethodError in the dumped-`kw` case regardless. There are other issues with `kw` which I'm ignoring in this PR (see #60162) - Delete some ancient history: `&` [used to be a valid argument](a378b75#diff-5d79463faae0f7f19454c7f9888498d9f876082e258ab3efdca36a0ee64b0c87L72) head sometime in 2012 apparently! (cherry picked from commit 2be8847)
I set out to fix a stdlib compilation failure JuliaLang/JuliaLowering.jl#98, but ran
into a limitation in the JuliaSyntax AST. Instead of hacking in a fix, this PR
attempts to address JuliaLang/JuliaLowering.jl#77 too.
kwThe
kwform isn't produced inSyntaxNode/SyntaxTreelike it is in Expr,which simplifies the parser, but causes problems once we start start caring
about the semantics of these trees. Parsing
"f(a=1)"will always produce anExpr(:call, :f, Expr(:kw, :a, 1)), but the equivalent SyntaxNoderepresentation
(call f (= a 1))makesExpr(:call, :f, Expr(:(=), :a, 1))unrepresentable, even though that's valid syntax a macro could produce.
To fix this, we need to convert
=tokwwithin certain forms beforemacro expansion.
One problem
There is currently no good place to put this conversion. Here's the path
from source to lowering:
*(2) and (3) are pretty trivial, and data structure names are used as
shorthand for what actually matters to this issue (the tree represented by the
data structure).
JS._to_SyntaxNode, which just deletes triviaJL._convert_nodes, which is more-or-less a one-to-one conversion, and Ithink is an artifact of JuliaSyntax and JuliaLowering being in separate
repositories. @c42f has talked about wanting to replace SyntaxNode with
SyntaxTree eventually.
easier
JS._node_to_expr, which is used for femtolisp lowering (5a) and forJuliaLowering's compatibility with existing macros (5b)
JL.expr_to_syntaxtree, which is also used for Expr-macro compatibilityExpr gets the chance to swap out
=within(call (parameters ...))in_node_to_expr, but to change SyntaxTree we can only change parsing. (Theinverse is also true: if someone wants to change parsing to
RawGreenNode,JuliaLowering will have to eat it).
This PR implements the following instead, where
_green_to_asthappens at (2)and may fix up the AST before lowering. Ideally this means more room for parser
cleanup and eventually eliminating our "pre-desugaring" mixed in with macro
expansion.
The catch is that if we want SyntaxTree to be different from RawGreenNode, we do
need to convert them to Expr differently. There are a few things we could do:
(pictured, and implemented).
This would add a step to our current femtolisp-lowered parsing (why)
SyntaxTreestructurally different from Expr (I wouldn'tmind this) and try to feed them through the same generic code (not so sure
about that).
For now I've done the lazy thing by using a boolean parameter to implement the
first option.
I also took this opportunity to put the green tree into the syntax graph. This
doesn't really change anything given how little we look at the green tree, but
wasn't difficult, and it's a neat representation.
kwnotesI've made SyntaxTree and Expr the same here, though some inconsistencies could
be ironed out in the future with syntax evolution. Ideally, we use
kwwherever a textual
=behaves more like a=>, or if"="is a parse error,wherever it would be more consistent to treat it like
=>.call*x(a=1,;b=1)(kw a 1) (kw b 1)(kw a 1) (kw b 1)dotcallx.(a=1,;b=1)(kw a 1) (kw b 1)(kw a 1) (kw b 1)refx[a=1,;b=1](kw a 1) (= b 1)(kw a 1) (kw b 1)curlyx{a=1,;b=1}(= a 1) (= b 1)(kw a 1) (kw b 1)tuple(a=1,;b=1)(= a 1) (kw b 1)(kw a 1) (kw b 1)vect[a=1,;b=1](= a 1) (= b 1)(= a 1) (kw b 1)braces{a=1,;b=1}(= a 1) (= b 1)(= a 1) (kw b 1)macrocall@x(a=1,;b=1)(= a 1) (kw b 1)(= a 1) (kw b 1)