Here’s the prototype.
macro error_dispatch(e)
_error_dispatch(e)
end
function _error_dispatch(ex)
catch_block = ex.args[3]
exception = ex.args[2]
catch_func = gensym(:catch)
catch_block.args = map(catch_block.args) do cex
if cex isa Expr && cex.head == :(->)
_anon_to_named_func(catch_func, cex)
else
cex
end
end
push!(catch_block.args, :($catch_func($exception)))
esc(ex)
end
function _anon_to_named_func(name::Symbol, anon::Expr)
@assert(anon.head == :(->))
func_args = anon.args[1]
func_body = anon.args[2]
quote
$name($func_args) = $func_body
end
end
Here is a demonstration:
julia> function foo(g)
@error_dispatch try
g()
catch e
e::AssertionError -> println("Hello. I got an AssertionError!")
e::InexactError -> println("Hola. ¡Recibí un IneaxctError!")
end
end
foo (generic function with 1 method)
julia> foo(()->@assert(false))
Hello. I got an AssertionError!
julia> foo(()->Int(5.2))
Hola. ¡Recibí un IneaxctError!
It works by converting all the anonymous functions created in the catch block into methods of the same named function. Then it adds a statement to call that named function with the exception.
julia> @macroexpand @error_dispatch try
g()
catch e
e::AssertionError -> println("Hello. I got an AssertionError!")
e::InexactError -> println("Hola. ¡Recibí un IneaxctError!")
end
:(try
#= REPL[81]:2 =#
g()
catch e
#= REPL[81]:4 =#
begin
#= REPL[74]:6 =#
var"##catch#310"(e::AssertionError) = begin
#= REPL[74]:6 =#
begin
#= REPL[81]:4 =#
println("Hello. I got an AssertionError!")
end
end
end
#= REPL[81]:5 =#
begin
#= REPL[74]:6 =#
var"##catch#310"(e::InexactError) = begin
#= REPL[74]:6 =#
begin
#= REPL[81]:5 =#
println("Hola. ¡Recibí un IneaxctError!")
end
end
end
var"##catch#310"(e)
end)
Should I turn this into a package?