Skip to content

Commit

Permalink
start fixing tests
Browse files Browse the repository at this point in the history
i also tried try non recursive macroexpand to get intermediary macrocalls
but it fails because of JuliaLang/julia#37691

try
```julia

@enum a b c

```
which will call `Base.@__doc__($(Expr(:escape, :sym))))` breaking
  • Loading branch information
Pangoraw committed Apr 11, 2021
1 parent ac83976 commit d0fe9c3
Show file tree
Hide file tree
Showing 6 changed files with 97 additions and 65 deletions.
48 changes: 33 additions & 15 deletions src/evaluation/Run.jl
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ will_run_code(notebook::Notebook) = notebook.process_status != ProcessStatus.no_
"We still have 'unresolved' macrocalls, use the pre-created workspace to do macro-expansions"
function resolve_topology(session::ServerSession, notebook::Notebook, unresolved_topology::NotebookTopology, old_workspace_name::Symbol)
sn = (session, notebook)
to_reimport = union(Set{Expr}(), map(c -> notebook.topology.codes[c].module_usings_imports.usings, notebook.cells)...)
to_reimport = union(Set{Expr}(), map(c -> unresolved_topology.codes[c].module_usings_imports.usings, notebook.cells)...)
WorkspaceManager.do_reimports(sn, to_reimport)

function macroexpand_cell(cell)
Expand All @@ -159,14 +159,14 @@ function resolve_topology(session::ServerSession, notebook::Notebook, unresolved
# 3. Move imports and re-try in the new module
# 4. *NotImplemented*. Would be to run imports and execute only a part of the graph
res = try_macroexpand()
if isa(res, LoadError) && isa(res.error, UndefVarError)
if res isa LoadError && res.error isa UndefVarError
# We have not found the macro in the new workspace after reimports
# this most likely means that the macro is user defined, we try to expand it
# in the old workspace to see whether or not it is defined there

res = try_macroexpand(old_workspace_name)
# It was not defined previously, we try searching modules in our own batch
if isa(res, LoadError) && isa(res.error, UndefVarError)
if res isa LoadError && res.error isa UndefVarError
to_import_from_batch = union(Set{Expr}(),
map(c -> unresolved_topology.codes[c].module_usings_imports.usings,
notebook.cells)...)
Expand All @@ -179,27 +179,45 @@ function resolve_topology(session::ServerSession, notebook::Notebook, unresolved
end

# create new node & new codes for macrocalled cells
new_nodes = Dict(
cell_symstate.first => cell_symstate.first
new_nodes = Dict{Cell,ReactiveNode}(
cell => cell
|> macroexpand_cell
|> function(result)
if typeof(result) <: Exception # if expansion failed, we use the "shallow" symbols state
@warn "Failed to expand macro" result

cell_symstate.second
else # otherwise, we use the expanded expression + the list of macrocalls
expanded_symbols_state = ExpressionExplorer.try_compute_symbolreferences(result)
union!(expanded_symbols_state.macrocalls, cell_symstate.second.macrocalls)
expanded_symbols_state
end
if typeof(result) <: Exception # if expansion failed, we use the "shallow" symbols state
error = result
@warn "Failed to expand macro" error

old_symstate
else # otherwise, we use the expanded expression + the list of macrocalls
expanded_symbols_state = ExpressionExplorer.try_compute_symbolreferences(result)
union!(expanded_symbols_state.macrocalls, old_symstate.macrocalls)
expanded_symbols_state
end
end
|> ReactiveNode
for cell_symstate in unresolved_topology.unresolved_cells)
for (cell, old_symstate) in unresolved_topology.unresolved_cells)
all_nodes = merge(unresolved_topology.nodes, new_nodes)

NotebookTopology(nodes=all_nodes, codes=unresolved_topology.codes)
end

"The same as `resolve_topology` but does not require custom code execution, only works with a few `Base` & `PlutoRunner` macros"
function static_resolve_topology(topology::NotebookTopology)
function static_macroexpand(cell_symstate)
cell, old_symstate = cell_symstate
new_symstate = ExpressionExplorer.maybe_macroexpand(topology.codes[cell].parsedcode; recursive=true) |>
ExpressionExplorer.try_compute_symbolreferences
union!(new_symstate.macrocalls, old_symstate.macrocalls)

cell => ReactiveNode(new_symstate)
end

new_nodes = Dict{Cell,ReactiveNode}(static_macroexpand.(topology.unresolved_cells))
all_nodes = merge(topology.nodes, new_nodes)

NotebookTopology(nodes=all_nodes, codes=topology.codes)
end

"Do all the things!"
function update_save_run!(session::ServerSession, notebook::Notebook, cells::Array{Cell,1}; save::Bool=true, run_async::Bool=false, prerender_text::Bool=false, deletion_hook_factory=nothing, kwargs...)
old = notebook.topology
Expand Down
16 changes: 11 additions & 5 deletions src/runner/PlutoRunner.jl
Original file line number Diff line number Diff line change
Expand Up @@ -68,16 +68,24 @@ function visit_expr(_, other)
other
end

function wrap_dot(name)
if length(name) == 1
name[1]
else
Expr(:(.), wrap_dot(name[1:end-1]), QuoteNode(name[end]))
end
end

"""
Returns an Expr with no GlobalRef to `Main.workspaceXX` so that reactive updates will work.
"""
no_workspace_ref(other) = other
no_workspace_ref(expr::Expr) = Expr(expr.head, no_workspace_ref.(expr.args)...)
function no_workspace_ref(ref::GlobalRef)
mod_name = nameof(ref.mod)
if startswith(string(mod_name), "workspace")
if startswith(nameof(ref.mod) |> string, "workspace")
ref.name
else
mod_name = fullname(ref.mod) |> wrap_dot
Expr(:(.), mod_name, QuoteNode(ref.name))
end
end
Expand Down Expand Up @@ -308,9 +316,7 @@ function do_reimports(workspace_name, module_imports_to_move::Set{Expr})
for expr in module_imports_to_move
try
Core.eval(workspace_name, expr)
catch e
@error e
end # TODO catch specificallly
catch e end # TODO catch specificallly
end
end

Expand Down
4 changes: 2 additions & 2 deletions test/Analysis.jl
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
using Test
import Pluto: Notebook, ServerSession, ClientSession, Cell, updated_topology, is_just_text
import Pluto: Notebook, ServerSession, ClientSession, Cell, updated_topology, static_resolve_topology, is_just_text

@testset "Analysis" begin
notebook = Notebook([
Expand Down Expand Up @@ -38,7 +38,7 @@ import Pluto: Notebook, ServerSession, ClientSession, Cell, updated_topology, is
])

old = notebook.topology
new = notebook.topology = updated_topology(old, notebook, notebook.cells)
new = notebook.topology = updated_topology(old, notebook, notebook.cells) |> static_resolve_topology

@testset "Only-text detection" begin
@test is_just_text(new, notebook.cells[1])
Expand Down
64 changes: 32 additions & 32 deletions test/ExpressionExplorer.jl
Original file line number Diff line number Diff line change
Expand Up @@ -273,9 +273,9 @@ Some of these @test_broken lines are commented out to prevent printing to the te
@test testee(:(f(x)::String = x), [], [], [], [
:f => ([:String], [], [], [])
])
@test testee(:(MIME"text/html"), [], [], [Symbol("@MIME_str")], [])
@test testee(:(MIME"text/html"), [], [], [], [], [Symbol("@MIME_str")])
@test testee(:(function f(::MIME"text/html") 1 end), [], [], [], [
:f => ([], [], [Symbol("@MIME_str")], [])
:f => ([], [], [], [], [Symbol("@MIME_str")])
])
@test testee(:(a(a::AbstractArray{T}) where T = 5), [], [], [], [
:a => ([:AbstractArray], [], [], [])
Expand Down Expand Up @@ -364,19 +364,19 @@ Some of these @test_broken lines are commented out to prevent printing to the te
dx = a*x - b*x*y
dy = -c*y + d*x*y
end a b c d
end, [], [:f, :LotkaVolterra], [Symbol("@ode_def")], [])
end, [], [:f], [], [], [Symbol("@ode_def")])
@test testee(quote
f = @ode_def begin
dx = a*x - b*x*y
dy = -c*y + d*x*y
end a b c d
end, [], [:f], [Symbol("@ode_def")], [])
end, [], [:f], [], [], [Symbol("@ode_def")])
# flux
@test testee(:(@functor Asdf), [], [:Asdf], [Symbol("@functor")], [])
@test testee(:(@functor Asdf), [], [], [], [], [Symbol("@functor")])
# symbolics
@test testee(:(@variables a b c), [], [:a, :b, :c], [Symbol("@variables")], [])
@test testee(:(@variables a b[1:2] c(t) d(..)), [], [:a, :b, :c, :d, :t], [:(:), Symbol("@variables")], [])
@test testee(:(@variables a b[1:x] c[1:10](t) d(..)), [:x], [:a, :b, :c, :d, :t], [:(:), Symbol("@variables")], [])
@test testee(:(@variables a b c), [], [], [], [], [Symbol("@variables")])
@test testee(:(@variables a b[1:2] c(t) d(..)), [], [], [], [], [Symbol("@variables")])
@test testee(:(@variables a b[1:x] c[1:10](t) d(..)), [], [], [], [], [Symbol("@variables")])
@test_nowarn testee(:(@variables(m, begin
x
y[i=1:2] >= i, (start = i, base_name = "Y_$i")
Expand All @@ -396,37 +396,37 @@ Some of these @test_broken lines are commented out to prevent printing to the te
# end)), [:m, :Bin], [:x, :y, :z], [Symbol("@variables")], [])
end
@testset "Macros" begin
@test testee(:(@time a = 2), [], [:a], [Symbol("@time")], [])
@test testee(:(@f(x; y=z)), [:x, :z], [], [Symbol("@f")], [])
@test testee(:(@f(x, y = z)), [:x, :z], [], [Symbol("@f")], []) # https://github.com/fonsp/Pluto.jl/issues/252
@test testee(:(Base.@time a = 2), [:Base], [:a], [[:Base, Symbol("@time")]], [])
# Macros tests are not just in ExpressionExplorer now

@test testee(:(@time a = 2), [], [], [], [], [Symbol("@time")])
@test testee(:(@f(x; y=z)), [], [], [], [], [Symbol("@f")])
@test testee(:(@f(x, y = z)), [], [], [], [], [Symbol("@f")]) # https://github.com/fonsp/Pluto.jl/issues/252
@test testee(:(Base.@time a = 2), [], [], [], [], [[:Base, Symbol("@time")]])
# @test_nowarn testee(:(@enum a b = d c), [:d], [:a, :b, :c], [Symbol("@enum")], [])
# @enum is tested in test/React.jl instead
@test testee(:(@gensym a b c), [], [:a, :b, :c], [:gensym, Symbol("@gensym")], [])
@test testee(:(Base.@gensym a b c), [:Base], [:a, :b, :c], [:gensym, [:Base, Symbol("@gensym")]], [])
@test testee(:(Base.@kwdef struct A; x = 1; y::Int = two; z end), [:Base], [:A], [[:Base, Symbol("@kwdef")], [:Base, Symbol("@__doc__")]], [
:A => ([:Int, :two], [], [], [])
])
@test testee(quote "asdf" f(x) = x end, [], [], [Symbol("@doc")], [:f => ([], [], [], [])])
@test testee(:(@gensym a b c), [], [], [], [], [Symbol("@gensym")])
@test testee(:(Base.@gensym a b c), [], [], [], [], [[:Base, Symbol("@gensym")]])
@test testee(:(Base.@kwdef struct A; x = 1; y::Int = two; z end), [], [], [], [], [[:Base, Symbol("@kwdef")]])
@test testee(quote "asdf" f(x) = x end, [], [], [], [], [Symbol("@doc")])

@test testee(:(@bind a b), [:b, :PlutoRunner, :Base, :Core], [:a], [[:Base, :get], [:Core, :applicable], [:PlutoRunner, :Bond], Symbol("@bind")], [])
@test testee(:(PlutoRunner.@bind a b), [:b, :PlutoRunner, :Base, :Core], [:a], [[:Base, :get], [:Core, :applicable], [:PlutoRunner, :Bond], [:PlutoRunner, Symbol("@bind")]], [])
@test testee(:(@bind a b), [], [], [], [], [Symbol("@bind")])
@test testee(:(PlutoRunner.@bind a b), [], [], [], [], [[:PlutoRunner, Symbol("@bind")]])
@test_broken testee(:(Main.PlutoRunner.@bind a b), [:b, :PlutoRunner, :Base, :Core], [:a], [[:Base, :get], [:Core, :applicable], [:PlutoRunner, :Bond], [:PlutoRunner, Symbol("@bind")]], [], verbose=false)
@test testee(:(let @bind a b end), [:b, :PlutoRunner, :Base, :Core], [:a], [[:Base, :get], [:Core, :applicable], [:PlutoRunner, :Bond], Symbol("@bind")], [])
@test testee(:(let @bind a b end), [], [], [], [], [Symbol("@bind")])

@test testee(:(@asdf a = x1 b = x2 c = x3), [:x1, :x2, :x3], [:a], [Symbol("@asdf")], []) # https://github.com/fonsp/Pluto.jl/issues/670
@test testee(:(@asdf a = x1 b = x2 c = x3), [], [], [], [], [Symbol("@asdf")]) # https://github.com/fonsp/Pluto.jl/issues/670

@test testee(:(@einsum a[i,j] := x[i]*y[j]), [:x, :y, :Float64], [:a], [[Symbol("@einsum")], [:*]], [])
@test testee(:(@tullio a := f(x)[i+2j, k[j]] init=z), [:x, :k, :z], [:a], [[Symbol("@tullio")], [:f], [:*], [:+]], [])
@test testee(:(Pack.@asdf a[1,k[j]] := log(x[i]/y[j])), [:x, :y, :k, :Pack, :Float64], [:a], [[:Pack, Symbol("@asdf")], [:/], [:log]], [])
@test testee(:(@einsum a[i,j] := x[i]*y[j]), [], [], [], [], [Symbol("@einsum")])
@test testee(:(@tullio a := f(x)[i+2j, k[j]] init=z), [], [], [], [], [Symbol("@tullio")])
@test testee(:(Pack.@asdf a[1,k[j]] := log(x[i]/y[j])), [], [], [], [], [[:Pack, Symbol("@asdf")]])

@test testee(:(`hey $(a = 1) $(b)`), [:b], [], [:cmd_gen, Symbol("@cmd")], [])
@test testee(:(md"hey $(@bind a b) $(a)"), [:b, :PlutoRunner, :Base, :Core], [:a], [:getindex, [:Base, :get], [:Core, :applicable], [:PlutoRunner, :Bond], Symbol("@md_str"), Symbol("@bind")], [])
@test testee(:(md"hey $(a) $(@bind a b)"), [:b, :a, :PlutoRunner, :Base, :Core], [:a], [:getindex, [:Base, :get], [:Core, :applicable], [:PlutoRunner, :Bond], Symbol("@md_str"), Symbol("@bind")], [])
@test testee(:(html"a $(b = c)"), [], [], [Symbol("@html_str")], [])
@test testee(:(md"a $(b = c) $(b)"), [:c], [:b], [:getindex, Symbol("@md_str")], [])
@test testee(:(md"\* $r"), [:r], [], [:getindex, Symbol("@md_str")], [])
@test testee(:(md"a \$(b = c)"), [], [], [:getindex, Symbol("@md_str")], [])
@test testee(:(`hey $(a = 1) $(b)`), [], [], [], [], [Symbol("@cmd")])
@test testee(:(md"hey $(@bind a b) $(a)"), [], [], [], [], [Symbol("@md_str")])
@test testee(:(md"hey $(a) $(@bind a b)"), [], [], [], [], [Symbol("@md_str")])
@test testee(:(html"a $(b = c)"), [], [], [], [], [Symbol("@html_str")])
@test testee(:(md"a $(b = c) $(b)"), [], [], [], [], [Symbol("@md_str")])
@test testee(:(md"\* $r"), [], [], [], [], [Symbol("@md_str")])
@test testee(:(md"a \$(b = c)"), [], [], [], [], [Symbol("@md_str")])
@test testee(:(macro a() end), [], [], [], [
Symbol("@a") => ([], [], [], [])
])
Expand Down
11 changes: 7 additions & 4 deletions test/helpers.jl
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ julia> @test testee(:(
true
```
"
function testee(expr, expected_references, expected_definitions, expected_funccalls, expected_funcdefs, expected_macrocalls = false; verbose::Bool=true)
function testee(expr, expected_references, expected_definitions, expected_funccalls, expected_funcdefs, expected_macrocalls = []; verbose::Bool=true)
expected = easy_symstate(expected_references, expected_definitions, expected_funccalls, expected_funcdefs, expected_macrocalls)

original_hash = Pluto.PlutoRunner.expr_hash(expr)
Expand Down Expand Up @@ -83,19 +83,22 @@ function testee(expr, expected_references, expected_definitions, expected_funcca
return expected == result
end

function easy_symstate(expected_references, expected_definitions, expected_funccalls, expected_funcdefs, expected_macrocalls = false)
new_expected_funccalls = map(expected_funccalls) do k
function easy_symstate(expected_references, expected_definitions, expected_funccalls, expected_funcdefs, expected_macrocalls = [])
array_to_set(array) = map(array) do k
new_k = k isa Symbol ? [k] : k
return new_k
end |> Set
new_expected_funccalls = array_to_set(expected_funccalls)

new_expected_funcdefs = map(expected_funcdefs) do (k, v)
new_k = k isa Symbol ? [k] : k
new_v = v isa SymbolsState ? v : easy_symstate(v...)
return FunctionNameSignaturePair(new_k, "hello") => new_v
end |> Dict

SymbolsState(Set(expected_references), Set(expected_definitions), new_expected_funccalls, new_expected_funcdefs, expected_macrocalls)
new_expected_macrocalls = array_to_set(expected_macrocalls)

SymbolsState(Set(expected_references), Set(expected_definitions), new_expected_funccalls, new_expected_funcdefs, new_expected_macrocalls)
end

function setcode(cell, newcode)
Expand Down
19 changes: 12 additions & 7 deletions test/runtests.jl
Original file line number Diff line number Diff line change
@@ -1,16 +1,21 @@
include("./helpers.jl")
include("./DependencyCache.jl")
include("./WorkspaceManager.jl")
include("./RichOutput.jl")

# NOT WORKING
# include("./MacroAnalysis.jl")
# include("./DependencyCache.jl")
# include("./Dynamic.jl")
# include("./Notebook.jl")

# WORKING
include("./React.jl")
include("./ExpressionExplorer.jl")
include("./Dynamic.jl")
include("./MethodSignatures.jl")
include("./Notebook.jl")
include("./Configuration.jl")
include("./Analysis.jl")
include("./Firebasey.jl")
include("./Throttled.jl")
include("./ExpressionExplorer.jl")
include("./WorkspaceManager.jl")
include("./Analysis.jl")
include("./RichOutput.jl")

# TODO: test PlutoRunner functions like:
# - from_this_notebook
Expand Down

0 comments on commit d0fe9c3

Please sign in to comment.