mvaruintconv.nim 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146
  1. import
  2. std/[macros, tables, hashes]
  3. export
  4. macros
  5. type
  6. FieldDescription* = object
  7. name*: NimNode
  8. isPublic*: bool
  9. isDiscriminator*: bool
  10. typ*: NimNode
  11. pragmas*: NimNode
  12. caseField*: NimNode
  13. caseBranch*: NimNode
  14. {.push raises: [].}
  15. func isTuple*(t: NimNode): bool =
  16. t.kind == nnkBracketExpr and t[0].kind == nnkSym and eqIdent(t[0], "tuple")
  17. macro isTuple*(T: type): untyped =
  18. newLit(isTuple(getType(T)[1]))
  19. proc collectFieldsFromRecList(result: var seq[FieldDescription],
  20. n: NimNode,
  21. parentCaseField: NimNode = nil,
  22. parentCaseBranch: NimNode = nil,
  23. isDiscriminator = false) =
  24. case n.kind
  25. of nnkRecList:
  26. for entry in n:
  27. collectFieldsFromRecList result, entry,
  28. parentCaseField, parentCaseBranch
  29. of nnkRecWhen:
  30. for branch in n:
  31. case branch.kind:
  32. of nnkElifBranch:
  33. collectFieldsFromRecList result, branch[1],
  34. parentCaseField, parentCaseBranch
  35. of nnkElse:
  36. collectFieldsFromRecList result, branch[0],
  37. parentCaseField, parentCaseBranch
  38. else:
  39. doAssert false
  40. of nnkRecCase:
  41. collectFieldsFromRecList result, n[0],
  42. parentCaseField,
  43. parentCaseBranch,
  44. isDiscriminator = true
  45. for i in 1 ..< n.len:
  46. let branch = n[i]
  47. case branch.kind
  48. of nnkOfBranch:
  49. collectFieldsFromRecList result, branch[^1], n[0], branch
  50. of nnkElse:
  51. collectFieldsFromRecList result, branch[0], n[0], branch
  52. else:
  53. doAssert false
  54. of nnkIdentDefs:
  55. let fieldType = n[^2]
  56. for i in 0 ..< n.len - 2:
  57. var field: FieldDescription
  58. field.name = n[i]
  59. field.typ = fieldType
  60. field.caseField = parentCaseField
  61. field.caseBranch = parentCaseBranch
  62. field.isDiscriminator = isDiscriminator
  63. if field.name.kind == nnkPragmaExpr:
  64. field.pragmas = field.name[1]
  65. field.name = field.name[0]
  66. if field.name.kind == nnkPostfix:
  67. field.isPublic = true
  68. field.name = field.name[1]
  69. result.add field
  70. of nnkSym:
  71. result.add FieldDescription(
  72. name: n,
  73. typ: getType(n),
  74. caseField: parentCaseField,
  75. caseBranch: parentCaseBranch,
  76. isDiscriminator: isDiscriminator)
  77. of nnkNilLit, nnkDiscardStmt, nnkCommentStmt, nnkEmpty:
  78. discard
  79. else:
  80. doAssert false, "Unexpected nodes in recordFields:\n" & n.treeRepr
  81. proc collectFieldsInHierarchy(result: var seq[FieldDescription],
  82. objectType: NimNode) =
  83. var objectType = objectType
  84. objectType.expectKind {nnkObjectTy, nnkRefTy}
  85. if objectType.kind == nnkRefTy:
  86. objectType = objectType[0]
  87. objectType.expectKind nnkObjectTy
  88. var baseType = objectType[1]
  89. if baseType.kind != nnkEmpty:
  90. baseType.expectKind nnkOfInherit
  91. baseType = baseType[0]
  92. baseType.expectKind nnkSym
  93. baseType = getImpl(baseType)
  94. baseType.expectKind nnkTypeDef
  95. baseType = baseType[2]
  96. baseType.expectKind {nnkObjectTy, nnkRefTy}
  97. collectFieldsInHierarchy result, baseType
  98. let recList = objectType[2]
  99. collectFieldsFromRecList result, recList
  100. proc recordFields*(typeImpl: NimNode): seq[FieldDescription] =
  101. if typeImpl.isTuple:
  102. for i in 1 ..< typeImpl.len:
  103. result.add FieldDescription(typ: typeImpl[i], name: ident("Field" & $(i - 1)))
  104. return
  105. let objectType = case typeImpl.kind
  106. of nnkObjectTy: typeImpl
  107. of nnkTypeDef: typeImpl[2]
  108. else:
  109. macros.error("object type expected", typeImpl)
  110. return
  111. collectFieldsInHierarchy(result, objectType)
  112. macro field*(obj: typed, fieldName: static string): untyped =
  113. newDotExpr(obj, ident fieldName)
  114. proc skipPragma*(n: NimNode): NimNode =
  115. if n.kind == nnkPragmaExpr: n[0]
  116. else: n
  117. {.pop.}