# Escaping of nested blocks

**URL:** <https://discourse.julialang.org/t/escaping-of-nested-blocks/1157>\
**Category:** General Usage\
**Created:** [December 26, 2016, 8:42pm UTC](https://discourse.julialang.org/t/escaping-of-nested-blocks/1157 "2016-12-26T20:42:43Z")\
**Posts on this page:** 10\
**Page:** 1

<div class="post-metadata">

**Author:** ![TomasPuverle](https://avatars.discourse-cdn.com/v4/letter/t/ecccb3/32.png) [@TomasPuverle](https://discourse.julialang.org/u/TomasPuverle)\
**Post date:** [December 26, 2016, 8:42pm UTC](https://discourse.julialang.org/t/escaping-of-nested-blocks/1157/1 "2016-12-26T20:42:43Z")

</div>

Hi,

I am trying to learn to work with macros and ASTs, but am running into a bit of confusion regarding escaping. I haven’t found a lot of documentation regarding this, but if there is an authorative source, I would appreciate any pointers.

I wrote some example code which looks similar to this:

```julia
function op_helper(ee::Expr)
...
end

macro op(ee::Expr)
   $(op_helper(ee))
end

```

Inside of `op_helper`, I recursively walk the AST and do some very simple transformations (I am effectively trying to just return identity) on the expressions.

I am running into an interesting conundrum, which is challenging my understanding of `esc` in recursive contexts.

Consider the following test function:

```julia
function test(a)
    x = @op a + 1 #1
    @op y = a + 2 #2

    @op begin #3
         z = a + 3 #4
    end
end

```

I am finding the following:

1. is straightforward, and my code simply recursively traverses the AST, only escaping

```julia
# ...
if typeof(ee) == Symbol 
   esc(ee)
elseif #...

```

1. Seems only a little bit more work is required (note for simplicity, I’m not recursing on the LHS)

```julia
if typeof(ee) == Expr && ee.head == :(=)
    esc(:($(ee.args[1]) = $(op_helper(ee.args[2])))
elseif #...

```

1. It is this case which is intriguing.

```julia
if typeof(ee) == Expr && ee.head == :block
    parts = [op_helper(elem) for elem in ee.args]
    Expr(:block, parts...) #5
elseif #...

```

It appears that for this to work, I actually need to write `esc(Expr(:block, parts...))` in #5; however, this then causes problems with #4, which now doesn’t want to be escaped, unlike the recursive code path for #2.

Is what I’m describing correct, or am I missing something?

Thank you,

Tom

---

<div class="post-metadata">

**Author:** ![yuyichao](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/yuyichao/32/20_2.png) [@yuyichao](https://discourse.julialang.org/u/yuyichao)\
**Post date:** [December 26, 2016, 9:11pm UTC](https://discourse.julialang.org/t/escaping-of-nested-blocks/1157/2 "2016-12-26T21:11:42Z")

</div>

> [@TomasPuverle](#):
>
> $(op\_helper(ee))

This looks wrong. I assume you mean `op_helper(ee)`.

> [@TomasPuverle](#):
>
> I’m not recursing on the LHS

You must escape the LHS.

> [@TomasPuverle](#):
>
> It appears that for this to work, I actually need to write esc(Expr(:block, parts…)) in #5

What do you mean by not working?

---

<div class="post-metadata">

**Author:** ![TomasPuverle](https://avatars.discourse-cdn.com/v4/letter/t/ecccb3/32.png) [@TomasPuverle](https://discourse.julialang.org/u/TomasPuverle)\
**Post date:** [December 26, 2016, 11:26pm UTC](https://discourse.julialang.org/t/escaping-of-nested-blocks/1157/3 "2016-12-26T23:26:36Z")

</div>

> [@yuyichao](#):
>
> This looks wrong. I assume you mean op\_helper(ee).

Yes. Typed the wrong thing, sorry.

> [@yuyichao](#):
>
> You must escape the LHS.

I think it is escaped; I just said I didn’t recurse.

> [@yuyichao](#):
>
> What do you mean by not working?

The compiler complains:

ERROR: LoadError: syntax: unhandled expr

Anyway, I think I’ve figured it out. I just generate the AST using op\_helper(), and then just `esc`’ape the resulting expression in `op`.

Thanks for the help,

Tom

---

<div class="post-metadata">

**Author:** ![yuyichao](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/yuyichao/32/20_2.png) [@yuyichao](https://discourse.julialang.org/u/yuyichao)\
**Post date:** [December 27, 2016, 12:44am UTC](https://discourse.julialang.org/t/escaping-of-nested-blocks/1157/4 "2016-12-27T00:44:46Z")

</div>

> [@TomasPuverle](#):
>
> I think it is escaped; I just said I didn’t recurse.

At least the code you paste didn’t.

> [@TomasPuverle](#):
>
> I just generate the AST using op\_helper(), and then just esc’ape the resulting expression in op.

Do note that this turns off macro hygiene and you can have accidental reference to user local variable that’s not intended.

---

<div class="post-metadata">

**Author:** ![TomasPuverle](https://avatars.discourse-cdn.com/v4/letter/t/ecccb3/32.png) [@TomasPuverle](https://discourse.julialang.org/u/TomasPuverle)\
**Post date:** [December 27, 2016, 1:36am UTC](https://discourse.julialang.org/t/escaping-of-nested-blocks/1157/5 "2016-12-27T01:36:27Z")

</div>

Hi Yuyichao,

Thank you for your time. I was wondering if you could clarify your comment for me, because I’m afraid I may not be understanding something correctly.

> [@yuyichao](#):
>
> At least the code you paste didn’t.

I wrote

```julia
if typeof(ee) == Expr && ee.head == :(=)
    esc(:($(ee.args[1]) = $(op_helper(ee.args[2])))
elseif #...

```

Say, in the case of #2, I would have expected this to expand to something like

esc(:(y = a + 2))

You assert that the code is not escaped. Would you be able to explain? I’ve copied the entire example code below for reference:

```julia
function op_helper(ee::Expr)
    if typeof(ee) == Symbol 
       esc(ee)
    elseif typeof(ee) == Expr && ee.head == :(=)
        esc(:($(ee.args[1]) = $(op_helper(ee.args[2]))))
    elseif typeof(ee) == Expr && ee.head == :block
        parts = [op_helper(elem) for elem in ee.args]
        Expr(:block, parts...) #5
    elseif typeof(ee) == Expr && ee.head == :call
        ee
    elseif ee.head == :line
        # Nothing
    else
        error("Not handled", ee)
    end
end

macro op(ee::Expr)
    res = op_helper(ee)
    println(res)
    res
end

function test(a)
    x = @op a + 1 #1
    @op y = a + 2 #2

    @op begin #3
         z = a + 3 #4
    end

    return (x, y, z)
end

println(test(3))

```

> [@yuyichao](#):
>
> Do note that this turns off macro hygiene and you can have accidental reference to user local variable that’s not intended.

Yes, that was partially my worry. It appears that my new code is able to avoid it to some degree, at least.

Thanks,

Tom

---

<div class="post-metadata">

**Author:** ![yuyichao](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/yuyichao/32/20_2.png) [@yuyichao](https://discourse.julialang.org/u/yuyichao)\
**Post date:** [December 27, 2016, 4:09am UTC](https://discourse.julialang.org/t/escaping-of-nested-blocks/1157/6 "2016-12-27T04:09:50Z")

</div>

> [@TomasPuverle](#):
>
> You assert that the code is not escaped. Would you be able to explain?

I missed the `esc` around the whole thing. That does escape the LHS but is wrong. In general, you must escape each piece of user input once and exactly once. A slightly better implementation would be

```julia
julia> function op_helper(ee::ANY)
           if isa(ee, Symbol) 
               esc(ee)
           elseif isa(ee, Expr) && ee.head == :(=)
               :($(esc(ee.args[1])) = $(op_helper(ee.args[2])))
           elseif isa(ee, Expr) && ee.head == :block
               parts = [op_helper(elem) for elem in ee.args]
               Expr(:block, parts...) #5
           elseif isa(ee, Expr) && ee.head == :call
               esc(ee)
           elseif isa(ee, Expr) && ee.head == :line
               esc(ee)
           else
               error("Not handled", ee)
           end
       end
op_helper (generic function with 1 method)

julia> macro op(ee::Expr)
           res = op_helper(ee)
           println(res)
           res
       end
@op (macro with 1 method)

julia> function test(a)
           x = @op a + 1 #1
           @op y = a + 2 #2

           @op begin #3
                z = a + 3 #4
           end

           return (x, y, z)
       end
$(Expr(:escape, :(a + 1)))
$(Expr(:escape, :y)) = $(Expr(:escape, :(a + 2)))
begin 
    $(Expr(:escape, :( # REPL[3], line 6:)))
    $(Expr(:escape, :z)) = $(Expr(:escape, :(a + 3)))
end
test (generic function with 1 method)

julia> println(test(3))
(4,5,6)

```

Note that handling `Symbol`s but not other literals is generally problematic. (although actually neither is handled in either version)

---

<div class="post-metadata">

**Author:** ![TomasPuverle](https://avatars.discourse-cdn.com/v4/letter/t/ecccb3/32.png) [@TomasPuverle](https://discourse.julialang.org/u/TomasPuverle)\
**Post date:** [December 28, 2016, 2:11am UTC](https://discourse.julialang.org/t/escaping-of-nested-blocks/1157/7 "2016-12-28T02:11:44Z")

</div>

Hi yuyichao,

Thank you very much for the example code; that helped a lot. I actually had something almost identical to what you wrote to begin with, but couldn’t get it to work. The main difference was my initial attempt of the assignment, which I couldn’t get working

```julia
:(esc($(ee.args[1])) = $(op_helper(ee.args[2])))

```

versus your version

```julia
:($(esc(ee.args[1])) = $(op_helper(ee.args[2])))

```

This was actually the reason why I wrapped the whole expression in `esc`, instead of just the destination.

Let me see if I can my code going now.

Thank you for your help, I really appreciate it.

Kind regards,

Tom

---

<div class="post-metadata">

**Author:** ![yuyichao](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/yuyichao/32/20_2.png) [@yuyichao](https://discourse.julialang.org/u/yuyichao)\
**Post date:** [December 28, 2016, 2:21am UTC](https://discourse.julialang.org/t/escaping-of-nested-blocks/1157/8 "2016-12-28T02:21:06Z")

</div>

> [@TomasPuverle](#):
>
> ```julia
> :(esc($(ee.args[1])) = $(op_helper(ee.args[2])))
> 
> ```
> 
> versus your version
> 
> ```julia
> :($(esc(ee.args[1])) = $(op_helper(ee.args[2])))
> 
> ```

I wouldn’t disagree that expression interpolation can easily give you multiple levels of parenthesis. At least you can always assign it to a variable (e.g. `earg1 = esc(ee.args[1])`) and in this sense it’s not too different from an expression with nested function calls.

---

<div class="post-metadata">

**Author:** ![TomasPuverle](https://avatars.discourse-cdn.com/v4/letter/t/ecccb3/32.png) [@TomasPuverle](https://discourse.julialang.org/u/TomasPuverle)\
**Post date:** [December 28, 2016, 3:28am UTC](https://discourse.julialang.org/t/escaping-of-nested-blocks/1157/9 "2016-12-28T03:28:07Z")

</div>

Hi yuyichao,

I wasn’t really referring the parenthesis, but more to the

`$(esc(<expr>))` vs `esc($(<expr>))`.

I can’t say I fully see the difference (other than one working and the other not).

Thanks,

Tom

---

<div class="post-metadata">

**Author:** ![yuyichao](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/yuyichao/32/20_2.png) [@yuyichao](https://discourse.julialang.org/u/yuyichao)\
**Post date:** [December 28, 2016, 6:01am UTC](https://discourse.julialang.org/t/escaping-of-nested-blocks/1157/10 "2016-12-28T06:01:59Z")

</div>

> [@TomasPuverle](#):
>
> (esc(&lt;expr&gt;)) vs esc((\<expr\>)).

I know. I’m just saying that the many level of parentheses makes it harder to tell the difference.

`$` is the interpolation so in `$(esc(<expr>))` it interpolated an escaped expression (what you want) and in `esc($(<expr>))` it interpolate the original expression into a function call of `esc`.
