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!
>

Reply via email to