So I’ve been getting really confused with the interaction between nested macro expansion and module scoping…
In my module MyModel
I have a set of macros with which I implement a simple DSL. Things work fine in this simpler case:
julia> using MyModel
julia> @macroexpand @habitat(MyModel.@landcover() == MyModel.water)
quote
function (pos, model)
if MyModel.landcover(pos, model) == MyModel.water
return true
else
return false
end
end
end
But in this more complex case, the function that @habitat
generates suddenly has (MyModel.pos, MyModel.model)
as function arguments, instead of just (pos, model)
:
julia> @macroexpand MyModel.@initialise!(@habitat(MyModel.@landcover() == MyModel.water), pairs=true)
:(initialise! = MyModel.initpopulation(begin
function (MyModel.pos, MyModel.model)
if MyModel.landcover(MyModel.pos, MyModel.model) == (MyModel.MyModel).water
return true
else
return false
end
end
end, $(Expr(:(=), Symbol("#527#pairs"), true))))
This throws an error if executed (LoadError: syntax: "MyModel.pos" is not a valid function argument name
).
The definitions of the relevant macros are (note that MyModel
exports @habitat
, but not the other two):
macro initialise!(habitatdescriptor, kwargs...)
:($(esc(:initialise!)) = initpopulation($habitatdescriptor, $(kwargs...)))
end
macro habitat(body)
quote
function($(esc(:pos)), $(esc(:model)))
if $(esc(body))
return true
else
return false
end
end
end
end
macro landcover()
:(landcover($(esc(:pos)), $(esc(:model))))
end
This is just one example of several similar problems I’m running into. So any help you can offer on this example would be great, but if you know of any good explanations on how macro expansion works in other module contexts, that would also be much appreciated!