Support type hierarchies in recordFields
This commit is contained in:
parent
cf837b3fb6
commit
4ffd3e1f59
|
@ -74,11 +74,17 @@ func isTuple*(t: NimNode): bool =
|
|||
macro isTuple*(T: type): untyped =
|
||||
newLit(isTuple(getType(T)[1]))
|
||||
|
||||
proc skipRef*(T: NimNode): NimNode =
|
||||
result = T
|
||||
if T.kind == nnkBracketExpr:
|
||||
if eqIdent(T[0], bindSym"ref"):
|
||||
result = T[1]
|
||||
|
||||
template readPragma*(field: FieldDescription, pragmaName: static string): NimNode =
|
||||
let p = findPragma(field.pragmas, bindSym(pragmaName))
|
||||
if p != nil and p.len == 2: p[1] else: p
|
||||
|
||||
proc recordFieldsAux(result: var seq[FieldDescription],
|
||||
proc collectFieldsFromRecList(result: var seq[FieldDescription],
|
||||
n: NimNode,
|
||||
parentCaseField: NimNode = nil,
|
||||
parentCaseBranch: NimNode = nil,
|
||||
|
@ -86,22 +92,22 @@ proc recordFieldsAux(result: var seq[FieldDescription],
|
|||
case n.kind
|
||||
of nnkRecList:
|
||||
for entry in n:
|
||||
recordFieldsAux result, entry,
|
||||
collectFieldsFromRecList result, entry,
|
||||
parentCaseField, parentCaseBranch
|
||||
of nnkRecWhen:
|
||||
for branch in n:
|
||||
case branch.kind:
|
||||
of nnkElifBranch:
|
||||
recordFieldsAux result, branch[1],
|
||||
collectFieldsFromRecList result, branch[1],
|
||||
parentCaseField, parentCaseBranch
|
||||
of nnkElse:
|
||||
recordFieldsAux result, branch[0],
|
||||
collectFieldsFromRecList result, branch[0],
|
||||
parentCaseField, parentCaseBranch
|
||||
else:
|
||||
doAssert false
|
||||
|
||||
of nnkRecCase:
|
||||
recordFieldsAux result, n[0],
|
||||
collectFieldsFromRecList result, n[0],
|
||||
parentCaseField,
|
||||
parentCaseBranch,
|
||||
isDiscriminator = true
|
||||
|
@ -110,9 +116,9 @@ proc recordFieldsAux(result: var seq[FieldDescription],
|
|||
let branch = n[i]
|
||||
case branch.kind
|
||||
of nnkOfBranch:
|
||||
recordFieldsAux result, branch[^1], n[0], branch
|
||||
collectFieldsFromRecList result, branch[^1], n[0], branch
|
||||
of nnkElse:
|
||||
recordFieldsAux result, branch[0], n[0], branch
|
||||
collectFieldsFromRecList result, branch[0], n[0], branch
|
||||
else:
|
||||
doAssert false
|
||||
|
||||
|
@ -150,19 +156,37 @@ proc recordFieldsAux(result: var seq[FieldDescription],
|
|||
else:
|
||||
doAssert false, "Unexpected nodes in recordFields:\n" & n.treeRepr
|
||||
|
||||
proc collectFieldsInHierarchy(result: var seq[FieldDescription],
|
||||
objectType: NimNode) =
|
||||
var objectType = objectType
|
||||
|
||||
if objectType.kind == nnkRefTy:
|
||||
objectType = objectType[0]
|
||||
|
||||
objectType.expectKind nnkObjectTy
|
||||
|
||||
var baseType = objectType[1]
|
||||
if baseType.kind != nnkEmpty:
|
||||
baseType.expectKind nnkOfInherit
|
||||
baseType = baseType[0]
|
||||
baseType.expectKind nnkSym
|
||||
baseType = getImpl(baseType)
|
||||
baseType.expectKind nnkTypeDef
|
||||
baseType = baseType[2]
|
||||
baseType.expectKind nnkObjectTy
|
||||
collectFieldsInHierarchy result, baseType
|
||||
|
||||
let recList = objectType[2]
|
||||
collectFieldsFromRecList result, recList
|
||||
|
||||
proc recordFields*(typeImpl: NimNode): seq[FieldDescription] =
|
||||
# TODO: This doesn't support inheritance yet
|
||||
if typeImpl.isTuple:
|
||||
for i in 1 ..< typeImpl.len:
|
||||
result.add FieldDescription(typ: typeImpl[i], name: ident("Field" & $(i - 1)))
|
||||
return
|
||||
|
||||
var objectType = typeImpl[2]
|
||||
if objectType.kind == nnkRefTy:
|
||||
objectType = objectType[0]
|
||||
|
||||
let recList = objectType[2]
|
||||
recordFieldsAux result, recList
|
||||
typeImpl.expectKind nnkTypeDef
|
||||
collectFieldsInHierarchy(result, typeImpl[2])
|
||||
|
||||
macro field*(obj: typed, fieldName: static string): untyped =
|
||||
newDotExpr(obj, ident fieldName)
|
||||
|
|
|
@ -16,6 +16,7 @@ import
|
|||
test_bitseqs,
|
||||
test_byteutils,
|
||||
test_endians2,
|
||||
test_macros,
|
||||
test_objects,
|
||||
test_ptrops,
|
||||
test_results,
|
||||
|
|
|
@ -0,0 +1,38 @@
|
|||
import
|
||||
../stew/shims/macros
|
||||
|
||||
type
|
||||
FieldKind = enum
|
||||
KindA
|
||||
KindB
|
||||
|
||||
BaseType = object of RootObj
|
||||
baseField: int
|
||||
case baseCaseField: FieldKind
|
||||
of KindA:
|
||||
baseA: int
|
||||
of KindB:
|
||||
discard
|
||||
|
||||
DerivedType = ref object of BaseType
|
||||
derivedField: int
|
||||
|
||||
macro getFieldsLists(T: type): untyped =
|
||||
result = newTree(nnkBracket)
|
||||
|
||||
var resolvedType = skipRef getType(T)[1]
|
||||
doAssert resolvedType.kind == nnkSym
|
||||
var objectType = getImpl(resolvedType)
|
||||
doAssert objectType.kind == nnkTypeDef
|
||||
|
||||
for f in recordFields(objectType):
|
||||
result.add newLit($f.name)
|
||||
|
||||
static:
|
||||
doAssert getFieldsLists(DerivedType) == [
|
||||
"baseField",
|
||||
"baseCaseField",
|
||||
"baseA",
|
||||
"derivedField"
|
||||
]
|
||||
|
Loading…
Reference in New Issue