diff --git a/compiler/ast.nim b/compiler/ast.nim index 001d96060..694944631 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -657,7 +657,7 @@ type mNHint, mNWarning, mNError, mInstantiationInfo, mGetTypeInfo, mNimvm, mIntDefine, mStrDefine, mRunnableExamples, - mException, mBuiltinType + mException, mBuiltinType, mSymOwner # things that we can evaluate safely at compile time, even if not asked for it: const diff --git a/compiler/condsyms.nim b/compiler/condsyms.nim index 78645b6fd..a22b613f0 100644 --- a/compiler/condsyms.nim +++ b/compiler/condsyms.nim @@ -75,6 +75,7 @@ proc initDefines*(symbols: StringTableRef) = defineSymbol("nimNoZeroTerminator") defineSymbol("nimNotNil") defineSymbol("nimVmExportFixed") + defineSymbol("nimHasSymOwnerInMacro") defineSymbol("nimNewRuntime") defineSymbol("nimIncrSeqV3") defineSymbol("nimAshr") diff --git a/compiler/vm.nim b/compiler/vm.nim index 9143051a9..e38642de8 100644 --- a/compiler/vm.nim +++ b/compiler/vm.nim @@ -920,6 +920,15 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg = regs[ra].node.flags.incl nfIsRef else: stackTrace(c, tos, pc, "node is not a symbol") + of opcSymOwner: + decodeB(rkNode) + let a = regs[rb].node + if a.kind == nkSym: + regs[ra].node = if a.sym.owner.isNil: newNode(nkNilLit) + else: newSymNode(a.sym.skipGenericOwner) + regs[ra].node.flags.incl nfIsRef + else: + stackTrace(c, tos, pc, "node is not a symbol") of opcEcho: let rb = instr.regB if rb == 1: diff --git a/compiler/vmdef.nim b/compiler/vmdef.nim index 0aee079f5..d642043dc 100644 --- a/compiler/vmdef.nim +++ b/compiler/vmdef.nim @@ -141,7 +141,8 @@ type opcSetType, # dest.typ = types[Bx] opcTypeTrait, opcMarshalLoad, opcMarshalStore, - opcToNarrowInt + opcToNarrowInt, + opcSymOwner TBlock* = object label*: PSym diff --git a/compiler/vmgen.nim b/compiler/vmgen.nim index dcf76f639..e87347ec8 100644 --- a/compiler/vmgen.nim +++ b/compiler/vmgen.nim @@ -1118,6 +1118,7 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) = of mStaticExec: genBinaryABCD(c, n, dest, opcGorge) of mNLen: genUnaryABI(c, n, dest, opcLenSeq, nimNodeFlag) of mGetImpl: genUnaryABC(c, n, dest, opcGetImpl) + of mSymOwner: genUnaryABC(c, n, dest, opcSymOwner) of mNChild: genBinaryABC(c, n, dest, opcNChild) of mNSetChild: genVoidABC(c, n, dest, opcNSetChild) of mNDel: genVoidABC(c, n, dest, opcNDel) diff --git a/lib/core/macros.nim b/lib/core/macros.nim index 5b29d5e94..4d76d60c2 100644 --- a/lib/core/macros.nim +++ b/lib/core/macros.nim @@ -237,6 +237,12 @@ else: # bootstrapping substitute else: n.strValOld +when defined(nimHasSymOwnerInMacro): + proc owner*(sym: NimNode): NimNode {.magic: "SymOwner", noSideEffect.} + ## accepts node of kind nnkSym and returns its owner's symbol. + ## result is also mnde of kind nnkSym if owner exists otherwise + ## nnkNilLit is returned + proc getType*(n: NimNode): NimNode {.magic: "NGetType", noSideEffect.} ## with 'getType' you can access the node's `type`:idx:. A Nim type is ## mapped to a Nim AST too, so it's slightly confusing but it means the same diff --git a/tests/macros/tgetimpl.nim b/tests/macros/tgetimpl.nim index d38492934..715c969f3 100644 --- a/tests/macros/tgetimpl.nim +++ b/tests/macros/tgetimpl.nim @@ -1,6 +1,7 @@ discard """ msg: '''"muhaha" proc poo(x, y: int) = + let y = x echo ["poo"]''' """ @@ -10,11 +11,39 @@ const foo = "muhaha" proc poo(x, y: int) = + let y = x echo "poo" macro m(x: typed): untyped = - echo repr x.symbol.getImpl + echo repr x.getImpl result = x discard m foo discard m poo + +#------------ + +macro checkOwner(x: typed, check_id: static[int]): untyped = + let sym = case check_id: + of 0: x + of 1: x.getImpl.body[0][0][0] + of 2: x.getImpl.body[0][0][^1] + of 3: x.getImpl.body[1][0] + else: x + result = newStrLitNode($sym.owner.symKind) + +macro isSameOwner(x, y: typed): untyped = + result = + if x.owner == y.owner: bindSym"true" + else: bindSym"false" + + +static: + doAssert checkOwner(foo, 0) == "nskModule" + doAssert checkOwner(poo, 0) == "nskModule" + doAssert checkOwner(poo, 1) == "nskProc" + doAssert checkOwner(poo, 2) == "nskProc" + doAssert checkOwner(poo, 3) == "nskModule" + doAssert isSameOwner(foo, poo) + doAssert isSameOwner(foo, echo) == false + doAssert isSameOwner(poo, len) == false