sizeof alignof offsetof macros api (#10855)

This commit is contained in:
Arne Döring
2019-03-19 08:23:00 +01:00
committed by Andreas Rumpf
parent 16fcbee1bc
commit 188870648a
7 changed files with 93 additions and 1 deletions

View File

@@ -662,7 +662,7 @@ type
mNIntVal, mNFloatVal, mNSymbol, mNIdent, mNGetType, mNStrVal, mNSetIntVal,
mNSetFloatVal, mNSetSymbol, mNSetIdent, mNSetType, mNSetStrVal, mNLineInfo,
mNNewNimNode, mNCopyNimNode, mNCopyNimTree, mStrToIdent, mNSigHash,
mNNewNimNode, mNCopyNimNode, mNCopyNimTree, mStrToIdent, mNSigHash, mNSizeOf,
mNBindSym, mLocals, mNCallSite,
mEqIdent, mEqNimrodNode, mSameNodeType, mGetImpl, mNGenSym,
mNHint, mNWarning, mNError,

View File

@@ -86,6 +86,7 @@ proc initDefines*(symbols: StringTableRef) =
defineSymbol("nimHasNilSeqs")
defineSymbol("nimHasSignatureHashInMacro")
defineSymbol("nimHasDefault")
defineSymbol("nimMacrosSizealignof")
for f in low(Feature)..high(Feature):
defineSymbol("nimHas" & $f)

View File

@@ -1477,6 +1477,27 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
regs[ra].node = opMapTypeImplToAst(c.cache, regs[rb].node.sym.typ, c.debug[pc])
else:
stackTrace(c, tos, pc, "node has no type")
of opcNGetSize:
decodeBImm(rkInt)
let n = regs[rb].node
case imm
of 0: # size
if n.typ == nil:
stackTrace(c, tos, pc, "node has no type")
else:
regs[ra].intVal = getSize(c.config, n.typ)
of 1: # align
if n.typ == nil:
stackTrace(c, tos, pc, "node has no type")
else:
regs[ra].intVal = getAlign(c.config, n.typ)
else: # offset
if n.kind != nkSym:
stackTrace(c, tos, pc, "node is not a symbol")
elif n.sym.kind != skField:
stackTrace(c, tos, pc, "symbol is not a field (nskField)")
else:
regs[ra].intVal = n.sym.offset
of opcNStrVal:
decodeB(rkNode)
createStr regs[ra]

View File

@@ -93,6 +93,7 @@ type
opcNGetType,
opcNStrVal,
opcNSigHash,
opcNGetSize,
opcNSetIntVal,
opcNSetFloatVal, opcNSetSymbol, opcNSetIdent, opcNSetType, opcNSetStrVal,

View File

@@ -1236,6 +1236,12 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) =
c.gABC(n, opcNGetType, dest, tmp, rc)
c.freeTemp(tmp)
#genUnaryABC(c, n, dest, opcNGetType)
of mNSizeOf:
let imm = case n[0].sym.name.s:
of "getSize": 0
of "getAlign": 1
else: 2 # "getOffset"
c.genUnaryABI(n, dest, opcNGetSize, imm)
of mNStrVal: genUnaryABC(c, n, dest, opcNStrVal)
of mNSigHash: genUnaryABC(c, n , dest, opcNSigHash)
of mNSetIntVal:

View File

@@ -1582,3 +1582,15 @@ proc getProjectPath*(): string = discard
## Returns the path to the currently compiling project, not to
## be confused with ``system.currentSourcePath`` which returns
## the path of the current module.
when defined(nimMacrosSizealignof):
proc getSize*(arg: NimNode): int {.magic: "NSizeOf", noSideEffect.} =
## Returns the same result as ``system.sizeof``, but it works on
## ``NimNode`` for use in macro context.
proc getAlign*(arg: NimNode): int {.magic: "NSizeOf", noSideEffect.} =
## Returns the same result as ``system.alignof``, but it works on
## ``NimNode`` for use in macro context.
proc getOffset*(arg: NimNode): int {.magic: "NSizeOf", noSideEffect.} =
## Returns the same result as ``system.offsetof``, but it expects
## a resolved symbol node from a field of a type. Therefore it
## only requires one argument instead of two.

View File

@@ -3,6 +3,7 @@ discard """
body executed
body executed
OK
macros api OK
'''
"""
@@ -485,3 +486,53 @@ if failed:
quit("FAIL")
else:
echo "OK"
##########################################
# sizeof macros API
##########################################
import macros
type
Vec2f = object
x,y: float32
Vec4f = object
x,y,z,w: float32
# this type is constructed to have no platform depended alignment.
ParticleDataA = object
pos, vel: Vec2f
birthday: float32
padding: float32
moreStuff: Vec4f
const expected = [
# name size align offset
("pos", 8, 4, 0),
("vel", 8, 4, 8),
("birthday", 4, 4, 16),
("padding", 4, 4, 20),
("moreStuff", 16, 4, 24)
]
macro typeProcessing(arg: typed): untyped =
let recList = arg.getTypeImpl[2]
recList.expectKind nnkRecList
for i, identDefs in recList:
identDefs.expectKind nnkIdentDefs
identDefs.expectLen 3
let sym = identDefs[0]
sym.expectKind nnkSym
doAssert expected[i][0] == sym.strVal
doAssert expected[i][1] == getSize(sym)
doAssert expected[i][2] == getAlign(sym)
doAssert expected[i][3] == getOffset(sym)
result = newCall(bindSym"echo", newLit("macros api OK"))
proc main() =
var mylocal: ParticleDataA
typeProcessing(mylocal)
main()