I’m trying to build a toy test library as an exercise in using macros. I’ve managed to get most things I tried doing to work eventually, but I’ve hit a brick wall with this one.
Basically I want to be able to write this code (I’ve tried to strip it down to be as simple and generic as possible):
outer do
inner(1)
inner(2)
end
… and have it expand to:
def my_method(arg) do
IO.puts(arg + 1)
IO.puts(arg + 2)
end
Here are the basic macros I have:
defmacro outer(do: body) do
quote do
def my_method(arg) do
unquote(body)
end
end
end
defmacro inner(n) do
quote do
IO.puts(arg + unquote(n))
end
end
This fails to compile, with the error undefined function arg/0. I’m assuming this is some kind of hygiene issue, but none of the things I’ve tried have resulted in being able to generate code in the function body separately, while still being able to access the function’s arguments.
I’m fairly sure there’s a simple solution to this – can anyone point me in the right direction ?
You can use var!/2 to access variables from the outer scope.
But please keep in mind, that you then make those variables part of the contract, in my opinion, its easier to understand and document to just take that extra argument in the macro.
inner/1 is used by the code that calls the macros, inside the body of the call to outer/1:
outer do
inner(1)
inner(2)
end
I want outer/1 to define a function that takes an argument, then multiple calls to inner/1 to generate code inside the body of that function, that use the value of the argument.
I realise that hiding the argument may not be a great idea, but in the real code where I’m trying to do the same thing it will remove a lot of boilerplate (and as I said it’s only really an experiment at this stage).