构建你的第一个宏

为了给写宏一个开始,我们展示如何实现之前提到的 myDebug 宏。 首先要构建一个宏使用的示例,接着打印实参。这可以看出一个正确的实参是什么样子。

  1. import macros
  2.  
  3. macro myAssert(arg: untyped): untyped =
  4. echo arg.treeRepr
  5.  
  6. let a = 1
  7. let b = 2
  8.  
  9. myAssert(a != b)
  1. Infix
  2. Ident "!="
  3. Ident "a"
  4. Ident "b"

从输出可以看出实参信息是一个中缀操作符(节点类型是"Infix"), 两个操作数在索引1和2的位置。用这个信息可以写真正的宏。

  1. import macros
  2.  
  3. macro myAssert(arg: untyped): untyped =
  4. # 所有节点类型标识符用前缀 "nnk"
  5. arg.expectKind nnkInfix
  6. arg.expectLen 3
  7. # 操作符作字符串字面值
  8. let op = newLit(" " & arg[0].repr & " ")
  9. let lhs = arg[1]
  10. let rhs = arg[2]
  11.  
  12. result = quote do:
  13. if not `arg`:
  14. raise newException(AssertionError,$`lhs` & `op` & $`rhs`)
  15.  
  16. let a = 1
  17. let b = 2
  18.  
  19. myAssert(a != b)
  20. myAssert(a == b)

这是即将生成的代码。 调试生成的宏可以在宏最后一行用 echo result.repr 语句。它也是用于获取此输出的语句。

  1. if not (a != b):
  2. raise newException(AssertionError, $a & " != " & $b)