macros at parse and runtime

metaprogramming

#1

I was recently the macro functionality, and specifically what happens at parse and at runtime:

macro parse_run(arg)
    println("at Parse time, The argument is: ", arg)
    return :(println("at Runtime, The argument is: ", $arg))
end

function test_macro(name::String)
    @parse_run name
end

test_macro("Amjad")

I was expecting test_macro to print : “at Runtime, The argument is: Amjad” but instead got this error:

at Parse time, The argument is: name
ERROR: LoadError: UndefVarError: name not defined
Stacktrace:
 [1] test_macro(::String) at C:\Users\User\Desktop\Tfach\LSP tests\test.jl:7
 [2] include_from_node1(::String) at .\loading.jl:576
 [3] include(::String) at .\sysimg.jl:14
 [4] process_options(::Base.JLOptions) at .\client.jl:305
 [5] _start() at .\client.jl:371
while loading C:\Users\User\Desktop\Tfach\LSP tests\test.jl, in expression starting on line 10

why doe’s this happen ? and why doesn’t this happen with the @assert name == "John" ? thanks in advance, and thanks for the revolution you made :clap:


#2
return :(println("at Runtime, The argument is: ", $arg))

arg == :name, if you splice that into your expression, it will get turned into something like ##1name, to make it hygienic (so you dont refer to local variables by accidant). If you want to make it refer to an actually variable in the calling scope of the macro use esc:

macro parse_run(arg)
    println("at Parse time, The argument is: ", arg)
    return :(println("at Runtime, The argument is: ", $(esc(arg))))
end
julia> function test_macro(name::String)
           @parse_run name
       end
at Parse time, The argument is: name

julia> test_macro("Amjad")
at Runtime, The argument is: Amjad

#3

Thanks for the help, I was so close from this but I tried esc($arg)) instead of $(esc(arg)). so esc actually returns a string here ?


#4

In this case it’ll be a global reference instead.

No. The runtime value cannot be known at compile time (which sounds silly but is very important) so the return value of esc is still returns a variable reference (a expression) and not it’s runtime value (the string value).

esc returns something, the exact form is an implementation detail that’s no important here, so that the macro expansion code will make sure it reference the variable name in the caller (macro user) scope instead of the callee (macro writer) scope.

You can see what it returns by just printing it although it’ll only tell you what the implementation defined special expresion that has the property above. You can see the effect of it in the macro expander by checking @macroexpand @parse_run name for the two implementation.