Use a simpler recursion in recordFields as it's no longer an iterator

This commit is contained in:
Zahary Karadjov 2020-04-09 20:39:02 +03:00
parent b06a5b6e32
commit 3e1fa974a4
No known key found for this signature in database
GPG Key ID: C8936F8A3073D609

View File

@ -34,88 +34,53 @@ template readPragma*(field: FieldDescription, pragmaName: static string): NimNod
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 recordFields*(typeImpl: NimNode): seq[FieldDescription] = proc recordFieldsAux(result: var seq[FieldDescription],
# TODO: This doesn't support inheritance yet n: NimNode,
if typeImpl.isTuple: parentCaseField: NimNode = nil,
for i in 1 ..< typeImpl.len: parentCaseBranch: NimNode = nil,
result.add FieldDescription(typ: typeImpl[i], name: ident("Field" & $(i - 1))) isDiscriminator = false) =
return
var objectType = typeImpl[2]
if objectType.kind == nnkRefTy:
objectType = objectType[0]
let recList = objectType[2]
type
RecursionStackItem = tuple
currentNode: NimNode
currentChildItem: int
parentCaseField: NimNode
parentCaseBranch: NimNode
if recList.len > 0:
var traversalStack: seq[RecursionStackItem] = @[
(recList, 0, NimNode(nil), NimNode(nil))
]
template recuseInto(childNode: NimNode,
currentCaseField: NimNode = nil,
currentCaseBranch: NimNode = nil) =
traversalStack.add (childNode, 0, currentCaseField, currentCaseBranch)
while true:
doAssert traversalStack.len > 0
var stackTop = traversalStack[^1]
let recList = stackTop.currentNode
let idx = stackTop.currentChildItem
let n = recList[idx]
inc traversalStack[^1].currentChildItem
if idx == recList.len - 1:
discard traversalStack.pop
case n.kind case n.kind
of nnkRecList:
for entry in n:
recordFieldsAux result, entry,
parentCaseField, parentCaseBranch
of nnkRecWhen: of nnkRecWhen:
for i in countdown(n.len - 1, 0): for branch in n:
let branch = n[i]
case branch.kind: case branch.kind:
of nnkElifBranch: of nnkElifBranch:
recuseInto branch[1] recordFieldsAux result, branch[1],
parentCaseField, parentCaseBranch
of nnkElse: of nnkElse:
recuseInto branch[0] recordFieldsAux result, branch[0],
parentCaseField, parentCaseBranch
else: else:
doAssert false doAssert false
continue
of nnkRecCase: of nnkRecCase:
doAssert n.len > 0 recordFieldsAux result, n[0],
for i in countdown(n.len - 1, 1): parentCaseField,
parentCaseBranch,
isDiscriminator = true
for i in 1 ..< n.len:
let branch = n[i] let branch = n[i]
case branch.kind case branch.kind
of nnkOfBranch: of nnkOfBranch:
recuseInto branch[^1], n[0], branch recordFieldsAux result, branch[^1], n[0], branch
of nnkElse: of nnkElse:
recuseInto branch[0], n[0], branch recordFieldsAux result, branch[0], n[0], branch
else: else:
doAssert false doAssert false
recuseInto newTree(nnkRecCase, n[0]),
stackTop.parentCaseField,
stackTop.parentCaseBranch
continue
of nnkIdentDefs: of nnkIdentDefs:
let fieldType = n[^2] let fieldType = n[^2]
for i in 0 ..< n.len - 2: for i in 0 ..< n.len - 2:
var field: FieldDescription var field: FieldDescription
field.name = n[i] field.name = n[i]
field.typ = fieldType field.typ = fieldType
field.caseField = stackTop.parentCaseField field.caseField = parentCaseField
field.caseBranch = stackTop.parentCaseBranch field.caseBranch = parentCaseBranch
field.isDiscriminator = recList.kind == nnkRecCase field.isDiscriminator = isDiscriminator
if field.name.kind == nnkPragmaExpr: if field.name.kind == nnkPragmaExpr:
field.pragmas = field.name[1] field.pragmas = field.name[1]
@ -133,7 +98,19 @@ proc recordFields*(typeImpl: NimNode): seq[FieldDescription] =
else: else:
doAssert false, "Unexpected nodes in recordFields:\n" & n.treeRepr doAssert false, "Unexpected nodes in recordFields:\n" & n.treeRepr
if traversalStack.len == 0: break 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
macro field*(obj: typed, fieldName: static string): untyped = macro field*(obj: typed, fieldName: static string): untyped =
newDotExpr(obj, ident fieldName) newDotExpr(obj, ident fieldName)