diff options
-rw-r--r-- | compiler/ast.nim | 2 | ||||
-rw-r--r-- | compiler/condsyms.nim | 1 | ||||
-rw-r--r-- | compiler/vm.nim | 21 | ||||
-rw-r--r-- | compiler/vmdef.nim | 1 | ||||
-rw-r--r-- | compiler/vmgen.nim | 6 | ||||
-rw-r--r-- | lib/core/macros.nim | 12 | ||||
-rw-r--r-- | tests/misc/tsizeof.nim | 51 |
7 files changed, 93 insertions, 1 deletions
diff --git a/compiler/ast.nim b/compiler/ast.nim index f6778eb85..5cc608c2e 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -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, diff --git a/compiler/condsyms.nim b/compiler/condsyms.nim index 15127e108..7ae5412f5 100644 --- a/compiler/condsyms.nim +++ b/compiler/condsyms.nim @@ -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) diff --git a/compiler/vm.nim b/compiler/vm.nim index 0922f7353..df0b4ac1d 100644 --- a/compiler/vm.nim +++ b/compiler/vm.nim @@ -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] diff --git a/compiler/vmdef.nim b/compiler/vmdef.nim index 3b6a44deb..6099bfb9f 100644 --- a/compiler/vmdef.nim +++ b/compiler/vmdef.nim @@ -93,6 +93,7 @@ type opcNGetType, opcNStrVal, opcNSigHash, + opcNGetSize, opcNSetIntVal, opcNSetFloatVal, opcNSetSymbol, opcNSetIdent, opcNSetType, opcNSetStrVal, diff --git a/compiler/vmgen.nim b/compiler/vmgen.nim index 2d9166be0..47b2c12e5 100644 --- a/compiler/vmgen.nim +++ b/compiler/vmgen.nim @@ -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: diff --git a/lib/core/macros.nim b/lib/core/macros.nim index b7d0f40f4..e48df38f5 100644 --- a/lib/core/macros.nim +++ b/lib/core/macros.nim @@ -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. diff --git a/tests/misc/tsizeof.nim b/tests/misc/tsizeof.nim index c53cfb676..50d1c645a 100644 --- a/tests/misc/tsizeof.nim +++ b/tests/misc/tsizeof.nim @@ -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() |