To be able to edit code and run cells, you need to run the notebook yourself. Where would you like to run the notebook?

This notebook takes about 20 seconds to run.

In the cloud (experimental)

Binder is a free, open source service that runs scientific notebooks in the cloud! It will take a while, usually 2-7 minutes to get a session.

On your computer

(Recommended if you want to store your changes.)

  1. Copy the notebook URL:
  2. Run Pluto

    (Also see: How to install Julia and Pluto)

  3. Paste URL in the Open box

Frontmatter

If you are publishing this notebook on the web, you can set the parameters below to provide HTML metadata. This is useful for search engines and social media.

Author 1
👀 Reading hidden code
[Dog(),Dog(),Dog(),Dog(),Dog()]
20.2 μs
5
👀 Reading hidden code
5
20.7 μs
👀 Reading hidden code
Dog()
14.3 μs
SymbolsState
👀 Reading hidden code
begin
"SymbolsState trickles _down_ the ASTree: it carries referenced and defined variables from endpoints down to the root."
mutable struct SymbolsState
references::Set{Symbol}
assignments::Set{Symbol}
function_calls::Set{FunctionName}
function_definitions::Dict{FunctionName,SymbolsState}
end
SymbolsState(references, assignments, function_calls) = SymbolsState(references, assignments, function_calls, Dict{FunctionName,SymbolsState}())
SymbolsState(references, assignments) = SymbolsState(references, assignments, Set{Symbol}())
SymbolsState() = SymbolsState(Set{Symbol}(), Set{Symbol}())
end
2.8 ms
will_assign_global (generic function with 2 methods)
👀 Reading hidden code
begin
function will_assign_global(assignee::Symbol, scopestate::ScopeState)::Bool
(scopestate.inglobalscope || assigneescopestate.exposedglobals) && (assigneescopestate.hiddenglobals || assigneescopestate.definedfuncs)
end
function will_assign_global(assignee::Array{Symbol,1}, scopestate::ScopeState)::Bool
if length(assignee) == 0
false
elseif length(assignee) > 1
scopestate.inglobalscope
else
end
end
end
1.4 ms

5337.573 kB

md" $(filesize(dog_file) / 1000) kB"
👀 Reading hidden code
5.4 ms
const modifiers = [:(+=), :(-=), :(*=), :(/=), :(//=), :(^=), :(÷=), :(%=), :(<<=), :(>>=), :(>>>=), :(&=), :(⊻=), :(≔), :(⩴), :(≕)]

👀 Reading hidden code
188 μs
const modifiers_dotprefixed = [Symbol('.' * String(m)) for m in modifiers]

👀 Reading hidden code
23.7 ms
begin
struct Dog end
function Base.show(io::IO, ::MIME"image/jpg", ::Dog)
write(io, read(dog_file))
end
end
👀 Reading hidden code
1.2 ms
[Dog(),Dog(),Dog(),Dog(),Dog()]
👀 Reading hidden code
22.1 μs
"/tmp/jl_p7QohV"
dog_file = download("https://upload.wikimedia.org/wikipedia/commons/e/ef/Pluto_in_True_Color_-_High-Res.jpg")
👀 Reading hidden code
355 ms
2
1+1
👀 Reading hidden code
13.0 μs

👀 Reading hidden code
61.3 μs
ScopeState

ScopeState moves up the ASTree: it carries scope information up towards the endpoints.

"ScopeState moves _up_ the ASTree: it carries scope information up towards the endpoints."
mutable struct ScopeState
inglobalscope::Bool
exposedglobals::Set{Symbol}
hiddenglobals::Set{Symbol}
definedfuncs::Set{Symbol}
end
👀 Reading hidden code
1.9 ms
begin
import Base: union, union!, ==, push!
function union(a::Dict{FunctionName,SymbolsState}, bs::Dict{FunctionName,SymbolsState}...)
union!(Dict{FunctionName,SymbolsState}(), a, bs...)
end
function union!(a::Dict{FunctionName,SymbolsState}, bs::Dict{FunctionName,SymbolsState}...)
for b in bs
for (k, v) in b
if haskey(a, k)
a[k] = union!(a[k], v)
else
a[k] = v
end
end
a
end
return a
end
function union(a::SymbolsState, b::SymbolsState)
SymbolsState(a.references ∪ b.references, a.assignments ∪ b.assignments, a.function_calls ∪ b.function_calls, a.function_definitions ∪ b.function_definitions)
end
function union!(a::SymbolsState, bs::SymbolsState...)
union!(a.references, (b.references for b in bs)...)
union!(a.assignments, (b.assignments for b in bs)...)
union!(a.function_calls, (b.function_calls for b in bs)...)
union!(a.function_definitions, (b.function_definitions for b in bs)...)
return a
end
function union!(a::Tuple{FunctionName,SymbolsState}, bs::Tuple{FunctionName,SymbolsState}...)
a[1], union!(a[2], (b[2] for b in bs)...)
end
function union(a::ScopeState, b::ScopeState)
SymbolsState(a.inglobalscope && b.inglobalscope, a.exposedglobals ∪ b.exposedglobals, a.hiddenglobals ∪ b.hiddenglobals)
end
function union!(a::ScopeState, bs::ScopeState...)
a.inglobalscope &= all((b.inglobalscope for b in bs)...)
union!(a.exposedglobals, (b.exposedglobals for b in bs)...)
union!(a.hiddenglobals, (b.hiddenglobals for b in bs)...)
union!(a.definedfuncs, (b.definedfuncs for b in bs)...)
return a
end
function ==(a::SymbolsState, b::SymbolsState)
a.references == b.references && a.assignments == b.assignments && a.function_calls == b.function_calls && a.function_definitions == b.function_definitions
end
Base.push!(x::Set) = x

end
👀 Reading hidden code
9.9 ms
get_global_assignees (generic function with 1 method)

function get_global_assignees(assignee_exprs, scopestate::ScopeState)::Set{Symbol}
global_assignees = Set{Symbol}()
for ae in assignee_exprs
if isa(ae, Symbol)
will_assign_global(ae, scopestate) && push!(global_assignees, ae)
else
if ae.head == :(::)
will_assign_global(ae.args[1], scopestate) && push!(global_assignees, ae.args[1])
else
@warn "Unknown assignee expression" ae
end
end
end
return global_assignees
end
👀 Reading hidden code
3.0 ms
get_assignees (generic function with 3 methods)
begin
function get_assignees(ex::Expr)::FunctionName
if ex.head == :tuple
# e.g. (x, y) in the ex (x, y) = (1, 23)
union!(Symbol[], get_assignees.(ex.args)...)
# filter(s->s isa Symbol, ex.args)
elseif ex.head == :(::)
# TODO: type is referenced
Symbol[ex.args[1]]
elseif ex.head == :ref || ex.head == :(.)
Symbol[]
else
@warn "unknow use of `=`. Assignee is unrecognised." ex
Symbol[]
end
end
# e.g. x = 123
get_assignees(ex::Symbol) = Symbol[ex]
# When you assign to a datatype like Int, String, or anything bad like that
# e.g. 1 = 2
# This is parsable code, so we have to treat it
get_assignees(::Any) = Symbol[]
end
👀 Reading hidden code
3.4 ms
uncurly! (generic function with 4 methods)
begin
# TODO: this should return a FunctionName, and use `split_FunctionName`.
"Turn :(A{T}) into :A."
function uncurly!(ex::Expr, scopestate::ScopeState)::Symbol
@assert ex.head == :curly
push!(scopestate.hiddenglobals, (a for a in ex.args[2:end] if a isa Symbol)...)
ex.args[1]
end
uncurly!(ex::Expr)::Symbol = ex.args[1]
uncurly!(s::Symbol, scopestate=nothing)::Symbol = s
end
👀 Reading hidden code
15.8 ms
0
a1 + a2 + a3 + a4 + a5 + a6 + a7 + a8 + a9 + a10 + a11 + a12 + a13 + a14 + a15 + a16 + a17 + a18 + a19 + a20 + a21 + a22 + a23 + a24 + a25 + a26 + a27 + a28 + a29 + a30 + a31 + a32 + a33 + a34 + a35 + a36 + a37 + a38 + a39 + a40 + a41 + a42 + a43 + a44 + a45 + a46 + a47 + a48 + a49 + a50 + a51 + a52 + a53 + a54 + a55 + a56 + a57 + a58 + a59 + a60 + a61 + a62 + a63 + a64 + a65 + a66 + a67 + a68 + a69 + a70 + a71 + a72 + a73 + a74 + a75 + a76 + a77 + a78 + a79 + a80 + a81 + a82 + a83 + a84 + a85 + a86 + a87 + a88 + a89 + a90 + a91 + a92 + a93 + a94 + a95 + a96 + a97 + a98 + a99 + a100 + a101 + a102 + a103 + a104 + a105 + a106 + a107 + a108 + a109 + a110 + a111 + a112 + a113 + a114 + a115 + a116 + a117 + a118 + a119 + a120 + a121 + a122 + a123 + a124 + a125 + a126 + a127 + a128 + a129 + a130 + a131 + a132 + a133 + a134 + a135 + a136 + a137 + a138 + a139 + a140 + a141 + a142 + a143 + a144 + a145 + a146 + a147 + a148 + a149 + a150 + a151 + a152 + a153 + a154 + a155 + a156 + a157 + a158 + a159 + a160 + a161 + a162 + a163 + a164 + a165 + a166 + a167 + a168 + a169 + a170 + a171 + a172 + a173 + a174 + a175 + a176 + a177 + a178 + a179 + a180 + a181 + a182 + a183 + a184 + a185 + a186 + a187 + a188 + a189 + a190 + a191 + a192 + a193 + a194 + a195 + a196 + a197 + a198 + a199 + a200 + 0
👀 Reading hidden code
31.2 ms

asdfasdf

md"asdfasdf"
👀 Reading hidden code
227 μs
0
a1 = a2 = a3 = a4 = a5 = a6 = a7 = a8 = a9 = a10 = a11 = a12 = a13 = a14 = a15 = a16 = a17 = a18 = a19 = a20 = a21 = a22 = a23 = a24 = a25 = a26 = a27 = a28 = a29 = a30 = a31 = a32 = a33 = a34 = a35 = a36 = a37 = a38 = a39 = a40 = a41 = a42 = a43 = a44 = a45 = a46 = a47 = a48 = a49 = a50 = a51 = a52 = a53 = a54 = a55 = a56 = a57 = a58 = a59 = a60 = a61 = a62 = a63 = a64 = a65 = a66 = a67 = a68 = a69 = a70 = a71 = a72 = a73 = a74 = a75 = a76 = a77 = a78 = a79 = a80 = a81 = a82 = a83 = a84 = a85 = a86 = a87 = a88 = a89 = a90 = a91 = a92 = a93 = a94 = a95 = a96 = a97 = a98 = a99 = a100 = a101 = a102 = a103 = a104 = a105 = a106 = a107 = a108 = a109 = a110 = a111 = a112 = a113 = a114 = a115 = a116 = a117 = a118 = a119 = a120 = a121 = a122 = a123 = a124 = a125 = a126 = a127 = a128 = a129 = a130 = a131 = a132 = a133 = a134 = a135 = a136 = a137 = a138 = a139 = a140 = a141 = a142 = a143 = a144 = a145 = a146 = a147 = a148 = a149 = a150 = a151 = a152 = a153 = a154 = a155 = a156 = a157 = a158 = a159 = a160 = a161 = a162 = a163 = a164 = a165 = a166 = a167 = a168 = a169 = a170 = a171 = a172 = a173 = a174 = a175 = a176 = a177 = a178 = a179 = a180 = a181 = a182 = a183 = a184 = a185 = a186 = a187 = a188 = a189 = a190 = a191 = a192 = a193 = a194 = a195 = a196 = a197 = a198 = a199 = a200 = 0
👀 Reading hidden code
420 μs
"a1 = a2 = a3 = a4 = a5 = a6 = a7 = a8 = a9 = a10 = a11 = a12 = a13 = a14 = a15 = a16 = a17 = a18 = a19 = a20 = a21 = a22 = a23 = a24 = a25 = a26 = a27 = a28 = a29 = a30 = a31 = a32 = a33 = a34 = a35 = a36 = a37 = a38 = a39 = a40 = a41 = a42 = a43 = a44 = a45 = a46 = a47 = a48 = a49 = a50 = a51 = a5" ⋯ 696 bytes ⋯ " = a159 = a160 = a161 = a162 = a163 = a164 = a165 = a166 = a167 = a168 = a169 = a170 = a171 = a172 = a173 = a174 = a175 = a176 = a177 = a178 = a179 = a180 = a181 = a182 = a183 = a184 = a185 = a186 = a187 = a188 = a189 = a190 = a191 = a192 = a193 = a194 = a195 = a196 = a197 = a198 = a199 = a200 = 0"
join(["a$i = " for i in 1:200]) * "0"
👀 Reading hidden code
94.7 μs
"a1 + a2 + a3 + a4 + a5 + a6 + a7 + a8 + a9 + a10 + a11 + a12 + a13 + a14 + a15 + a16 + a17 + a18 + a19 + a20 + a21 + a22 + a23 + a24 + a25 + a26 + a27 + a28 + a29 + a30 + a31 + a32 + a33 + a34 + a35 + a36 + a37 + a38 + a39 + a40 + a41 + a42 + a43 + a44 + a45 + a46 + a47 + a48 + a49 + a50 + a51 + a5" ⋯ 696 bytes ⋯ " + a159 + a160 + a161 + a162 + a163 + a164 + a165 + a166 + a167 + a168 + a169 + a170 + a171 + a172 + a173 + a174 + a175 + a176 + a177 + a178 + a179 + a180 + a181 + a182 + a183 + a184 + a185 + a186 + a187 + a188 + a189 + a190 + a191 + a192 + a193 + a194 + a195 + a196 + a197 + a198 + a199 + a200 + 0"
join(["a$i + " for i in 1:200]) * "0"
👀 Reading hidden code
76.7 μs
Vector{Symbol} (alias for Array{Symbol, 1})
FunctionName = Array{Symbol,1}
👀 Reading hidden code
16.4 μs
split_FunctionName (generic function with 4 methods)
begin
"Turn `:(Base.Submodule.f)` into `[:Base, :Submodule, :f]` and `:f` into `[:f]`."
function split_FunctionName(FunctionName_ex::Expr)::FunctionName
if FunctionName_ex.head == :(.)
vcat(split_FunctionName.(FunctionName_ex.args)...)
else
# a call to a function that's not a global, like calling an array element: `funcs[12]()`
# TODO: explore symstate!
Symbol[]
end
end
function split_FunctionName(FunctionName_ex::QuoteNode)::FunctionName
split_FunctionName(FunctionName_ex.value)
end
function split_FunctionName(FunctionName_ex::Symbol)::FunctionName
Symbol[FunctionName_ex |> without_dotprefix |> without_dotsuffix]
end
function split_FunctionName(::Any)::FunctionName
Symbol[]
end
end
👀 Reading hidden code
2.3 ms
without_dotsuffix

Turn :(sqrt.) into :(sqrt)

begin
"Turn :(.+) into :(+)"
function without_dotprefix(FunctionName::Symbol)::Symbol
fn_str = String(FunctionName)
if length(fn_str) > 0 && fn_str[1] == '.'
Symbol(fn_str[2:end])
else
FunctionName
end
end
"Turn :(sqrt.) into :(sqrt)"
function without_dotsuffix(FunctionName::Symbol)::Symbol
fn_str = String(FunctionName)
if length(fn_str) > 0 && fn_str[end] == '.'
Symbol(fn_str[1:end - 1])
else
FunctionName
end
end
end
👀 Reading hidden code
1.8 ms
join_FunctionName_parts

Turn Symbol[:Module, :func] into Symbol("Module.func").

This is not the same as the expression :(Module.func), but is used to identify the function name using a single Symbol (like normal variables). This means that it is only the inverse of ExploreExpression.split_FunctionName iff length(parts) ≤ 1.

"""Turn `Symbol[:Module, :func]` into Symbol("Module.func").

This is **not** the same as the expression `:(Module.func)`, but is used to identify the function name using a single `Symbol` (like normal variables).
This means that it is only the inverse of `ExploreExpression.split_FunctionName` iff `length(parts) ≤ 1`."""
function join_FunctionName_parts(parts::FunctionName)::Symbol
join(parts .|> String, ".") |> Symbol
end
👀 Reading hidden code
747 μs
explore_funcdef! (generic function with 4 methods)
begin
"Return the function name and the SymbolsState from argument defaults. Add arguments as hidden globals to the `scopestate`.
Is also used for `struct` and `abstract`."
function explore_funcdef!(ex::Expr, scopestate::ScopeState)::Tuple{FunctionName,SymbolsState}
if ex.head == :call
# get the function name
name, symstate = explore_funcdef!(ex.args[1], scopestate)
# and explore the function arguments
return mapfoldl(a -> explore_funcdef!(a, scopestate), union!, ex.args[2:end], init=(name, symstate))
elseif ex.head == :(::) || ex.head == :kw || ex.head == :(=)
# recurse
name, symstate = explore_funcdef!(ex.args[1], scopestate)
if length(ex.args) > 1
# use `explore!` (not `explore_funcdef!`) to explore the argument's default value - these can contain arbitrary expressions
union!(symstate, explore!(ex.args[2], scopestate))
end
return name, symstate
elseif ex.head == :where
# function(...) where {T, S <: R, U <: A.B}
# supertypes `R` and `A.B` are referenced
supertypes_symstate = SymbolsState()
for a in ex.args[2:end]
name, inner_symstate = explore_funcdef!(a, scopestate)
if length(name) == 1
push!(scopestate.hiddenglobals, name[1])
end
union!(supertypes_symstate, inner_symstate)
end
# recurse
name, symstate = explore_funcdef!(ex.args[1], scopestate)
union!(symstate, supertypes_symstate)
return name, symstate
elseif ex.head == :(<:)
# for use in `struct` and `abstract`
name = uncurly!(ex.args[1], scopestate)
symstate = if length(ex.args) == 1
SymbolsState()
else
explore!(ex.args[2], scopestate)
end
return Symbol[name], symstate
elseif ex.head == :curly
name = uncurly!(ex, scopestate)
return Symbol[name], SymbolsState()
elseif ex.head == :parameters || ex.head == :tuple
return mapfoldl(a -> explore_funcdef!(a, scopestate), union!, ex.args, init=(Symbol[], SymbolsState()))
elseif ex.head == :(.)
return split_FunctionName(ex), SymbolsState()
else
return Symbol[], explore!(ex, scopestate)
end
end
function explore_funcdef!(ex::QuoteNode, scopestate::ScopeState)::Tuple{FunctionName,SymbolsState}
explore_funcdef!(ex.value, scopestate)
end
function explore_funcdef!(ex::Symbol, scopestate::ScopeState)::Tuple{FunctionName,SymbolsState}
push!(scopestate.hiddenglobals, ex)
Symbol[ex |> without_dotprefix |> without_dotsuffix], SymbolsState()
end
function explore_funcdef!(::Any, ::ScopeState)::Tuple{FunctionName,SymbolsState}
Symbol[], SymbolsState()
end
end
👀 Reading hidden code
8.1 ms
explore! (generic function with 3 methods)
begin
# Spaghetti code for a spaghetti problem 🍝
# Possible leaf: value
# Like: a = 1
# 1 is a value (Int64)
function explore!(value, scopestate::ScopeState)::SymbolsState
# includes: LineNumberNode, Int64, String,
return SymbolsState()
end
# Possible leaf: symbol
# Like a = x
# x is a symbol
# We handle the assignment separately, and explore!(:a, ...) will not be called.
# Therefore, this method only handles _references_, which are added to the symbolstate, depending on the scopestate.
function explore!(sym::Symbol, scopestate::ScopeState)::SymbolsState
if sym ∈ scopestate.hiddenglobals
SymbolsState(Set{Symbol}(), Set{Symbol}(), Set{Symbol}(), Dict{FunctionName,SymbolsState}())
else
SymbolsState(Set([sym]), Set{Symbol}(), Set{Symbol}(), Dict{FunctionName,SymbolsState}())
end
end
# General recursive method. Is never a leaf.
# Modifies the `scopestate`.
function explore!(ex::Expr, scopestate::ScopeState)::SymbolsState
if ex.head == :(=)
# Does not create scope
if ex.args[1] isa Expr && (ex.args[1].head == :call || ex.args[1].head == :where)
# f(x, y) = x + y
# Rewrite to:
# function f(x, y) x + y end
return explore!(Expr(:function, ex.args...), scopestate)
end
assignees = get_assignees(ex.args[1])
val = ex.args[2]
global_assignees = get_global_assignees(assignees, scopestate)
symstate = innersymstate = explore!(val, scopestate)
# If we are _not_ assigning a global variable, then this symbol hides any global definition with that name
push!(scopestate.hiddenglobals, setdiff(assignees, global_assignees)...)
assigneesymstate = explore!(ex.args[1], scopestate)
push!(scopestate.hiddenglobals, global_assignees...)
push!(symstate.assignments, global_assignees...)
push!(symstate.references, setdiff(assigneesymstate.references, global_assignees)...)
return symstate
elseif ex.head in modifiers
# We change: a[1] += 123
# to: a[1] = a[1] + 123
# We transform the modifier back to its operator
# for when users redefine the + function
operator = Symbol(string(ex.head)[1:end - 1])
expanded_expr = Expr(:(=), ex.args[1], Expr(:call, operator, ex.args[1], ex.args[2]))
return explore!(expanded_expr, scopestate)
elseif ex.head in modifiers_dotprefixed
# We change: a[1] .+= 123
# to: a[1] .= a[1] + 123
operator = Symbol(string(ex.head)[2:end - 1])
expanded_expr = Expr(:(.=), ex.args[1], Expr(:call, operator, ex.args[1], ex.args[2]))
return explore!(expanded_expr, scopestate)
elseif ex.head == :let || ex.head == :for || ex.head == :while
# Creates local scope
# Because we are entering a new scope, we create a copy of the current scope state, and run it through the expressions.
innerscopestate = deepcopy(scopestate)
innerscopestate.inglobalscope = false
return mapfoldl(a -> explore!(a, innerscopestate), union!, ex.args, init=SymbolsState())
elseif ex.head == :call
# Does not create scope
FunctionName = ex.args[1] |> split_FunctionName
symstate = if length(FunctionName) == 0
explore!(ex.args[1], scopestate)
elseif length(FunctionName) == 1
if FunctionName[1] ∈ scopestate.hiddenglobals
SymbolsState()
else
SymbolsState(Set{Symbol}(), Set{Symbol}(), Set{FunctionName}([FunctionName]))
end
else
SymbolsState(Set{Symbol}([FunctionName[end - 1]]), Set{Symbol}(), Set{FunctionName}([FunctionName]))
end
# Explore code inside function arguments:
union!(symstate, explore!(Expr(:block, ex.args[2:end]...), scopestate))
return symstate
elseif ex.head == :kw
return explore!(ex.args[2], scopestate)
elseif ex.head == :struct
# Creates local scope
structname = ex.args[2]
structfields = ex.args[3].args
equiv_func = Expr(:function, Expr(:call, structname, structfields...), Expr(:block, nothing))
return explore!(equiv_func, scopestate)
elseif ex.head == :generator
# Creates local scope
# In a `generator`, a single expression is followed by the iterator assignments.
# In a `for`, this expression comes at the end.
# This is not strictly the normal form of a `for` but that's okay
return explore!(Expr(:for, ex.args[2:end]..., ex.args[1]), scopestate)
elseif ex.head == :function || ex.head == :abstract
symstate = SymbolsState()
# Creates local scope
funcroot = ex.args[1]
# Because we are entering a new scope, we create a copy of the current scope state, and run it through the expressions.
innerscopestate = deepcopy(scopestate)
innerscopestate.inglobalscope = false
FunctionName, innersymstate = explore_funcdef!(funcroot, innerscopestate)
union!(innersymstate, explore!(Expr(:block, ex.args[2:end]...), innerscopestate))
if will_assign_global(FunctionName, scopestate)
symstate.function_definitions[FunctionName] = innersymstate
if length(FunctionName) == 1
push!(scopestate.definedfuncs, FunctionName[end])
push!(scopestate.hiddenglobals, FunctionName[end])
elseif length(FunctionName) > 1
push!(symstate.references, FunctionName[end - 1]) # reference the module of the extended function
end
else
# The function is not defined globally. However, the function can still modify the global scope or reference globals, e.g.
# let
# function f(x)
# global z = x + a
# end
# f(2)
# end
# so we insert the function's inner symbol state here, as if it was a `let` block.
symstate = innersymstate
end
return symstate
elseif ex.head == :(->)
# Creates local scope
tempname = Symbol("anon", rand(UInt64))
# We will rewrite this to a normal function definition, with a temporary name
funcroot = ex.args[1]
args_ex = if funcroot isa Symbol || (funcroot isa Expr && funcroot.head == :(::))
[funcroot]
elseif funcroot.head == :tuple
funcroot.args
else
@error "Unknown lambda type"
end
equiv_func = Expr(:function, Expr(:call, tempname, args_ex...), ex.args[2])
return explore!(equiv_func, scopestate)
elseif ex.head == :global
# Does not create scope
# We have one of:
# global x;
# global x = 1;
# global x += 1;
# where x can also be a tuple:
# global a,b = 1,2
globalisee = ex.args[1]
if isa(globalisee, Symbol)
push!(scopestate.exposedglobals, globalisee)
return SymbolsState()
elseif isa(globalisee, Expr)
innerscopestate = deepcopy(scopestate)
innerscopestate.inglobalscope = true
return explore!(globalisee, innerscopestate)
else
@error "unknow global use" ex
return explore!(globalisee, scopestate)
end
return symstate
elseif ex.head == :local
# Does not create scope
localisee = ex.args[1]
if isa(localisee, Symbol)
push!(scopestate.hiddenglobals, localisee)
return SymbolsState()
elseif isa(localisee, Expr) && (localisee.head == :(=) || localisee.head in modifiers)
push!(scopestate.hiddenglobals, get_assignees(localisee.args[1])...)
return explore!(localisee, scopestate)
else
@warn "unknow local use" ex
return explore!(localisee, scopestate)
end
elseif ex.head == :tuple
# Does not create scope
# Is something like:
# a,b,c = 1,2,3
# This parses to:
# head = :tuple
# args = [:a, :b, :(c=1), :2, :3]
# 🤔
# we turn it into two expressions:
# (a, b) = (2, 3)
# (c = 1)
# and explore those :)
indexoffirstassignment = findfirst(a -> isa(a, Expr) && a.head == :(=), ex.args)
if indexoffirstassignment !== nothing
# we have one of two cases, see next `if`
indexofsecondassignment = findnext(a -> isa(a, Expr) && a.head == :(=), ex.args, indexoffirstassignment + 1)
if indexofsecondassignment !== nothing
# we have a named tuple, e.g. (a=1, b=2)
new_args = map(ex.args) do a
(a isa Expr && a.head == :(=)) ? a.args[2] : a
end
return explore!(Expr(:block, new_args...), scopestate)
else
# we have a tuple assignment, e.g. `a, (b, c) = [1, [2, 3]]`
before = ex.args[1:indexoffirstassignment - 1]
after = ex.args[indexoffirstassignment + 1:end]
symstate_middle = explore!(ex.args[indexoffirstassignment], scopestate)
symstate_outer = explore!(Expr(:(=), Expr(:tuple, before...), Expr(:block, after...)), scopestate)
return union!(symstate_middle, symstate_outer)
end
else
return explore!(Expr(:block, ex.args...), scopestate)
end
elseif ex.head == :(.) && ex.args[2] isa Expr && ex.args[2].head == :tuple
# pointwise function call, e.g. sqrt.(nums)
# we rewrite to a regular call
return explore!(Expr(:call, ex.args[1], ex.args[2].args...), scopestate)
elseif ex.head == :using || ex.head == :import
if scopestate.inglobalscope
imports = if ex.args[1].head == :(:)
ex.args[1].args[2:end]
else
ex.args
end
packagenames = map(e -> e.args[end], imports)
return SymbolsState(Set{Symbol}(), Set{Symbol}(packagenames))
else
return SymbolsState(Set{Symbol}(), Set{Symbol}())
end
elseif ex.head == :macrocall && ex.args[1] isa Symbol && ex.args[1] == Symbol("@md_str")
# Does not create scope
# The Markdown macro treats things differently, so we must too
innersymstate = explore!(Markdown.toexpr(Markdown.parse(ex.args[3])), scopestate)
push!(innersymstate.references, Symbol("@md_str"))
return innersymstate
elseif (ex.head == :macrocall && ex.args[1] isa Symbol && ex.args[1] == Symbol("@bind")
&& length(ex.args) == 4 && ex.args[3] isa Symbol)
innersymstate = explore!(ex.args[4], scopestate)
push!(innersymstate.assignments, ex.args[3])
return innersymstate
elseif ex.head == :quote
# We ignore contents
return SymbolsState()
elseif ex.head == :module
# We ignore contents
return SymbolsState(Set{Symbol}(), Set{Symbol}([ex.args[2]]))
else
# fallback, includes:
# begin, block, do, toplevel
# (and hopefully much more!)
# Does not create scope (probably)
return mapfoldl(a -> explore!(a, scopestate), union!, ex.args, init=SymbolsState())
end
end
end
👀 Reading hidden code
35.1 ms

<h1><img alt="Pluto.jl" src="https://raw.githubusercontent.com/fonsp/Pluto.jl/main/frontend/img/logo.svg" width=300 height=74 ></h1>

Writing a notebook is not just about writing the final document — Pluto empowers the experiments and discoveries that are essential to getting there.

Explore models and share results in a notebook that is

  • reactive - when changing a function or variable, Pluto automatically updates all affected cells.

  • lightweight - Pluto is written in pure Julia and is easy to install

  • simple - no hidden workspace state; intuitive UI.

<img alt="reactivity screencap" src="https://raw.githubusercontent.com/fonsp/Pluto.jl/580ab811f13d565cc81ebfa70ed36c84b125f55d/demo/plutodemo.gif" >

Input

A Pluto notebook is made up of small blocks of Julia code (cells) and together they form a ***reactive*** notebook. When you change a variable, Pluto automatically re-runs the cells that refer to it. Cells can even be placed in arbitrary order - intelligent syntax analysis figures out the dependencies between them and takes care of execution.

Cells can contain arbitrary Julia code, and you can use external libraries. There are no code rewrites or wrappers, Pluto just looks at your code once before evaluation.

Output

Your notebooks are saved as pure Julia files (sample), which you can then import as if you had been programming in a regular editor all along. You can also export your notebook with cell outputs as attractive HTML and PDF documents. By reordering cells and hiding code, you have full control over how you tell your story.

<br >

Dynamic environment

Pluto offers an environment where changed code takes effect instantly and where deleted code leaves no trace. Unlike Jupyter or Matlab, there is no mutable workspace, but rather, an important guarantee: <blockquote align="center"><em><b>At any instant</b>, the program state is <b>completely described</b> by the code you see.</em></blockquote> No hidden state, no hidden bugs.

Interactivity

Your programming environment becomes interactive by splitting your code into multiple cells! Changing one cell instantly shows effects on all other cells, giving you a fast and fun way to experiment with your model.

In the example below, changing the parameter A and running the first cell will directly re-evaluate the second cell and display the new plot.

<img alt="plotting screencap" src="https://user-images.githubusercontent.com/6933510/80637344-24ac0180-8a5f-11ea-82dd-813dbceca9c9.gif" width="50%">

<br >

HTML interaction

Lastly, here's one more feature: Pluto notebooks have a @bind macro to create a live bond between an HTML object and a Julia variable. Combined with reactivity, this is a very powerful tool!

<img alt="@bind macro screencap" src="https://user-images.githubusercontent.com/6933510/80617037-e2c09280-8a41-11ea-9fb3-18bb2921dd9e.gif" width="70%">

notebook from [vdplasthijs/juliasir](https://github.com/vdplasthijs/juliasir)

<br >

You don't need to know HTML to use it! The PlutoUI package contains basic inputs like sliders and buttons.

But for those who want to dive deeper - you can use HTML, JavaScript and CSS to write your own widgets! Custom update events can be fired by dispatching a new CustomEvent("input"), making it compatible with the viewof operator of observablehq. Have a look at the sample notebooks inside Pluto to learn more!

<br > <hr > <br >

Let's do it!

Ingredients

For one tasty notebook 🥞 you will need:

  • Julia v1.0 or above

  • Linux, macOS or Windows, Linux and macOS will work best

  • Mozilla Firefox or Google Chrome, be sure to get the latest version

Installation

Run Julia and add the package:

julia> ]
(v1.0) pkg> add Pluto

Using the package manager for the first time can take up to 15 minutes - hang in there!

To run the notebook server:

julia> import Pluto
julia> Pluto.run(1234)

Then go to http://localhost:1234/ to start coding!

To developers

Follow these instructions to start working on the package.

<img src="https://raw.githubusercontent.com/gist/fonsp/9a36c183e2cad7c8fc30290ec95eb104/raw/ca3a38a61f95cd58d79d00b663a3c114d21e284e/cute.svg">

License

Pluto.jl is open source! Specifically, it is MIT Licensed. The included sample notebooks have a more permissive license: the Unlicense. This means that you can use sample notebook code however you like - you do not need to credit us!

Pluto.jl is built by gluing together open source software:

Your notebook files are yours, you do not need to credit us. Have fun!

Note

We are happy to say that Pluto.jl runs smoothly for most users, and is ready to be used in your next project!

That being said, the Pluto project is an ambition to rethink what a programming environment should be. We believe that scientific programming can be a lot simpler. Not by adding more buttons to a text editor — by giving space to creative thought, and automating the rest.

If you feel the same, give Pluto a try! We would love to hear what you think. 😊

<img alt="feedback screencap" src="https://user-images.githubusercontent.com/6933510/78135402-22d02d80-7422-11ea-900f-a8b01bdbd8d3.png" width="70%">

Questions? Have a look at the FAQ.

Created by Fons van der Plas and Mikołaj Bochenski. Inspired by Observable.

md"""
<h1><img alt="Pluto.jl" src="https://raw.githubusercontent.com/fonsp/Pluto.jl/main/frontend/img/logo.svg" width=300 height=74 ></h1>

_Writing a notebook is not just about writing the final document — Pluto empowers the experiments and discoveries that are essential to getting there._

**Explore models and share results** in a notebook that is
- **_reactive_** - when changing a function or variable, Pluto automatically updates all affected cells.
- **_lightweight_** - Pluto is written in pure Julia and is easy to install
- **_simple_** - no hidden workspace state; intuitive UI.

<img alt="reactivity screencap" src="https://raw.githubusercontent.com/fonsp/Pluto.jl/580ab811f13d565cc81ebfa70ed36c84b125f55d/demo/plutodemo.gif" >


### Input

A Pluto notebook is made up of small blocks of Julia code (_cells_) and together they form a [***reactive*** notebook](https://medium.com/@mbostock/a-better-way-to-code-2b1d2876a3a0).
When you change a variable, Pluto automatically re-runs the cells that refer to it. Cells can even be placed in arbitrary order - intelligent syntax analysis figures out the dependencies between them and takes care of execution.

Cells can contain _arbitrary_ Julia code, and you can use external libraries. There are no code rewrites or wrappers, Pluto just looks at your code once before evaluation.

### Output

Your notebooks are **saved as pure Julia files** ([sample](https://github.com/fonsp/Pluto.jl/blob/main/sample/basic.jl)), which you can then import as if you had been programming in a regular editor all along. You can also export your notebook with cell outputs as attractive HTML and PDF documents. By reordering cells and hiding code, you have full control over how you tell your story.

<br >

## Dynamic environment

Pluto offers an environment where changed code takes effect instantly and where deleted code leaves no trace.
Unlike Jupyter or Matlab, there is **no mutable workspace**, but rather, an important guarantee:
<blockquote align="center"><em><b>At any instant</b>, the program state is <b>completely described</b> by the code you see.</em></blockquote>
No hidden state, no hidden bugs.

### Interactivity

Your programming environment becomes interactive by splitting your code into multiple cells! Changing one cell **instantly shows effects** on all other cells, giving you a fast and fun way to experiment with your model.

In the example below, changing the parameter `A` and running the first cell will directly re-evaluate the second cell and display the new plot.

<img alt="plotting screencap" src="https://user-images.githubusercontent.com/6933510/80637344-24ac0180-8a5f-11ea-82dd-813dbceca9c9.gif" width="50%">

<br >

### HTML interaction
Lastly, here's _**one more feature**_: Pluto notebooks have a `@bind` macro to create a **live bond between an HTML object and a Julia variable**. Combined with reactivity, this is a very powerful tool!

<img alt="@bind macro screencap" src="https://user-images.githubusercontent.com/6933510/80617037-e2c09280-8a41-11ea-9fb3-18bb2921dd9e.gif" width="70%">

_notebook from [vdplasthijs/julia_sir](https://github.com/vdplasthijs/julia_sir)_

<br >

You don't need to know HTML to use it! The [PlutoUI package](https://github.com/fonsp/PlutoUI.jl) contains basic inputs like sliders and buttons.

But for those who want to dive deeper - you can use HTML, JavaScript and CSS to write your own widgets! Custom update events can be fired by dispatching a `new CustomEvent("input")`, making it compatible with the [`viewof` operator of observablehq](https://observablehq.com/@observablehq/a-brief-introduction-to-viewof). Have a look at the sample notebooks inside Pluto to learn more!

<br >
<hr >
<br >

# Let's do it!

### Ingredients
For one tasty notebook 🥞 you will need:
- **Julia** v1.0 or above
- **Linux**, **macOS** or **Windows**, _Linux and macOS will work best_
- Mozilla **Firefox** or Google **Chrome**, be sure to get the latest version

### Installation

Run Julia and add the package:
```julia
julia> ]
(v1.0) pkg> add Pluto
```

_Using the package manager for the first time can take up to 15 minutes - hang in there!_

To run the notebook server:
```julia
julia> import Pluto
julia> Pluto.run(1234)
```

Then go to [`http://localhost:1234/`](http://localhost:1234/) to start coding!

### To developers
Follow [these instructions](https://github.com/fonsp/Pluto.jl/blob/main/dev_instructions.md) to start working on the package.

<img src="https://raw.githubusercontent.com/gist/fonsp/9a36c183e2cad7c8fc30290ec95eb104/raw/ca3a38a61f95cd58d79d00b663a3c114d21e284e/cute.svg">

## License

Pluto.jl is open source! Specifically, it is [MIT Licensed](https://github.com/fonsp/Pluto.jl/blob/main/LICENSE). The included sample notebooks have a more permissive license: the [Unlicense](https://github.com/fonsp/Pluto.jl/blob/main/sample/LICENSE). This means that you can use sample notebook code however you like - you do not need to credit us!

Pluto.jl is built by gluing together open source software:

- `Julia` - [license](https://github.com/JuliaLang/julia/blob/master/LICENSE.md)
- `HTTP.jl` - [license](https://github.com/JuliaWeb/HTTP.jl/blob/master/LICENSE.md)
- `JSON.jl` - [license](https://github.com/JuliaWeb/HTTP.jl/blob/master/LICENSE.md)
- `CodeMirror` - [license](https://github.com/codemirror/CodeMirror/blob/master/LICENSE)
- `MathJax` - [license](https://github.com/mathjax/MathJax-src/blob/master/LICENSE)
- `observablehq/stdlib` - [license](https://github.com/observablehq/stdlib/blob/master/LICENSE)
- `preact` - [license](https://github.com/preactjs/preact/blob/master/LICENSE)
- `developit/htm` - [license](https://github.com/developit/htm/blob/master/LICENSE)

Your notebook files are _yours_, you do not need to credit us. Have fun!

## Note

We are happy to say that Pluto.jl runs smoothly for most users, and is **ready to be used in your next project**!

That being said, the Pluto project is an ambition to [_rethink what a programming environment should be_](http://worrydream.com/#!/LearnableProgramming). We believe that scientific programming can be a lot simpler. Not by adding more buttons to a text editor — by giving space to creative thought, and automating the rest.

If you feel the same, give Pluto a try! We would love to hear what you think. 😊

<img alt="feedback screencap" src="https://user-images.githubusercontent.com/6933510/78135402-22d02d80-7422-11ea-900f-a8b01bdbd8d3.png" width="70%">

Questions? Have a look at the [FAQ](https://www.notion.so/3ce1c1cff62f4f97815891cdaa3daa7d?v=b5824fb6bc804d2c90d34c4d49a1c295).

_Created by [**Fons van der Plas**](https://github.com/fonsp) and [**Mikołaj Bochenski**](https://github.com/malyvsen). Inspired by [Observable](https://observablehq.com/)._


"""
👀 Reading hidden code
5.1 ms
x
👀 Reading hidden code
12.5 μs
struct Wow
x
y
end
👀 Reading hidden code
840 μs
show(io::IO, ::MIME{Symbol("text/plain")}, w::Main.workspace#3.Wow) in Main.workspace#3 at /home/runner/work/disorganised-mess/disorganised-mess/big.jl#==#d6bb60b0-8fc4-11ea-1a96-6dffb769ac8d:1
which(show, (IO, MIME"text/plain", Wow))
👀 Reading hidden code
70.3 μs
Base.show(io::IO, ::MIME"text/plain", w::Wow) = print(io, "wowie")
👀 Reading hidden code
451 μs
ww = md"";
👀 Reading hidden code
163 μs
3×3 Matrix{Float64}:
 -0.482689   0.0102364   0.750039
  0.203227  -2.05814    -1.32106
  1.41978   -0.266789   -0.151653
s = randn((3, 3))
👀 Reading hidden code
16.1 μs
wowie
w = Wow(1, 2)
👀 Reading hidden code
15.0 μs

a

md"a"
👀 Reading hidden code
204 μs
wowie
w
👀 Reading hidden code
13.1 μs
false
w isa Base.AbstractDict
👀 Reading hidden code
16.0 μs
using Distributed
👀 Reading hidden code
198 μs
include_dependency("potato")
👀 Reading hidden code
35.4 μs
Error message

UndefVarError: Pluto not defined

Stacktrace:

[1] top-level scope

@ none:1

[2] eval

@ ./boot.jl:373 [inlined]

[3] #153

@ /opt/hostedtoolcache/julia/1.7.3/x64/share/julia/stdlib/v1.7/Distributed/src/remotecall.jl:429 [inlined]

[4] run_work_thunk(thunk::Distributed.var"#153#154"{typeof(Core.eval), Tuple{Module, Expr}, Base.Pairs{Symbol, Union{}, Tuple{}, NamedTuple{(), Tuple{}}}}, print_error::Bool)

@ Distributed /opt/hostedtoolcache/julia/1.7.3/x64/share/julia/stdlib/v1.7/Distributed/src/process_messages.jl:63

[5] #remotecall_fetch#158

@ /opt/hostedtoolcache/julia/1.7.3/x64/share/julia/stdlib/v1.7/Distributed/src/remotecall.jl:454 [inlined]

[6] remotecall_fetch

@ /opt/hostedtoolcache/julia/1.7.3/x64/share/julia/stdlib/v1.7/Distributed/src/remotecall.jl:454 [inlined]

[7] #remotecall_fetch#162

@ /opt/hostedtoolcache/julia/1.7.3/x64/share/julia/stdlib/v1.7/Distributed/src/remotecall.jl:496 [inlined]

[8] remotecall_fetch

@ /opt/hostedtoolcache/julia/1.7.3/x64/share/julia/stdlib/v1.7/Distributed/src/remotecall.jl:496 [inlined]

[9] remotecall_eval(m::Module, pid::Int64, ex::Expr)

@ Distributed /opt/hostedtoolcache/julia/1.7.3/x64/share/julia/stdlib/v1.7/Distributed/src/macros.jl:242

[10] ##function_wrapped_cell#406

@ ~/work/disorganised-mess/disorganised-mess/big.jl#==#9749bdd8-93c0-11ea-218e-bb3c8aca84a6:1 [inlined]

[11] var"##function_wrapped_cell#406"(Distributed::Module, Main::Module)

@ Main ./none:0

[12] invokelatest(::Any, ::Any, ::Vararg{Any}; kwargs::Base.Pairs{Symbol, Union{}, Tuple{}, NamedTuple{(), Tuple{}}})

@ Base ./essentials.jl:716

[13] invokelatest(::Any, ::Any, ::Vararg{Any})

@ Base ./essentials.jl:714

[14] compute(m::Module, computer::PlutoRunner.Computer)

@ PlutoRunner ~/.julia/packages/Pluto/6smog/src/runner/PlutoRunner/src/evaluation/run_expression.jl:85

[15] (::PlutoRunner.var"#34#37"{Module})()

@ PlutoRunner ~/.julia/packages/Pluto/6smog/src/runner/PlutoRunner/src/evaluation/run_expression.jl:261

[16] run_inside_trycatch(m::Module, f::PlutoRunner.var"#34#37"{Module})

@ PlutoRunner ~/.julia/packages/Pluto/6smog/src/runner/PlutoRunner/src/evaluation/run_expression.jl:125

[17] (::PlutoRunner.var"#32#35"{Bool, Module, Expr, Base.UUID, Base.UUID, Tuple{Set{Symbol}, Set{Symbol}}, Nothing, UInt64, Expr})()

@ PlutoRunner ~/.julia/packages/Pluto/6smog/src/runner/PlutoRunner/src/evaluation/run_expression.jl:261

[18] with_io_to_logs(f::PlutoRunner.var"#32#35"{Bool, Module, Expr, Base.UUID, Base.UUID, Tuple{Set{Symbol}, Set{Symbol}}, Nothing, UInt64, Expr}; enabled::Bool, loglevel::Base.CoreLogging.LogLevel)

@ PlutoRunner ~/.julia/packages/Pluto/6smog/src/runner/PlutoRunner/src/io/stdout.jl:64

[19] (::PlutoRunner.var"#126#127"{Bool, Base.CoreLogging.LogLevel, PlutoRunner.var"#32#35"{Bool, Module, Expr, Base.UUID, Base.UUID, Tuple{Set{Symbol}, Set{Symbol}}, Nothing, UInt64, Expr}})()

@ PlutoRunner ~/.julia/packages/Pluto/6smog/src/runner/PlutoRunner/src/io/logging.jl:129

[20] with_logstate(f::Function, logstate::Any)

@ Base.CoreLogging ./logging.jl:511

[21] with_logger

@ ./logging.jl:623 [inlined]

[22] #with_logger_and_io_to_logs#125

@ ~/.julia/packages/Pluto/6smog/src/runner/PlutoRunner/src/io/logging.jl:128 [inlined]

[23] run_expression(m::Module, expr::Expr, notebook_id::Base.UUID, cell_id::Base.UUID, function_wrapped_info::Union{Nothing, Tuple{Set{Symbol}, Set{Symbol}}}, forced_expr_id::Union{Nothing, UInt64}; user_requested_run::Bool, capture_stdout::Bool)

@ PlutoRunner ~/.julia/packages/Pluto/6smog/src/runner/PlutoRunner/src/evaluation/run_expression.jl:236

[24] top-level scope

@ ~/.julia/packages/Pluto/6smog/src/evaluation/WorkspaceManager.jl:439

[25] eval

@ ./boot.jl:373 [inlined]

[26] macro expansion

@ ~/.julia/packages/Malt/YJ2Ml/src/worker.jl:120 [inlined]

[27] (::var"#1#2"{Sockets.TCPSocket, UInt64, Bool, Base.Pairs{Symbol, Union{}, Tuple{}, NamedTuple{(), Tuple{}}}, Tuple{Module, Expr}, typeof(Core.eval)})()

@ Main ./task.jl:429

Stack trace

Here is what happened, the most recent locations are first:

  1. #remotecall_fetch#158
  2. remotecall_fetch
  3. #remotecall_fetch#162
  4. remotecall_fetch
  5. remotecall_eval(m::Module, pid::Int64, ex::Expr)
  6. Distributed.remotecall_eval(Main, 1, :(VersionNumber(Pluto.Pkg.TOML.parsefile(joinpath(Pluto.PKG_ROOT_DIR, "Project.toml"))["version"])))
C'est la vie !
Distributed.remotecall_eval(Main, 1, :(VersionNumber(Pluto.Pkg.TOML.parsefile(joinpath(Pluto.PKG_ROOT_DIR, "Project.toml"))["version"])))
👀 Reading hidden code
---
Error message

UndefVarError: Pluto not defined

Stacktrace:

[1] top-level scope

@ :0

[2] eval

@ ./boot.jl:373 [inlined]

[3] #153

@ /opt/hostedtoolcache/julia/1.7.3/x64/share/julia/stdlib/v1.7/Distributed/src/remotecall.jl:429 [inlined]

[4] run_work_thunk(thunk::Distributed.var"#153#154"{typeof(Core.eval), Tuple{Module, Expr}, Base.Pairs{Symbol, Union{}, Tuple{}, NamedTuple{(), Tuple{}}}}, print_error::Bool)

@ Distributed /opt/hostedtoolcache/julia/1.7.3/x64/share/julia/stdlib/v1.7/Distributed/src/process_messages.jl:63

[5] #remotecall_fetch#158

@ /opt/hostedtoolcache/julia/1.7.3/x64/share/julia/stdlib/v1.7/Distributed/src/remotecall.jl:454 [inlined]

[6] remotecall_fetch

@ /opt/hostedtoolcache/julia/1.7.3/x64/share/julia/stdlib/v1.7/Distributed/src/remotecall.jl:454 [inlined]

[7] #remotecall_fetch#162

@ /opt/hostedtoolcache/julia/1.7.3/x64/share/julia/stdlib/v1.7/Distributed/src/remotecall.jl:496 [inlined]

[8] remotecall_fetch

@ /opt/hostedtoolcache/julia/1.7.3/x64/share/julia/stdlib/v1.7/Distributed/src/remotecall.jl:496 [inlined]

[9] remotecall_eval(m::Module, pid::Int64, ex::Expr)

@ Distributed /opt/hostedtoolcache/julia/1.7.3/x64/share/julia/stdlib/v1.7/Distributed/src/macros.jl:242

[10] ##function_wrapped_cell#410

@ ~/work/disorganised-mess/disorganised-mess/big.jl#==#e46bc5fe-93c0-11ea-3a28-a57866436552:1 [inlined]

[11] var"##function_wrapped_cell#410"(Distributed::Module, Main::Module)

@ Main ./none:0

[12] invokelatest(::Any, ::Any, ::Vararg{Any}; kwargs::Base.Pairs{Symbol, Union{}, Tuple{}, NamedTuple{(), Tuple{}}})

@ Base ./essentials.jl:716

[13] invokelatest(::Any, ::Any, ::Vararg{Any})

@ Base ./essentials.jl:714

[14] compute(m::Module, computer::PlutoRunner.Computer)

@ PlutoRunner ~/.julia/packages/Pluto/6smog/src/runner/PlutoRunner/src/evaluation/run_expression.jl:85

[15] (::PlutoRunner.var"#34#37"{Module})()

@ PlutoRunner ~/.julia/packages/Pluto/6smog/src/runner/PlutoRunner/src/evaluation/run_expression.jl:261

[16] run_inside_trycatch(m::Module, f::PlutoRunner.var"#34#37"{Module})

@ PlutoRunner ~/.julia/packages/Pluto/6smog/src/runner/PlutoRunner/src/evaluation/run_expression.jl:125

[17] (::PlutoRunner.var"#32#35"{Bool, Module, Expr, Base.UUID, Base.UUID, Tuple{Set{Symbol}, Set{Symbol}}, Nothing, UInt64, Expr})()

@ PlutoRunner ~/.julia/packages/Pluto/6smog/src/runner/PlutoRunner/src/evaluation/run_expression.jl:261

[18] with_io_to_logs(f::PlutoRunner.var"#32#35"{Bool, Module, Expr, Base.UUID, Base.UUID, Tuple{Set{Symbol}, Set{Symbol}}, Nothing, UInt64, Expr}; enabled::Bool, loglevel::Base.CoreLogging.LogLevel)

@ PlutoRunner ~/.julia/packages/Pluto/6smog/src/runner/PlutoRunner/src/io/stdout.jl:64

[19] (::PlutoRunner.var"#126#127"{Bool, Base.CoreLogging.LogLevel, PlutoRunner.var"#32#35"{Bool, Module, Expr, Base.UUID, Base.UUID, Tuple{Set{Symbol}, Set{Symbol}}, Nothing, UInt64, Expr}})()

@ PlutoRunner ~/.julia/packages/Pluto/6smog/src/runner/PlutoRunner/src/io/logging.jl:129

[20] with_logstate(f::Function, logstate::Any)

@ Base.CoreLogging ./logging.jl:511

[21] with_logger

@ ./logging.jl:623 [inlined]

[22] #with_logger_and_io_to_logs#125

@ ~/.julia/packages/Pluto/6smog/src/runner/PlutoRunner/src/io/logging.jl:128 [inlined]

[23] run_expression(m::Module, expr::Expr, notebook_id::Base.UUID, cell_id::Base.UUID, function_wrapped_info::Union{Nothing, Tuple{Set{Symbol}, Set{Symbol}}}, forced_expr_id::Union{Nothing, UInt64}; user_requested_run::Bool, capture_stdout::Bool)

@ PlutoRunner ~/.julia/packages/Pluto/6smog/src/runner/PlutoRunner/src/evaluation/run_expression.jl:236

[24] top-level scope

@ ~/.julia/packages/Pluto/6smog/src/evaluation/WorkspaceManager.jl:439

[25] eval

@ ./boot.jl:373 [inlined]

[26] macro expansion

@ ~/.julia/packages/Malt/YJ2Ml/src/worker.jl:120 [inlined]

[27] (::var"#1#2"{Sockets.TCPSocket, UInt64, Bool, Base.Pairs{Symbol, Union{}, Tuple{}, NamedTuple{(), Tuple{}}}, Tuple{Module, Expr}, typeof(Core.eval)})()

@ Main ./task.jl:429

Stack trace

Here is what happened, the most recent locations are first:

  1. #remotecall_fetch#158
  2. remotecall_fetch
  3. #remotecall_fetch#162
  4. remotecall_fetch
  5. remotecall_eval(m::Module, pid::Int64, ex::Expr)
  6. Distributed.remotecall_eval(Main, 1, :(Pluto.PLUTO_VERSION))
Distributed.remotecall_eval(Main, 1, :(Pluto.PLUTO_VERSION))
👀 Reading hidden code
---
[1] |> Base.nfields, w |> Base.sizeof
👀 Reading hidden code
175 μs
x = [1, [2,3,4], 620:800...]
👀 Reading hidden code
31.5 ms
doggos = [i,i,i, @bind p html"<input type='range' />"]
👀 Reading hidden code
152 ms
missing
p
👀 Reading hidden code
12.3 μs
Dict(:a => 1, :b => ["hoi", "merlino"])
👀 Reading hidden code
26.6 μs
good_boys = Dict(:title => md"# Hello world", :img => i) # :names => ["Hannes", "Floep"]
👀 Reading hidden code
86.0 ms
m = md"asasdf $x+1$ asdfasdf".content
👀 Reading hidden code
3.2 ms
"183-element Vector&#123;Any&#125;:\n   1\n    &#91;2, 3, 4&#93;\n 620\n 621\n 622\n 623\n 624\n 625\n 626\n 627\n 628\n 629\n 630\n 631\n 632\n 633\n 634\n 635\n 636\n 637\n 638\n 639\n 640\n 641\n 642\n 643\n 644\n 645\n 646\n 647\n 648\n 649\n 650\n 651\n 652\n 653\n 654\n 655\n 656\n 657\n 658\n 659\n 660\n 661\n 662\n 663\n 664\n 665\n 666\n 6" ⋯ 369 bytes ⋯ "741\n 742\n 743\n 744\n 745\n 746\n 747\n 748\n 749\n 750\n 751\n 752\n 753\n 754\n 755\n 756\n 757\n 758\n 759\n 760\n 761\n 762\n 763\n 764\n 765\n 766\n 767\n 768\n 769\n 770\n 771\n 772\n 773\n 774\n 775\n 776\n 777\n 778\n 779\n 780\n 781\n 782\n 783\n 784\n 785\n 786\n 787\n 788\n 789\n 790\n 791\n 792\n 793\n 794\n 795\n 796\n 797\n 798\n 799\n 800"
sprint(Markdown.tohtml, x)
👀 Reading hidden code
300 ms

A 123 D

md"A $([1,2,3]) D"
👀 Reading hidden code
317 μs
#= begin
import Markdown: html, htmlinline, Paragraph, withtag, tohtml
function html(io::IO, md::Paragraph)
withtag(io, :p) do
for x in md.content
htmlinline(io, x)
end
end
end
htmlinline(io::IO, content::Vector) = tohtml(io, content)
end =#
👀 Reading hidden code
20.0 μs
2
begin
1
2
end
👀 Reading hidden code
38.4 μs

asdf Dict{Symbol, Markdown.MD} with 2 entries: :title => # Hello world :img => ![asdf](https://fonsp.com/img/doggoSmall.jpg?raw=true) asd

md"asdf $(good_boys) asd"
👀 Reading hidden code
334 μs
"<div class=\"markdown\"><p>asdf Dict&#123;Symbol, Markdown.MD&#125; with 2 entries:\n  :title &#61;&gt; # Hello world\n\n  :img &#61;&gt; &#33;&#91;asdf&#93;&#40;https://fonsp.com/img/doggoSmall.jpg?raw&#61;true&#41;\n asd</p>\n</div>"
repr(MIME"text/html"(), md"asdf $(good_boys) asd")
👀 Reading hidden code
22.1 ms
#= begin
import Markdown: html, tohtml, withtag
function tohtml(io::IO, m::MIME"text/html", x)
withtag(io, :DIV) do
show(io, m, x)
end
end
end =#
👀 Reading hidden code
21.6 μs
occursin.(["a"], ["aa", "bb"])
👀 Reading hidden code
96.0 ms
1.0
sqrt(1...)
👀 Reading hidden code
6.3 ms

asdf

md"asdf "
👀 Reading hidden code
241 μs
x
👀 Reading hidden code
10.8 μs
Dict([i => i for i in 1:100])
👀 Reading hidden code
70.0 ms
false
Vector{UInt8}() isa String
👀 Reading hidden code
1.4 ms
Base.OneTo(9)
r = Set([123,54,1,2,23,23,21,42,34234,4]) |> Base.axes1
👀 Reading hidden code
3.8 ms

asdf

i = md"![asdf](https://fonsp.com/img/doggoSmall.jpg?raw=true)"
👀 Reading hidden code
28.7 ms

asdf 1234620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800 asdf

md"asdf $(x) asdf"
👀 Reading hidden code
252 μs

asdf Main.workspace#3.Derp(1, 2) asdf

md"asdf $(d) asdf"
👀 Reading hidden code
263 μs
Error message

MethodError: no method matching getindex(::Base.Iterators.Enumerate{Vector{Any}}, ::Int64)

Stack trace

Here is what happened, the most recent locations are first:

  1. 	enu = enumerate(x)	enu[1], enu[1]end
let
enu = enumerate(x)
enu[1], enu[1]
end
👀 Reading hidden code
---
md"I like [_dogs_](dogs.org) **and** cats!".content
👀 Reading hidden code
367 μs





















html"<br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br>"
👀 Reading hidden code
138 μs
ENV
👀 Reading hidden code
10.0 μs
zip([1,2],[3,4]) |> collect
👀 Reading hidden code
51.8 ms
#= begin
import Base: show
function show_richest_textmime(io::IO, x::Any)
if showable(MIME("text/html"), x)
show(io, MIME("text/html"), x)
else
show(io, MIME("text/plain"), x)
end
end
function show_array_row(io::IO, pair::Tuple)
i, el = pair
print(io, "<r><i>", i, "</i><e>")
show_richest_textmime(io, el)
print(io, "</e></r>")
end
function show_dict_row(io::IO, pair::Pair)
k, el = pair
print(io, "<r><k>")
show_richest_textmime(io, k)
print(io, "</k><e>")
show_richest_textmime(io, el)
print(io, "</e></r>")
end
function show(io::IO, ::MIME"text/html", x::Array{<:Any, 1})
print(io, """<jltree class="collapsed" onclick="onjltreeclick(this, event)">""")
print(io, eltype(x))
print(io, "<jlarray>")
if length(x) <= tree_display_limit
show_array_row.([io], enumerate(x))
else
show_array_row.([io], enumerate(x[1:tree_display_limit]))
print(io, "<r><more></more></r>")
from_end = tree_display_limit > 20 ? 10 : 1
indices = 1+length(x)-from_end:length(x)
show_array_row.([io], zip(indices, x[indices]))
end
print(io, "</jlarray>")
print(io, "</jltree>")
end
function show(io::IO, ::MIME"text/html", x::Dict{<:Any, <:Any})
print(io, """<jltree class="collapsed" onclick="onjltreeclick(this, event)">""")
print(io, "Dict")
print(io, "<jldict>")
row_index = 1
for pair in x
show_dict_row(io, pair)
if row_index == tree_display_limit
print(io, "<r><more></more></r>")
break
end
row_index += 1
end
print(io, "</jldict>")
print(io, "</jltree>")
end
end =#
👀 Reading hidden code
20.3 μs
Error message

MethodError: no method matching lastindex(::Dict{Symbol, Markdown.MD})

Closest candidates are:

lastindex(::Any, ::Any) at /opt/hostedtoolcache/julia/1.7.3/x64/share/julia/base/abstractarray.jl:373

lastindex(::Tuple) at /opt/hostedtoolcache/julia/1.7.3/x64/share/julia/base/tuple.jl:26

lastindex(::Pair) at /opt/hostedtoolcache/julia/1.7.3/x64/share/julia/base/pair.jl:51

...

Stack trace

Here is what happened, the most recent locations are first:

  1. good_boys[1:end]
good_boys[1:end]
👀 Reading hidden code
---

a

md"a"
👀 Reading hidden code
218 μs
3×3 Matrix{Float64}:
 0.923833  0.888414  0.457494
 0.298344  0.406496  0.401118
 0.237243  0.20092   0.375773
rand(Float64, (3, 3))
👀 Reading hidden code
39.6 ms

The Basel problem

Leonard Euler proved in 1741 that the series

11+14+19+

converges to

π26

md"# The Basel problem

_Leonard Euler_ proved in 1741 that the series

$$\frac{1}{1} + \frac{1}{4} + \frac{1}{9} + \cdots$$

converges to

$$\frac{\pi^2}{6}$$"
👀 Reading hidden code
339 μs

The Basel problem

Leonard Euler proved in 1741 that the series

11+14+19+

converges to

π26

md"# The Basel problem

_Leonard Euler_ proved in 1741 that the series

$$\frac{1}{1} + \frac{1}{4} + \frac{1}{9} + \cdots$$

converges to

$$\frac{\pi^2}{6}$$"
👀 Reading hidden code
328 μs
3.04936163598207
sqrt(sum(seq) * 6.0)
👀 Reading hidden code
17.3 μs
IOContext(Base.PipeEndpoint(RawFD(4294967295) closed, 0 bytes waiting))
ctx = IOContext(stdout)
👀 Reading hidden code
15.0 μs
Error message

UndefVarError: iocontext not defined

Stack trace

Here is what happened, the most recent locations are first:

  1. getproperty
    from Base.jl:35
  2. get(PlutoRunner.iocontext, :module, @__MODULE__)
get(PlutoRunner.iocontext, :module, @__MODULE__)
👀 Reading hidden code
---
mutable struct Derp
left
right
end
👀 Reading hidden code
848 μs
ENV
👀 Reading hidden code
8.6 μs
(a = 12, b = :a)
👀 Reading hidden code
25.6 μs
Error message

UndefVarError: sprint_withreturned not defined

Stack trace

Here is what happened, the most recent locations are first:

  1. getproperty
    from Base.jl:35
  2. PlutoRunner.sprint_withreturned(PlutoRunner.show_richest, "a")
PlutoRunner.sprint_withreturned(PlutoRunner.show_richest, "a")
👀 Reading hidden code
---
Error message

UndefVarError: sprint_withreturned not defined

Stack trace

Here is what happened, the most recent locations are first:

  1. getproperty
    from Base.jl:35
  2. PlutoRunner.sprint_withreturned(PlutoRunner.show_richest, "a")
PlutoRunner.sprint_withreturned(PlutoRunner.show_richest, "a")
👀 Reading hidden code
---
"\"a\""
sprint(PlutoRunner.show_richest, "a")
👀 Reading hidden code
51.5 ms
"\"a\""
sprint(PlutoRunner.show_richest, "a")
👀 Reading hidden code
116 μs
Error message

UndefVarError: sprint_withreturned not defined

Stack trace

Here is what happened, the most recent locations are first:

  1. getproperty
    from Base.jl:35
  2. PlutoRunner.sprint_withreturned(show, MIME"text/plain"(), "a")
PlutoRunner.sprint_withreturned(show, MIME"text/plain"(), "a")
👀 Reading hidden code
---
Error message

UndefVarError: sprint_withreturned not defined

Stack trace

Here is what happened, the most recent locations are first:

  1. getproperty
    from Base.jl:35
  2. PlutoRunner.sprint_withreturned(show, MIME"text/plain"(), "a")
PlutoRunner.sprint_withreturned(show, MIME"text/plain"(), "a")
👀 Reading hidden code
---
"\"a\""
sprint(show, MIME"text/plain"(), "a")
👀 Reading hidden code
42.6 μs
true
istextmime(MIME"text/plain"())
👀 Reading hidden code
36.4 μs
"a"
"a"
👀 Reading hidden code
20.8 μs
MIME type text/plain
mime = MIME"text/plain"()
👀 Reading hidden code
59.0 μs
String
t = String
👀 Reading hidden code
13.1 μs
false
mime isa MIME"text/plain" &&
t isa DataType &&
which(show, (IO, MIME"text/plain", t)) === PlutoRunner.struct_showmethod_mime &&
which(show, (IO, t)) === PlutoRunner.struct_showmethod
👀 Reading hidden code
102 μs
show(io::IO, mime::MIME{Symbol("text/plain")}, str::AbstractString; limit) in Base at strings/io.jl:196
which(show, (IO, MIME"text/plain", String))
👀 Reading hidden code
2.7 ms
show_richest (generic function with 1 method)
f = PlutoRunner.show_richest
👀 Reading hidden code
15.6 μs
args = ["a"]
👀 Reading hidden code
15.0 μs
MIME type text/plain
first(filter(m -> Base.invokelatest(showable, m, x), PlutoRunner.allmimes))
👀 Reading hidden code
64.4 ms
MIME type text/plain
first(filter(m -> showable(m, x), PlutoRunner.allmimes))
👀 Reading hidden code
77.6 ms
12
findfirst(m -> showable(m, x), PlutoRunner.allmimes)
👀 Reading hidden code
49.6 ms
xshowable (generic function with 1 method)
xshowable(m) = showable(m, x)
👀 Reading hidden code
365 μs
fr (generic function with 1 method)
function fr()
PlutoRunner.allmimes[findfirst(m -> showable(m, x), PlutoRunner.allmimes)]
end
👀 Reading hidden code
833 μs
12
findnext(m -> showable(m, x), PlutoRunner.allmimes, 1)
👀 Reading hidden code
44.4 ms
MIME type text/plain
fr()
👀 Reading hidden code
48.6 ms
[1 for i in 1:3]
👀 Reading hidden code
17.1 μs
collect(1:3)
👀 Reading hidden code
14.8 μs
12
let
x = [1,2,3]
findfirst(m -> showable(m, x), PlutoRunner.allmimes)
end
👀 Reading hidden code
82.9 ms
MIME type text/plain
let
x = [1,2,3]
local mime
for m in PlutoRunner.allmimes
if showable(m, x)
mime = m
end
end
mime
end
👀 Reading hidden code
8.2 ms
Error message

UndefVarError: mmmm not defined

Stack trace

Here is what happened, the most recent locations are first:

  1. mmmm
mmmm
👀 Reading hidden code
---
# 15 methods for generic function findnext:
methods(findnext)
👀 Reading hidden code
54.6 μs
[showable(m, x) for m in PlutoRunner.allmimes]
👀 Reading hidden code
56.5 ms
[false for m in PlutoRunner.allmimes];
👀 Reading hidden code
15.6 ms
map(m -> m, PlutoRunner.allmimes);
👀 Reading hidden code
88.6 ms
true
showable(MIME"text/plain"(),x)
👀 Reading hidden code
78.2 μs
false
showable(MIME"image/gif"(),x)
👀 Reading hidden code
41.4 μs
false
showable(MIME"image/bmp"(),x)
👀 Reading hidden code
38.5 μs
false
showable(MIME"image/jpg"(),x)
👀 Reading hidden code
46.5 μs
false
showable(MIME"image/png"(),x)
👀 Reading hidden code
56.0 μs
false
showable(MIME"image/svg+xml"(),x)
👀 Reading hidden code
55.4 μs
false
showable(MIME"text/html"(),x)
👀 Reading hidden code
64.2 μs
false
showable(MIME"application/vnd.pluto.tree+xml"(),x)
👀 Reading hidden code
42.3 μs
if false
afsddfsadfsadfs
end
👀 Reading hidden code
119 μs
d = Derp(1, 2)
👀 Reading hidden code
12.7 μs
x |> Tuple
👀 Reading hidden code
1.8 ms
typename(Derp)
tn = ((d |> typeof).name)
👀 Reading hidden code
85.8 μs
# 271 methods for generic function show:
methods(show)
👀 Reading hidden code
3.3 ms
let
a = Derp(nothing, nothing)
b = Derp(a, nothing)
a.left = b
a, b
end
👀 Reading hidden code
34.0 μs
1:10
n = 1:10
👀 Reading hidden code
15.8 μs
seq = n.^-2
👀 Reading hidden code
58.6 ms