Open fonsp opened 3 years ago
Code Relay task for this is here https://github.com/code-relay-io/Pluto.jl/blob/main/README.md. We will work on this issue!
Hello, I took a little go at this, here's an initial attempt that could be turned into a PR, probably:
using MacroTools: prewalk
function top_level_exprs(expr)
quote_level = 0
unquoted_exprs = [expr]
prewalk(expr) do e
!isa(e, Expr) && return e
if e.head == :quote
quote_level += 1
elseif e.head == :$
quote_level -= 1
if quote_level == 0
push!(unquoted_exprs, e.args[1])
end
end
return e
end
return unquoted_exprs
end
And here are some examples of use that look correct to me:
julia> top_level_exprs(:(a = 1))
1-element Array{Expr,1}:
:(a = 1)
julia> top_level_exprs(:(a = :($(b = 2))))
2-element Array{Expr,1}:
:(a = $(Expr(:quote, :($(Expr(:$, :(b = 2)))))))
:(b = 2)
julia> top_level_exprs(:(a = :(:($(b = 2)))))
1-element Array{Expr,1}:
:(a = $(Expr(:quote, :($(Expr(:quote, :($(Expr(:$, :(b = 2))))))))))
julia> top_level_exprs(:(a = :(:($$(b = 2)))))
2-element Array{Expr,1}:
:(a = $(Expr(:quote, :($(Expr(:quote, :($(Expr(:$, :($(Expr(:$, :(b = 2)))))))))))))
:(b = 2)
# like fons' example
julia> top_level_exprs(:(:(a = $(b = :($(c = 1))))))
3-element Array{Expr,1}:
:($(Expr(:quote, :(a = $(Expr(:$, :(b = $(Expr(:quote, :($(Expr(:$, :(c = 1)))))))))))))
:(b = $(Expr(:quote, :($(Expr(:$, :(c = 1)))))))
:(c = 1)
julia> top_level_exprs(Meta.parse(":(a = \$(b = :(\$(c = 1))))"))
3-element Array{Expr,1}:
:($(Expr(:quote, :(a = $(Expr(:$, :(b = $(Expr(:quote, :($(Expr(:$, :(c = 1)))))))))))))
:(b = $(Expr(:quote, :($(Expr(:$, :(c = 1)))))))
:(c = 1)
I did this because of the relay thing, but also it took me closer to an hour to get to this stage than the 15 minutes it suggested. I'm not sure I could have meaningfully cut the work down, tho. Maybe I'm just a bit slow :shrug:
Anyway, hope this is useful!
Lol, I got the walk wrong. Too tired. Here's a better one:
function top_level_exprs2(expr)
unquoted_exprs = Any[expr]
function walk(e, quote_level)
!isa(e, Expr) && return
if e.head == :quote
quote_level += 1
elseif e.head == :$
quote_level -= 1
if quote_level == 0
push!(unquoted_exprs, e.args[1])
end
end
walk.(e.args, quote_level)
end
walk(expr, 0)
return unquoted_exprs
end
Now it handles inputs like :(a = :($x; $y))
correctly.
Currently, we ignore all code inside a quoted expression:
which makes sense! (Unless that code is
eval
ed within the same cell, which is almost impossible to track for us, but we want to discourage 'raw'eval
altogether #279 )However, we should detect interpolated code:
In fact, this can go on for multiple layers: