JuliaSyntax.jl icon indicating copy to clipboard operation
JuliaSyntax.jl copied to clipboard

0.4.8 lets `a.[1]` parse and lower

Open LilithHafner opened this issue 1 year ago • 11 comments

This came up at https://github.com/JuliaLang/julia/pull/53119

@LilithHafnerBot bisect()

using JuliaSyntax
JuliaSyntax.parse("a.[1]")

LilithHafner avatar Feb 01 '24 14:02 LilithHafner

Note that this was allowed in the flisp parser.

julia +lts -E ':(a.[1])'                                                                                                                                      
:(a.:([1]))

savq avatar Feb 01 '24 16:02 savq

There was a bug in the bisector backend. Should hopefully be fixed now.

@LilithHafnerBot bisect()

using JuliaSyntax
JuliaSyntax.parse(Expr, "a.[1]")

LilithHafner avatar Feb 01 '24 18:02 LilithHafner

❌ Bisect failed

Commit stdout
b1c6d541ee41b0451d151a2074ca2a00f6c6e59c a.:([1])
a6f2d1580f7bbad11822033e8c83e607aa31f100 a.:([1])

LilithHafnerBot avatar Feb 01 '24 18:02 LilithHafnerBot

@LilithHafnerBot bisect()

using JuliaSyntax
JuliaSyntax.enable_in_core!()
eval(Meta.parse("""
Meta.lower(Main, :(a.[1]))
"""))

LilithHafner avatar Feb 01 '24 18:02 LilithHafner

✅ 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 avatar Feb 01 '24 18:02 LilithHafnerBot

@LilithHafnerBot bisect()

using JuliaSyntax
dump(JuliaSyntax.parse(Expr, "a.[1]"))

LilithHafner avatar Feb 01 '24 19:02 LilithHafner

✅ 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...

LilithHafnerBot avatar Feb 01 '24 19:02 LilithHafnerBot

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)

LilithHafner avatar Feb 01 '24 19:02 LilithHafner

Are Expr(:quote, ...) and QuoteNode(...) semantically identical?

pfitzseb avatar Feb 01 '24 19:02 pfitzseb

Are Expr(:quote, ...) and QuoteNode(...) semantically identical?

No, but the difference is subtle.

  • quote does $ interpolation (in lisp, this is called quasiquote)
  • QuoteNode (or equivalently, Expr(:inert)) doesn't participate in $ interpolation (somewhat confusingly, this is called quote in lisp)

c42f avatar Jul 23 '24 05:07 c42f

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

c42f avatar Jul 23 '24 20:07 c42f