JuliaSyntax.jl
JuliaSyntax.jl copied to clipboard
0.4.8 lets `a.[1]` parse and lower
This came up at https://github.com/JuliaLang/julia/pull/53119
@LilithHafnerBot bisect()
using JuliaSyntax
JuliaSyntax.parse("a.[1]")
Note that this was allowed in the flisp parser.
julia +lts -E ':(a.[1])'
:(a.:([1]))
There was a bug in the bisector backend. Should hopefully be fixed now.
@LilithHafnerBot bisect()
using JuliaSyntax
JuliaSyntax.parse(Expr, "a.[1]")
❌ Bisect failed
| Commit | stdout |
|---|---|
| b1c6d541ee41b0451d151a2074ca2a00f6c6e59c | a.:([1]) |
| a6f2d1580f7bbad11822033e8c83e607aa31f100 | a.:([1]) |
@LilithHafnerBot bisect()
using JuliaSyntax
JuliaSyntax.enable_in_core!()
eval(Meta.parse("""
Meta.lower(Main, :(a.[1]))
"""))
✅ Bisect succeeded! The first new commit is 296cd5ee4cded19cec84d8328da0b5ee1ce98f05
| Commit | stdout |
|---|---|
| b1c6d541ee41b0451d151a2074ca2a00f6c6e59c | $(Expr(:error, "invalid syntax "a.[1]"")) |
| e3e447da2fd849124bc4e520eb42a1f541f9bfce | $(Expr(:error, "invalid syntax "a.[1]"")) |
| 8731bab86f14762cca8cf24224d8c7a6a89c21c5 | $(Expr(:error, "invalid syntax "a.[1]"")) |
| 6da0fc487ad5af13fc4b1dd82679b4501a28c794 | $(Expr(:error, "invalid syntax "a.[1]"")) |
| 5aad8126ac8380981ef8db75c01fea579956caff | $(Expr(:error, "invalid syntax "a.[1]"")) |
| 296cd5ee4cded19cec84d8328da0b5ee1ce98f05 | $(Expr(:thunk, CodeInfo(⏎ @ none within top-level scope⏎1 ─ %1 = Base.getproperty(a, $(Quote... |
| df84e02381b741f9982399b24c1c7bf2fbd630a2 | $(Expr(:thunk, CodeInfo(⏎ @ none within top-level scope⏎1 ─ %1 = Base.getproperty(a, $(Quote... |
| a6f2d1580f7bbad11822033e8c83e607aa31f100 | $(Expr(:thunk, CodeInfo(⏎ @ none within top-level scope⏎1 ─ %1 = Base.getproperty(a, $(Quote... |
@LilithHafnerBot bisect()
using JuliaSyntax
dump(JuliaSyntax.parse(Expr, "a.[1]"))
✅ Bisect succeeded! The first new commit is 296cd5ee4cded19cec84d8328da0b5ee1ce98f05
| Commit | stdout |
|---|---|
| b1c6d541ee41b0451d151a2074ca2a00f6c6e59c | Expr⏎ head: Symbol .⏎ args: Array{Any}((2,))⏎ 1: Symbol a⏎ 2: Expr⏎ head: Symbol quo... |
| e3e447da2fd849124bc4e520eb42a1f541f9bfce | Expr⏎ head: Symbol .⏎ args: Array{Any}((2,))⏎ 1: Symbol a⏎ 2: Expr⏎ head: Symbol quo... |
| 8731bab86f14762cca8cf24224d8c7a6a89c21c5 | Expr⏎ head: Symbol .⏎ args: Array{Any}((2,))⏎ 1: Symbol a⏎ 2: Expr⏎ head: Symbol quo... |
| 6da0fc487ad5af13fc4b1dd82679b4501a28c794 | Expr⏎ head: Symbol .⏎ args: Array{Any}((2,))⏎ 1: Symbol a⏎ 2: Expr⏎ head: Symbol quo... |
| 5aad8126ac8380981ef8db75c01fea579956caff | Expr⏎ head: Symbol .⏎ args: Array{Any}((2,))⏎ 1: Symbol a⏎ 2: Expr⏎ head: Symbol quo... |
| 296cd5ee4cded19cec84d8328da0b5ee1ce98f05 | Expr⏎ head: Symbol .⏎ args: Array{Any}((2,))⏎ 1: Symbol a⏎ 2: QuoteNode⏎ value: Expr... |
| df84e02381b741f9982399b24c1c7bf2fbd630a2 | Expr⏎ head: Symbol .⏎ args: Array{Any}((2,))⏎ 1: Symbol a⏎ 2: QuoteNode⏎ value: Expr... |
| a6f2d1580f7bbad11822033e8c83e607aa31f100 | Expr⏎ head: Symbol .⏎ args: Array{Any}((2,))⏎ 1: Symbol a⏎ 2: QuoteNode⏎ value: Expr... |
Alas, @savq, the old and new parsing results both print to :(a.:([1])), but they are not the same.
julia> old = Expr(:., :a, Expr(:quote, :([1])))
:(a.:([1]))
julia> new = Expr(:., :a, QuoteNode(:([1])))
:(a.:([1]))
julia> old == new
false
julia> Meta.lower(Main, old)
:($(Expr(:error, "invalid syntax \"a.[1]\"")))
julia> Meta.lower(Main, new)
:($(Expr(:thunk, CodeInfo(
@ none within `top-level scope'
1 ─ %1 = Base.getproperty(a, $(QuoteNode(:([1]))))
└── return %1
))))
From the commit message, this looks intentional; perhaps the appropriate fix is to prohibit this in lowering (and possibly gate the new parsing to new versions of Julia)
Are Expr(:quote, ...) and QuoteNode(...) semantically identical?
Are
Expr(:quote, ...)andQuoteNode(...)semantically identical?
No, but the difference is subtle.
quotedoes$interpolation (in lisp, this is calledquasiquote)QuoteNode(or equivalently,Expr(:inert)) doesn't participate in$interpolation (somewhat confusingly, this is calledquotein lisp)
Note that the old parser uses QuoteNode in the special case that $ interpolation comes after the .:
julia> dump(JuliaSyntax.fl_parse(raw"x.$y"))
Expr
head: Symbol .
args: Array{Any}((2,))
1: Symbol x
2: QuoteNode
value: Expr
head: Symbol $
args: Array{Any}((1,))
1: Symbol y
QuoteNode rather than quote is required in this case so that the following works
julia> let
field_name = :a
quote
x.$field_name
end
end
quote
#= REPL[10]:4 =#
x.a
end
But in the old parser, the following doesn't work because use of quote for anything other than $ after the x. means that the $field_name is double quoted (ie, "inside two quotes") in the Expr tree:
julia> let
field_name = :a
quote
x.[$field_name]
end
end
quote
#= REPL[11]:4 =#
x.:([$(Expr(:$, :field_name))])
end
However, after #324, we have
julia> JuliaSyntax.enable_in_core!()
julia> let
field_name = :a
quote
x.[$field_name]
end
end
quote
#= REPL[13]:4 =#
x.:([a])
end