Skip to content
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

Interpolation inside expressions #1001

Open
fonsp opened this issue Mar 16, 2021 · 3 comments
Open

Interpolation inside expressions #1001

fonsp opened this issue Mar 16, 2021 · 3 comments
Labels
bug Something isn't working expression explorer Figuring out assignments and references in a cell good first issue Good for newcomers

Comments

@fonsp
Copy link
Owner

fonsp commented Mar 16, 2021

Currently, we ignore all code inside a quoted expression:

julia> Base.show(io::IO, ::MIME"text/plain", b::Bool) = println(io, b ? "👍" : "😢")

julia> import Pluto: ReactiveNode

julia> ReactiveNode("""
       begin
           x = 1
           y = quote
               z = 3
           end
       end
       """).definitions
Set{Symbol} with 2 elements:
  :y
  :x

julia> :z  ans
👍

which makes sense! (Unless that code is evaled 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:

julia> ReactiveNode("""
       begin
           x = 1
           y = quote
               z = $(realz = 3)
           end
       end
       """).definitions
Set{Symbol} with 2 elements:
  :y
  :x

julia> :realz  ans
😢

In fact, this can go on for multiple layers:

julia> ReactiveNode("""
       begin
           x = 1
           y = quote
               z1 = $(realz1 = quote
                   z2 = $(realz2 = 3)
               end)
           end
       end
       """).definitions
Set{Symbol} with 2 elements:
  :y
  :x

julia> [:realz1, :realz2]  ans
😢
@fonsp fonsp added bug Something isn't working good first issue Good for newcomers expression explorer Figuring out assignments and references in a cell labels Mar 16, 2021
@mmulet
Copy link

mmulet commented Mar 19, 2021

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!

@cmcaine
Copy link

cmcaine commented Mar 19, 2021

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 🤷

Anyway, hope this is useful!

@cmcaine
Copy link

cmcaine commented Mar 19, 2021

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working expression explorer Figuring out assignments and references in a cell good first issue Good for newcomers
Projects
None yet
Development

No branches or pull requests

3 participants