在 nim 中,如果我正在编写宏,如何从参数显式构造名称。具体来说,在 nim 手册中(参见here),我们有以下“标识符构造”的示例
template typedef(name: untyped, typ: typedesc) =
type
`T name`* {.inject.} = typ
`P name`* {.inject.} = ref `T name`
typedef(myint, int)
var x: PMyInt
如果我希望 typedef 成为宏而不是模板,我怎样才能完成同样的事情?
任何模板都可以简单地成为宏。这里:
template typedef(name: untyped, typ: typedesc) =
type
`T name`* {.inject.} = typ
`P name`* {.inject.} = ref `T name`
typedef(myint, int)
var x: PMyInt
import macros
import std/genasts
macro typedef2(name:untyped, typ:typedesc) =
result = genast(name,typ):
type
`T name`* {.inject.} = typ
`P name`* {.inject.} = ref `T name`
typedef2(yourint, int)
var y: PYourInt
x = new int
x[] = 3
y = x
assert (y[] == 3)
但这没有帮助。
如果您发现自己需要从模板升级到宏观领域,那是因为您需要直接操作 ast。所以你要做的第一件事就是弄清楚你想要的输出的 ast 是多少:
import macros
dumpTree: # dumpAstGen is also helpful
type
TMytype* = int
PMytype* = ref TMytype
TypeSection
TypeDef
Postfix
Ident "*"
Ident "Tmyname"
Empty
Ident "int"
TypeDef
Postfix
Ident "*"
Ident "Pmyname"
Empty
RefTy
Ident "Tmyname"
dumpAstGen
将输出您需要放入宏中的确切代码,但视觉上不太清晰,所以我使用 dumpTree
。
现在我们创建一个宏来构造精确的 as:
macro typedef3(name: untyped, typ: typedesc) =
result = nnkTypeSection.newNimNode()
result.add nnkTypeDef.newTree(
nnkPostfix.newTree(
ident"*",
ident "T" & name.strVal),
newEmptyNode(),
typ)
result.add nnkTypeDef.newTree(
nnkPostfix.newTree(
ident"*",
ident "P" & name.strVal),
newEmptyNode(),
nnkRefTy.newTree(typ))
#echo result.treerepr
typedef3(yourtype, float)
最后我们回显我们刚刚制作的 ast,以便我们可以将其与我们的预期进行比较
这里是
echo result.repr
只是为了清楚起见:
type
Tyourtype* = float
Pyourtype* = ref float