BindSym

The above debug macro relies on the fact that write, writeLine and stdout are declared in the system module and thus visible in the instantiating context. There is a way to use bound identifiers (aka symbols) instead of using unbound identifiers. The bindSym builtin can be used for that:

  1. import macros
  2. macro debug(n: varargs[typed]): untyped =
  3. result = newNimNode(nnkStmtList, n)
  4. for x in n:
  5. # we can bind symbols in scope via 'bindSym':
  6. add(result, newCall(bindSym"write", bindSym"stdout", toStrLit(x)))
  7. add(result, newCall(bindSym"write", bindSym"stdout", newStrLitNode(": ")))
  8. add(result, newCall(bindSym"writeLine", bindSym"stdout", x))
  9. var
  10. a: array[0..10, int]
  11. x = "some string"
  12. a[0] = 42
  13. a[1] = 45
  14. debug(a[0], a[1], x)

The macro call expands to:

  1. write(stdout, "a[0]")
  2. write(stdout, ": ")
  3. writeLine(stdout, a[0])
  4. write(stdout, "a[1]")
  5. write(stdout, ": ")
  6. writeLine(stdout, a[1])
  7. write(stdout, "x")
  8. write(stdout, ": ")
  9. writeLine(stdout, x)

However, the symbols write, writeLine and stdout are already bound and are not looked up again. As the example shows, bindSym does work with overloaded symbols implicitly.