# Is there a trick to input an \`Expr\` into a macro?

**URL:** <https://discourse.julialang.org/t/is-there-a-trick-to-input-an-expr-into-a-macro/82383>\
**Category:** General Usage\
**Tags:** macros\
**Created:** [June 7, 2022, 6:16pm UTC](https://discourse.julialang.org/t/is-there-a-trick-to-input-an-expr-into-a-macro/82383 "2022-06-07T18:16:26Z")\
**Posts on this page:** 8\
**Page:** 1

<div class="post-metadata">

**Author:** ![Benny](https://avatars.discourse-cdn.com/v4/letter/b/49beb7/32.png) [@Benny](https://discourse.julialang.org/u/Benny)\
**Post date:** [June 7, 2022, 6:16pm UTC](https://discourse.julialang.org/t/is-there-a-trick-to-input-an-expr-into-a-macro/82383/1 "2022-06-07T18:16:26Z")

</div>

AFAIK a macro only works like a “tag” on source code that is parsed to input expressions for the macro. Is there a way to make a macro work on an `Expr` instance?

I’m aware that this might be a problem because macros are documented to only work on expressions, literals, and symbols, but an `Expr` instance can contain other types’ instances. I’m also aware that a method can take an `Expr`, and the typical way to accomplish what I want is such a method and a macro that uses that method. It’s just that sometimes a macro’s internal `Expr`-method isn’t part of the API or doesn’t exist.

---

<div class="post-metadata">

**Author:** ![Sukera](https://avatars.discourse-cdn.com/v4/letter/s/ce7236/32.png) [@Sukera](https://discourse.julialang.org/u/Sukera)\
**Post date:** [June 7, 2022, 6:29pm UTC](https://discourse.julialang.org/t/is-there-a-trick-to-input-an-expr-into-a-macro/82383/2 "2022-06-07T18:29:49Z")

</div>

> [@Benny](#):
>
> AFAIK a macro only works like a “tag” on source code that is parsed to input expressions for the macro. Is there a way to make a macro work on an `Expr` instance?

That’s not what a macro is, no. A macro is given a parsed expression (of type `Expr`) to transform into another `Expr`, so they already work on `Expr` objects/instances.

> [@Benny](#):
>
> but an `Expr` instance can contain other types’ instances.

Not for arbitrary types, no - only literals the parser knows about, like literal 64 bit integers, floating point values, strings, symbols, function definitions/calls (which are different kinds of `Expr` literals - the _values_ these end up as don’t exist at macro expansion time).

> [@Benny](#):
>
> and the typical way to accomplish what I want is such a method and a macro that calls that method. It’s just that sometimes a macro’s internal `Expr` method isn’t part of the API or doesn’t exist.

What do you want to accomplish? Using functions to build more complicated `Expr`s in a macro is usually just a design choice by the macro author - it’s never required to do that.

---

<div class="post-metadata">

**Author:** ![Benny](https://avatars.discourse-cdn.com/v4/letter/b/49beb7/32.png) [@Benny](https://discourse.julialang.org/u/Benny)\
**Post date:** [June 7, 2022, 10:44pm UTC](https://discourse.julialang.org/t/is-there-a-trick-to-input-an-expr-into-a-macro/82383/3 "2022-06-07T22:44:57Z")

</div>

My understanding is that an `Expr` can contain any types, just not when parsed from source. For example, I can interpolate a custom type’s instance into an `Expr`:

```julia
julia> mutable struct Blah
         x::Int
         y::Float64
       end

julia> :($(Blah(1, 1.1)) - 1.5) |> dump
Expr
  head: Symbol call
  args: Array{Any}((3,))
    1: Symbol -
    2: Blah
      x: Int64 1
      y: Float64 1.1
    3: Float64 1.5

```

I’m talking about these “runtime” `Expr` instances. For example, `@eval 1+3` works, but there’s no way to input `:(1+3)` to the macro, you need the method version `eval(:(1+3))`. The macro only seems to work on expressions that are parsed from the source code “tagged” by the macro call.

---

<div class="post-metadata">

**Author:** ![johnmyleswhite](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/johnmyleswhite/32/31_2.png) [@johnmyleswhite](https://discourse.julialang.org/u/johnmyleswhite)\
**Post date:** [June 7, 2022, 11:17pm UTC](https://discourse.julialang.org/t/is-there-a-trick-to-input-an-expr-into-a-macro/82383/4 "2022-06-07T23:17:04Z")

</div>

Are you sure you don’t just want a function that takes in an Expr?

---

<div class="post-metadata">

**Author:** ![Mason](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mason/32/2423_2.png) [@Mason](https://discourse.julialang.org/u/Mason)\
**Post date:** [June 7, 2022, 11:51pm UTC](https://discourse.julialang.org/t/is-there-a-trick-to-input-an-expr-into-a-macro/82383/5 "2022-06-07T23:51:12Z")

</div>

Given a macro `@something` you can get the actual macro object by writing `var"@something"` and from that you can inspect it’s methods and call it. For example:

```julia
julia> macro do_nothing(ex)
           ex
       end
@do_nothing (macro with 1 method)

julia> methods(var"@do_nothing")
# 1 method for macro "@do_nothing":
[1] var"@do_nothing"( __source__ ::LineNumberNode, __module__ ::Module, ex) in Main at REPL[13]:1

```

This says that `var"@do_nothing"` has a method that takes in `LineNumberNode` and `Module` telling you where the macro was invoked, and an expression that it operates on. If you provide this stuff, you can run the macro on a runtime `Expr` and get out an `Expr`. For example,

```julia
julia> var"@do_nothing"(LineNumberNode(@ __LINE__ (), @ __FILE__ ()), @ __MODULE__ (), :(x + 1))
:(x + 1)

```

---

<div class="post-metadata">

**Author:** ![Benny](https://avatars.discourse-cdn.com/v4/letter/b/49beb7/32.png) [@Benny](https://discourse.julialang.org/u/Benny)\
**Post date:** [June 8, 2022, 1:55am UTC](https://discourse.julialang.org/t/is-there-a-trick-to-input-an-expr-into-a-macro/82383/6 "2022-06-08T01:55:23Z")

</div>

> [@johnmyleswhite](#):
>
> Are you sure you don’t just want a function that takes in an Expr?

I absolutely want that, but sometimes a cool macro doesn’t have a function version, and I’m not cool enough to write one.

> [@Mason](#):
>
> This says that `var"@do_nothing"` has a method that takes in `LineNumberNode` and `Module`

“Wait it’s all methods?” “Always has been.”

Also I’ve been messing around with `macroexpand` a bit, found another way to do it:

```julia
julia> y = 2
2

julia> x = :(y+1)
:(y + 1)

julia> macro minus1(ex) return :($ex - 1) end
@minus1 (macro with 1 method)

julia> @macroexpand @minus1 y+1 # ideal output Expr
:((Main.y + 1) - 1)

julia> @minus1 y+1 # ideal eval
2

julia> @macroexpand @minus1 $x # cannot interpolate in source, would error
:($(Expr(:$, :(Main.x))) - 1)

julia> macroexpand(Main, :(@minus1 $x)) # interpolate argument, then expand
:((Main.y + 1) - 1)

julia> Core.eval(Main, :(@minus1 $x))
2

```

---

<div class="post-metadata">

**Author:** ![Mason](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mason/32/2423_2.png) [@Mason](https://discourse.julialang.org/u/Mason)\
**Post date:** [June 8, 2022, 2:06am UTC](https://discourse.julialang.org/t/is-there-a-trick-to-input-an-expr-into-a-macro/82383/7 "2022-06-08T02:06:10Z")

</div>

If you’re going to use `macroexpand`, I’d recommend using `@macroexpand1 ex` / `macroexpand(module, ex; recursive=false)`, because that way you won’t accidentally end up expanding any inner macros buried in `ex`.

---

<div class="post-metadata">

**Author:** ![Benny](https://avatars.discourse-cdn.com/v4/letter/b/49beb7/32.png) [@Benny](https://discourse.julialang.org/u/Benny)\
**Post date:** [June 8, 2022, 2:27am UTC](https://discourse.julialang.org/t/is-there-a-trick-to-input-an-expr-into-a-macro/82383/8 "2022-06-08T02:27:08Z")

</div>

In what sort of situations would it be useful to only expand the outermost macro call? Documentation for `macroexpand1` and `macroexpand` doesn’t give any tips.
