我想编写宏,它必须根据命名元组或对象的字段执行一些逻辑。我认为这最好通过将元组/对象作为typed
参数传递给宏来实现。
问题是,我typed
一般如何遍历参数的字段?我基本上是在寻找forfieldPairs
宏的等效项,即,与其采取具体的元组/对象,还不如对其进行操作,NimNode
并同样返回字段名称/类型(以进一步生成AST)。
我找到了该问题的解决方案,它似乎工作正常,但我不确定是否有更好的替代方案。该解决方案是基于使用getTypeImpl
的typed
参数。要了解它是如何工作的,查看t.getTypeImpl.treeRepr
简单元组和对象的输出会有所帮助。
元组:例如类型 impl AST(x: 0, y: 1, name: "")
看起来像这样:
TupleTy
IdentDefs
Sym "x"
Sym "int"
Empty
IdentDefs
Sym "y"
Sym "int"
Empty
IdentDefs
Sym "name"
Sym "string"
Empty
注:typeKind
的getTypeImpl
ISntyTuple
Object:具有相同结构的对象的类型 impl AST 将是:
ObjectTy
Empty
Empty
RecList
IdentDefs
Sym "x"
Sym "int"
Empty
IdentDefs
Sym "y"
Sym "int"
Empty
IdentDefs
Sym "name"
Sym "string"
Empty
注:typeKind
的getTypeImpl
ISntyObject
这表明我们正在寻找的信息在IdentDefs
. 我们只需要确保适当地处理元组和对象:对于元组,IdentDefs
是的直接子级NimNode
,而对于对象,IdentDefs
将存储在索引2的子级中(索引0的子级包含编译指示信息,索引中的子级1 是关于父母的信息)。
总体而言,宏可能看起来像(添加了一些调试输出以进行说明):
macro iterateFields*(t: typed): untyped =
echo "--------------------------------"
# check type of t
var tTypeImpl = t.getTypeImpl
echo tTypeImpl.len
echo tTypeImpl.kind
echo tTypeImpl.typeKind
echo tTypeImpl.treeRepr
case tTypeImpl.typeKind:
of ntyTuple:
# For a tuple the IdentDefs are top level, no need to descent
discard
of ntyObject:
# For an object we have to descent to the nnkRecList
tTypeImpl = tTypeImpl[2]
else:
error "Not a tuple or object"
# iterate over fields
for child in tTypeImpl.children:
if child.kind == nnkIdentDefs:
let field = child[0] # first child of IdentDef is a Sym corresponding to field name
let ftype = child[1] # second child is type
echo "Iterating field: " & $field & " -> " & $ftype
else:
echo "Unexpected kind: " & child.kind.repr
# Note that this can happen for an object with a case
# fields, which would give a child of type nnkRecCase.
# How to handle them depends on the use case.
# small test
type
TestObj = object
x: int
y: int
name: string
let t = (x: 0, y: 1, name: "")
let o = TestObj(x: 0, y: 1, name: "")
iterateFields(t)
iterateFields(o)
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句