1
votes

All these following lines of code are Julia expressions:

x = 10
1 + 1
println("hi")

if you want to pass an expression to a macro, it works like this. Macro foo just returns the given expression, which will be executed:

macro foo(ex)
  return ex
end

@foo println("yes") # prints yes

x = @foo 1+1
println(x) # prints 2

If you want to convert a string into an expression, you can use Meta.parse():

string = "1+1"
expr = Meta.parse(string)
x = @foo expr
println(x) # prints 1 + 1

But, obviously, the macro treats expr as a symbol. What am i getting wrong here?

Thanks in advance!

1

1 Answers

3
votes

Macro hygiene is important "macros must ensure that the variables they introduce in their returned expressions do not accidentally clash with existing variables in the surrounding code they expand into." There is a section in the docs. It is easiest just to show a simple case:

macro foo(x)
    return :($x)
end

When you enter an ordinary expression in the REPL, it is evaluated immediately. To suppress that evaluation, surround the expression with :( ).

julia> 1 + 1
2
julia> :(1 + 1)
:(1 + 1)
# note this is the same result as you get using Meta.parse
julia> Meta.parse("1 + 1")
:(1 + 1)

So, Meta.parse will convert an appropriate string to an expression. And if you eval the result, the expression will be evaluated. Note that printing a simple expression removes the outer :( )

julia> expr = Meta.parse("1 + 1")
:(1 + 1)
julia> print(expr)
1 + 1
julia> result = eval(expr)
2

Usually, macros are used to manipulate things before the usual evaluation of expressions; they are syntax transformations, mostly. Macros are performed before other source code is compiled/evaluated/executed.

Rather than seeking a macro that evaluates a string as if it were typed directly into the REPL (without quotes), use this function instead.

evalstr(x::AbstractString) = eval(Meta.parse(x))

While I do not recommend this next macro, it is good to know the technique. A macro named <name>_str is used like this <name>"<string contents>" :

julia> macro eval_str(x)
          :(eval(Meta.parse($x)))
      end

julia> eval"1 + 1"
2

(p.s. do not reuse Base function names as variable names, use str not string)

Please let me know if there is something I have not addressed.