I want to write a macro that, before the enclosed expressions is run, activates “unsafe mode” and deactivates this mode again afterwards, kind of like
@unsafe_mode my_expr
translating to
unsafe(true)
my_expr
unsafe(false)
This is not too hard to write, but it gets trickier. The expression passed in by the user might fail, and must thus be enclosed in a try/finally
block, so that unsafe(false)
is always run no matter what. This is where I run into problems. If my_expr
containts an assignment, I want to declare those assigned variables local outside of the try block so that the user can use them. I have not managed to do this. Here is my attempt
using MacroTools
state = false
unsafe_state() = state
unsafe_state(x) = (global state = x)
macro unsafe_comparisons(ex)
@capture(ex, assigned_vars__ = y_) # if assigned_vars is empty do something
quote
previous_state = unsafe_state()
unsafe_state(true)
local $(esc.(assigned_vars)...)
local res
try
res = ($(esc(ex)))
finally
unsafe_state(previous_state)
end
res
end
end
julia> @unsafe a = 1
ERROR: syntax: invalid syntax in "local" declaration
I also tried
macro unsafe(ex)
@capture(ex, assigned_vars__ = y_)
ex1 = quote
previous_state = unsafe_state()
unsafe_state(true)
end
ex2 =Expr(:local, esc.(assigned_vars)...)
quote
$ex1
$ex2
local res
try
res = ($(esc(ex)))
finally
unsafe_state(previous_state)
end
res
end
end
julia> @unsafe a = 1
1
julia> a
ERROR: UndefVarError: a not defined
which returns the correct value but does not define a
.
I’m kind of lost at this point as to what to try
Edit:
The second version actually works if the macro is used inside a function
julia> test() = (@unsafe(a = 1); a)
test (generic function with 1 method)
julia> test()
1
It does however not work if the macro is used in global scope. I suspect that when used in global scope, I have to somehow declare the assigned variables local instead of global, but I do not know how to detect this.