Skip to content

Commit

Permalink
Print ::Mux.Closure instead of ::Mux.var""{...}
Browse files Browse the repository at this point in the history
Replaces #140.

I rewrote this because I wanted us to correctly match the braces, which
isn't practical with Regex.
  • Loading branch information
cmcaine committed Sep 10, 2023
1 parent 9d6bb83 commit 1d04884
Show file tree
Hide file tree
Showing 4 changed files with 108 additions and 1 deletion.
1 change: 1 addition & 0 deletions src/Mux.jl
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ using Hiccup

include("lazy.jl")
include("server.jl")
include("backtrace_rewriting.jl")
include("basics.jl")
include("routing.jl")

Expand Down
79 changes: 79 additions & 0 deletions src/backtrace_rewriting.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
"""
mux_showerror(io, exc, bt)
`showerror(io, exc, bt)`, but simplify the printing of all those Mux closures.
"""
function mux_showerror(io, e, bt)
buf = IOBuffer()
showerror(buf, e, bt)
str = String(take!(buf))
write(io, rename_mux_closures(str))
end

"""
find_matching_index(str, idx, closing_char)
Find the index in `str` of the matching `closing_char` for the opening character at `idx`, or `nothing` if there is no matching character.
If there is a matching character, `str[idx:find_matching_index(str, idx, closing_char)]` will contain:
- n opening characters, where 1 ≤ n
- m closing characters, where 1 ≤ m ≤ n
The interior opening and closing characters need not be balanced.
# Examples
```
julia> find_closing_char("((()))", 1, ')')
6
julia> find_closing_char("Vector{Union{Int64, Float64}}()", 7, '}')
29
```
"""
function find_closing_char(str, idx, closing_char)
opening_char = str[idx]
open = 1
while open != 0 && idx < lastindex(str)
idx = nextind(str, idx)
char = str[idx]
if char == opening_char
open += 1
elseif char == closing_char
open -= 1
end
end
return open == 0 ? idx : nothing
end

"""
rename_mux_closures(str)
Replace all anonymous "Mux.var" closures in `str` with "Mux.Closure" to make backtraces easier to read.
"""
function rename_mux_closures(str)
maybe_idx = findfirst(r"Mux\.var\"#\w+#\w+\"{", str)
if isnothing(maybe_idx)
return str
else
start_idx, brace_idx = extrema(maybe_idx)
end
maybe_idx = find_closing_char(str, brace_idx, '}')
if !isnothing(maybe_idx)
suffix = maybe_idx == lastindex(str) ? "" : str[nextind(str, maybe_idx):end]
str = str[1:prevind(str, start_idx)] * "Mux.Closure" * suffix
rename_mux_closures(str)
else
str
end
end

"""
Closure
Mux doesn't really use this type, we just print `Mux.Closure` instead of `Mux.var"#1#2{Mux.var"#3#4"{...}}` in stacktraces to make them easier to read.
"""
struct Closure
Closure() = error("""Mux doesn't really use this type, we just print `Mux.Closure` instead of `Mux.var"#1#2{Mux.var"#3#4"{...}}` in stacktraces to make them easier to read.""")
end
11 changes: 10 additions & 1 deletion src/basics.jl
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ function basiccatch(app, req)
println(io, "<h1>Internal Error</h1>")
println(io, "<p>$(error_phrases[rand(1:length(error_phrases))])</p>")
println(io, "<pre class=\"box\">")
showerror(io, e, catch_backtrace())
mux_showerror(io, e, catch_backtrace())
println(io, "</pre>")
return d(:status => 500, :body => codeunits(String(take!(io))))
end
Expand All @@ -98,3 +98,12 @@ function stderrcatch(app, req)
return d(:status => 500, :body => codeunits("Internal server error"))
end
end

function prettierstderrcatch(app, req)
try
app(req)
catch e
mux_showerror(stderr, e, catch_backtrace())
return d(:status => 500, :body => codeunits("Internal server error"))
end
end
18 changes: 18 additions & 0 deletions test/runtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -177,4 +177,22 @@ println("SSL/TLS")
end
end

@testset "rename_mux_closures" begin
s1 = """
[4] prettystderrcatch(app::Mux.var"#1#2"{typeof(test), Mux.var"#1#2"{Mux.var"#5#6"{Mux.var"#33#34"{Vector{Any}}, Mux.var"#23#24"{String}}, Mux.var"#1#2"{Mux.var"#5#6"{Mux.var"#33#34"{Vector{SubString{String}}}, Mux.var"#1#2"{Mux.var"#5#6"{Mux.var"#37#38"{Float64}, Mux.var"#23#24"{String}}, Mux.var"#23#24"{String}}}, Mux.var"#1#2"{Mux.var"#5#6"{Mux.var"#33#34"{Vector{SubString{String}}}, var"#5#7"}, Mux.var"#1#2"{Mux.var"#21#22"{Mux.var"#25#26"{Symbol, Int64}}, Mux.var"#23#24"{String}}}}}}, req::Dict{Any, Any})"""
e1 = "[4] prettystderrcatch(app::Mux.Closure, req::Dict{Any, Any})"
@test Mux.rename_mux_closures(s1) == e1

s2 = """[21] (::Mux.var"#7#8"{Mux.App})(req::HTTP.Messages.Request)"""
e2 = """[21] (::Mux.Closure)(req::HTTP.Messages.Request)"""
@test Mux.rename_mux_closures(s2) == e2

# Replace multiple closures at once
@test Mux.rename_mux_closures(s1 * '\n' * s2) == e1 * '\n' * e2

# Leave malformed input alone
s3 = """gabble (::Mux.var"#7#8{ gabble"""
@test Mux.rename_mux_closures(s3) == s3
end

end

0 comments on commit 1d04884

Please sign in to comment.