I'm very new to macros and just recently started playing around with them when I discovered the following thing:
import macros
macro test(number: string) =
let procName = newIdentNode("problem" & $number)
quote do:
proc `procName`() = echo "test: " & `number`
test("1000")
problem1000() # works fine
for i in 0..100:
let numberName: string = $i
test(numberName)
if i == 50:
problem50() # doesn't compile
I can call problem1000() fine since I explicitly created it with the call to the macro. I thought that problem50() would be generated as well by the time that i == 50 is true, but apparently not? Why is this? Can't I use the procs that are created from the for loop?
try this:
import macros
macro genTuple(startI, endI : static[int]) : untyped =
result = nnkTupleConstr.newTree()
for i in startI..endI:
result.add newLit(i)
macro test(number: static[string]) =
let
procName = newIdentNode("problem" & number)
numberLit = newLit(number)
quote do:
proc `procName`() = echo "test: " & `numberLit`
for i in fields(genTuple(0,100)):
const
numberName = $i
test(numberName)
when i == 50:
problem50()
This should work. You can also pass in a macro.
You should do macro logic inside the macro
How about you test his code before questioning my logic. It compiles but problem 50 is never declared. Try this and the assert will fail.
template test(number) =
echo "Generating ", number
proc `problem number`() = echo "test: ", number
test(1000)
problem1000()
var
x = false
for i in 0..100:
test(i)
x = x or declared(problem50)
when declared(problem50):
if i == 50: problem50()
assert(x == true)
I've thought of a better solution that allows you to access the procs outside of the loop.
import macros
macro staticFor(i : untyped, startI, endI : static[int], body : untyped) : untyped =
result = newStmtList()
let
t = genSym(nskTemplate,"t")
result.add quote do:
template `t`(`i` : untyped) : untyped =
`body`
for i in startI..endI:
let
iLit = newLit(i)
result.add quote do:
`t`(`iLit`)
macro test(number: static[string]) =
let
procName = ident("problem" & number)
numberLit = newLit(number)
quote do:
proc `procName`() = echo "test: " & `numberLit`
staticFor(i,0,100):
const
numberName = $i
test(numberName)
when i == 50:
problem50()
problem1()
Aaah, so If I understand what Araq and others are saying here is that the for loop doesn't execute the way I thought at compile time? The static for loop looks cool! Thanks for the many responses and helppful playground links :)
I want to dive more into macros, but It's a very foreign concept to me and you have to think a bit differently from what I am used to with writing runtime code.
I want to dive more into macros, but It's a very foreign concept to me and you have to think a bit differently from what I am used to with writing runtime code.
You need to use macros for concrete use-cases, not by comparing it to runtime code. Macros are useful for:
You don't write a macro to construct 500 procs as then you still lack the code that actually calls these 500 different procs and nobody asked for these 500 different procs either...