mirror of
https://github.com/status-im/nim-stew.git
synced 2025-02-20 07:48:26 +00:00
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 =
|
macro isTuple*(T: type): untyped =
|
||||||
newLit(isTuple(getType(T)[1]))
|
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 =
|
template readPragma*(field: FieldDescription, pragmaName: static string): NimNode =
|
||||||
let p = findPragma(field.pragmas, bindSym(pragmaName))
|
let p = findPragma(field.pragmas, bindSym(pragmaName))
|
||||||
if p != nil and p.len == 2: p[1] else: p
|
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,
|
n: NimNode,
|
||||||
parentCaseField: NimNode = nil,
|
parentCaseField: NimNode = nil,
|
||||||
parentCaseBranch: NimNode = nil,
|
parentCaseBranch: NimNode = nil,
|
||||||
@ -86,22 +92,22 @@ proc recordFieldsAux(result: var seq[FieldDescription],
|
|||||||
case n.kind
|
case n.kind
|
||||||
of nnkRecList:
|
of nnkRecList:
|
||||||
for entry in n:
|
for entry in n:
|
||||||
recordFieldsAux result, entry,
|
collectFieldsFromRecList result, entry,
|
||||||
parentCaseField, parentCaseBranch
|
parentCaseField, parentCaseBranch
|
||||||
of nnkRecWhen:
|
of nnkRecWhen:
|
||||||
for branch in n:
|
for branch in n:
|
||||||
case branch.kind:
|
case branch.kind:
|
||||||
of nnkElifBranch:
|
of nnkElifBranch:
|
||||||
recordFieldsAux result, branch[1],
|
collectFieldsFromRecList result, branch[1],
|
||||||
parentCaseField, parentCaseBranch
|
parentCaseField, parentCaseBranch
|
||||||
of nnkElse:
|
of nnkElse:
|
||||||
recordFieldsAux result, branch[0],
|
collectFieldsFromRecList result, branch[0],
|
||||||
parentCaseField, parentCaseBranch
|
parentCaseField, parentCaseBranch
|
||||||
else:
|
else:
|
||||||
doAssert false
|
doAssert false
|
||||||
|
|
||||||
of nnkRecCase:
|
of nnkRecCase:
|
||||||
recordFieldsAux result, n[0],
|
collectFieldsFromRecList result, n[0],
|
||||||
parentCaseField,
|
parentCaseField,
|
||||||
parentCaseBranch,
|
parentCaseBranch,
|
||||||
isDiscriminator = true
|
isDiscriminator = true
|
||||||
@ -110,9 +116,9 @@ proc recordFieldsAux(result: var seq[FieldDescription],
|
|||||||
let branch = n[i]
|
let branch = n[i]
|
||||||
case branch.kind
|
case branch.kind
|
||||||
of nnkOfBranch:
|
of nnkOfBranch:
|
||||||
recordFieldsAux result, branch[^1], n[0], branch
|
collectFieldsFromRecList result, branch[^1], n[0], branch
|
||||||
of nnkElse:
|
of nnkElse:
|
||||||
recordFieldsAux result, branch[0], n[0], branch
|
collectFieldsFromRecList result, branch[0], n[0], branch
|
||||||
else:
|
else:
|
||||||
doAssert false
|
doAssert false
|
||||||
|
|
||||||
@ -150,19 +156,37 @@ proc recordFieldsAux(result: var seq[FieldDescription],
|
|||||||
else:
|
else:
|
||||||
doAssert false, "Unexpected nodes in recordFields:\n" & n.treeRepr
|
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] =
|
proc recordFields*(typeImpl: NimNode): seq[FieldDescription] =
|
||||||
# TODO: This doesn't support inheritance yet
|
|
||||||
if typeImpl.isTuple:
|
if typeImpl.isTuple:
|
||||||
for i in 1 ..< typeImpl.len:
|
for i in 1 ..< typeImpl.len:
|
||||||
result.add FieldDescription(typ: typeImpl[i], name: ident("Field" & $(i - 1)))
|
result.add FieldDescription(typ: typeImpl[i], name: ident("Field" & $(i - 1)))
|
||||||
return
|
return
|
||||||
|
|
||||||
var objectType = typeImpl[2]
|
typeImpl.expectKind nnkTypeDef
|
||||||
if objectType.kind == nnkRefTy:
|
collectFieldsInHierarchy(result, typeImpl[2])
|
||||||
objectType = objectType[0]
|
|
||||||
|
|
||||||
let recList = objectType[2]
|
|
||||||
recordFieldsAux result, recList
|
|
||||||
|
|
||||||
macro field*(obj: typed, fieldName: static string): untyped =
|
macro field*(obj: typed, fieldName: static string): untyped =
|
||||||
newDotExpr(obj, ident fieldName)
|
newDotExpr(obj, ident fieldName)
|
||||||
|
@ -16,6 +16,7 @@ import
|
|||||||
test_bitseqs,
|
test_bitseqs,
|
||||||
test_byteutils,
|
test_byteutils,
|
||||||
test_endians2,
|
test_endians2,
|
||||||
|
test_macros,
|
||||||
test_objects,
|
test_objects,
|
||||||
test_ptrops,
|
test_ptrops,
|
||||||
test_results,
|
test_results,
|
||||||
|
38
tests/test_macros.nim
Normal file
38
tests/test_macros.nim
Normal file
@ -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…
x
Reference in New Issue
Block a user