To clarify the possible solution hinted at in my previous message here is
code to show how it could be done:
function run_code(t::Type{Runner}, runnername::Symbol, block::Expr)
quote
for i in 1:($runnername.reps)
$block
end
end
end
macro foo2(runnertypename, ex)
rt = eval(runnertypename) # But what if Runner type not defined in global
scope? Risky!?
quote
local r = $(esc(runnertypename))()
$(run_code(rt, :r, esc(ex)))
end
end
a = 1
@foo2 Runner begin
a += 1
end
@show(a);
This works as intended and gives a lot of power for people to write their
own Runners but feels a bit inelegant and error prone. If there is a more
idiomatic way please share.
/Robert
Den lördag 13 februari 2016 kl. 12:16:43 UTC+1 skrev Robert Feldt:
>
> 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!
>