123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156 |
- # issue #23186
- block: # simplified
- template typedTempl(x: int, body): untyped =
- body
- proc generic1[T]() =
- discard
- proc generic2[T]() =
- typedTempl(1):
- let x = generic1[T]
- generic2[int]()
- import std/macros
- when not compiles(len((1, 2))):
- import std/typetraits
- func len(x: tuple): int =
- arity(type(x))
- block: # full issue example
- type FieldDescription = object
- name: NimNode
- func isTuple(t: NimNode): bool =
- t.kind == nnkBracketExpr and t[0].kind == nnkSym and eqIdent(t[0], "tuple")
- proc collectFieldsFromRecList(result: var seq[FieldDescription],
- n: NimNode,
- parentCaseField: NimNode = nil,
- parentCaseBranch: NimNode = nil,
- isDiscriminator = false) =
- case n.kind
- of nnkRecList:
- for entry in n:
- collectFieldsFromRecList result, entry,
- parentCaseField, parentCaseBranch
- of nnkIdentDefs:
- for i in 0 ..< n.len - 2:
- var field: FieldDescription
- field.name = n[i]
- if field.name.kind == nnkPragmaExpr:
- field.name = field.name[0]
- if field.name.kind == nnkPostfix:
- field.name = field.name[1]
- result.add field
- of nnkNilLit, nnkDiscardStmt, nnkCommentStmt, nnkEmpty:
- discard
- 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]
- let recList = objectType[2]
- collectFieldsFromRecList result, recList
- proc recordFields(typeImpl: NimNode): seq[FieldDescription] =
- let objectType = case typeImpl.kind
- of nnkObjectTy: typeImpl
- of nnkTypeDef: typeImpl[2]
- else:
- macros.error("object type expected", typeImpl)
- return
- collectFieldsInHierarchy(result, objectType)
- proc skipPragma(n: NimNode): NimNode =
- if n.kind == nnkPragmaExpr: n[0]
- else: n
- func declval(T: type): T =
- doAssert false,
- "declval should be used only in `typeof` expressions and concepts"
- default(ptr T)[]
- macro enumAllSerializedFieldsImpl(T: type, body: untyped): untyped =
- var typeAst = getType(T)[1]
- var typeImpl: NimNode
- let isSymbol = not typeAst.isTuple
- if not isSymbol:
- typeImpl = typeAst
- else:
- typeImpl = getImpl(typeAst)
- result = newStmtList()
- var i = 0
- for field in recordFields(typeImpl):
- let
- fieldIdent = field.name
- realFieldName = newLit($fieldIdent.skipPragma)
- fieldName = realFieldName
- fieldIndex = newLit(i)
- let fieldNameDefs =
- if isSymbol:
- quote:
- const fieldName {.inject, used.} = `fieldName`
- const realFieldName {.inject, used.} = `realFieldName`
- else:
- quote:
- const fieldName {.inject, used.} = $`fieldIndex`
- const realFieldName {.inject, used.} = $`fieldIndex`
- # we can't access .Fieldn, so our helper knows
- # to parseInt this
- let field =
- if isSymbol:
- quote do: declval(`T`).`fieldIdent`
- else:
- quote do: declval(`T`)[`fieldIndex`]
- result.add quote do:
- block:
- `fieldNameDefs`
- type FieldType {.inject, used.} = type(`field`)
- `body`
- i += 1
- template enumAllSerializedFields(T: type, body): untyped =
- when T is ref|ptr:
- type TT = type(default(T)[])
- enumAllSerializedFieldsImpl(TT, body)
- else:
- enumAllSerializedFieldsImpl(T, body)
- type
- MemRange = object
- startAddr: ptr byte
- length: int
- SszNavigator[T] = object
- m: MemRange
- func sszMount(data: openArray[byte], T: type): SszNavigator[T] =
- let startAddr = unsafeAddr data[0]
- SszNavigator[T](m: MemRange(startAddr: startAddr, length: data.len))
- func sszMount(data: openArray[char], T: type): SszNavigator[T] =
- let startAddr = cast[ptr byte](unsafeAddr data[0])
- SszNavigator[T](m: MemRange(startAddr: startAddr, length: data.len))
- template sszMount(data: MemRange, T: type): SszNavigator[T] =
- SszNavigator[T](m: data)
- func navigateToField[T](
- n: SszNavigator[T],
- FieldType: type): SszNavigator[FieldType] =
- default(SszNavigator[FieldType])
- type
- FieldInfo = ref object
- navigator: proc (m: MemRange): MemRange {.
- gcsafe, noSideEffect, raises: [IOError] .}
- func fieldNavigatorImpl[RecordType; FieldType; fieldName: static string](
- m: MemRange): MemRange =
- var typedNavigator = sszMount(m, RecordType)
- discard navigateToField(typedNavigator, FieldType)
- default(MemRange)
- func genTypeInfo(T: type) =
- when T is object:
- enumAllSerializedFields(T):
- discard FieldInfo(navigator: fieldNavigatorImpl[T, FieldType, fieldName])
- type
- Foo = object
- bar: Bar
- BarList = seq[uint64]
- Bar = object
- b: BarList
- baz: Baz
- Baz = object
- i: uint64
- genTypeInfo(Foo)
|