Thomas
Thomas

Reputation: 3381

Nim reflect on type's field types at compile-time

Suppose I have a type defined as follows:

type TMyStruct = object
    foo: int32
    bar: int16

My goal is to construct a macro (or otherwise) which, given a "simple" object type like the one above, is able to compute the sum of the sizes of each field in the type, based on sizeof. In this case int32 has size 4 and int16 has size 2 so the idea is that

myMacro(TMyStruct)  # or, in the worst case, myMacro(x) where x is a TMyStruct

should evaluate to 6 as a constant expression. I want to extend it to nested objects later on but that should be easy via recursion once the basic version is working.

I have tried many things and failed horribly; the farthest I managed to get was to retrieve the field names "foo" and "bar" in the AST as nnkSymNodes, but I was unable to retrieve any information about their types. Meaningful documentation (at my level of Nim expertise) is sparse to non-existent.

Is what I am asking possible, and what Nim functionality do I need to use to achieve it?

Thanks

Upvotes: 2

Views: 909

Answers (1)

flyx
flyx

Reputation: 39768

import macros

type TMyStruct = object
  foo: int32
  bar: int16

macro sumSizes(t: typedesc): expr =
  result = nil
  let tDesc = getType(getType(t)[1])
  for field in tDesc[2].children:
    let sizeOfThis = newCall("sizeof", field)
    if isNil(result):
      result = sizeOfThis
    else:
      result = infix(result, "+", sizeOfThis)

echo sumSizes(TMyStruct)

It is a bit strange that you have to chain the getType calls in the beginning. This is because getType(t) returns the following:

BracketExpr
  Sym "typeDesc"
  Sym "TMyStruct"

If you want to do this with instances of a type, just change these lines:

macro sumSizes(e: typed): expr =
  result = nil
  let tDesc = getType(e)

Note that typed is important here to have a typed symbol inside the macro.

Upvotes: 2

Related Questions