Warning: Yet another post on hygienic macros.
I want to annotate the offsets of all interpolated values in a text string (storing the indices of the slices). I found it convenient to do this with a macro, but still struggle to escape the expressions properly.
MWE
Running the following works:
span(token, start, stop) = ("text" => token, "start" => start, "stop" => stop)
span(token, start) = span(token, start, start + length(token) - 1)
macro spans(text)
return quote
local start = 1
for arg in $(esc(text.args))
if !isa(arg, String)
arg = eval(arg)
println(span(arg, start)) # Might as well store these spans
end
start += length(arg)
end
$text
end
end
question = "the ultimate question of life, universe and everything";
answer = "42";
@spans "The answer to $question is $answer.";
Output
("text" => "the ultimate question of life, universe and everything", "start" => 15, "stop" => 68)
("text" => "42", "start" => 73, "stop" => 74)
"The answer to the ultimate question of life, universe and everything is 42."
Issue
After placing this into a separate module, say module Span
, I managed to replicate the example above by escape the expressions for the interpolated values correctly and immediately ruined that working version .
This is the code (identical to the above) that I’m currently trying to get to work:
module Spans
span(token, start, stop) = ("text" => token, "start" => start, "stop" => stop)
span(token, start) = span(token, start, start + length(token) - 1)
macro spans(text)
return quote
local start = 1
for arg in $(esc(text.args))
if !isa(arg, String)
arg = eval(arg)
println(span(arg, start)) # Might as well store these spans
end
start += length(arg)
end
$text
end
end
end # module
question = "the ultimate question of life, universe and everything";
answer = "42";
Spans.@spans "The answer to $question is $answer." # ERROR: LoadError: UndefVarError: question not defined
How do I evaluate question
and answer
within the if
block?