Redundant blocks: flatten an iterator?

question
macros
metaprogramming

#1

Hi,

There’s a minor metaprogramming annoyance I’m working through, hoping someone can help me understand the best idiomatic Julia (“Julianic”?) way to do this.

I’m seeing a lot of redundant blocks coming from the MetaTools “postwalk/@capture” pattern. This generally happens when replacing one :block element with several. For a silly example, suppose we wanted to rewrite every v = foo(k) as

v = 3k
v += 2

MacroTools makes this pretty easy:

using MacroTools: @capture, postwalk

rewrite(expr) = postwalk(expr) do x
   if @capture(x, v_ = foo(k_))
      @q begin
         $v = 3*$k
         $v += 2
      end
   else x
   end
end

Ok great, let’s try it out:

julia> myExpr = @q begin
          a = 0
          b = foo(a)
       end
quote
    a = 0
    b = foo(a)
end

julia> rewrite(myExpr)
quote
    a = 0
    begin
        b = 3a
        b += 2
    end
end

That inner begin block is redundant; the code is the exquivalent to

quote
    a = 0
    b = 3a
    b += 2
end

There’s no harm in the inner block other than aesthetic, but it would still be nice to get rid of it. MacroTools has an unblock function, but this seem to only solve the simpler problem of a block containing only a single sub-block. More generally, it seems we could flatten any element of a block that is itself just a block.

This morning the “flattening” idea became a sort of side-quest - we ought to be able to just treat this an an iterator. But this seems to involve a lot lower-level code than I would have expected, especially compared to Python’s yield keyword. I would think there’d be a similar approach here, or maybe some existing combinator I could build on.

Any ideas?