When working on a possible PR for the new Base.Test infrastructure I run
into a design problem of how to allow flexible control of how the expr
available to a macro is executed. Sorry if this is trivial but I'd
appreciate any design ideas/pointers. Simplified code below to try and
explain what I mean.
# A macro can eval in the calling context:
macro foo(ex)
quote
$(esc(ex))
end
end
a = 1
@foo begin
a += 1
end
@show(a); # a = 2
# But lets say I want to be able to dynamically control how the expr
# of a macro is executed via a Runner (this is a convoluted/dummy example
but
# simplified from a more complex case where there are multiple types
# of Runners)
type Runner
reps::Int64
Runner() = new(2)
end
run(f::Function, r::Runner) = begin
for i in 1:r.reps
f()
end
end
# Is there any way I can "package" the expr a macro has so that its
execution
# is controlled by an instance of the Runner above while still evaluating
# the expr in the scope where the macro is called?
# First try:
macro foo1(ex)
quote
r = Runner()
run(r) do # UndefVarError since do-block creates new scope?
$(esc(ex))
end
end
end
@foo1 begin
a += 1 # UndefVarError!
end
@show(a);
# What I could do is maybe have dispatch on Type{Runner}to generate the
run code to be spliced into
# the macro but this seems inelegant and maybe error prone since it mixes
compile-time
# and runtime (since Type{Runner} is needed at macro expansion time).
# Any ideas on a clean and elegant way to accomplish this?
# Further details at the bottom
of: https://github.com/JuliaLang/julia/pull/14971
Thanks!