diff --git a/compiler/ast.nim b/compiler/ast.nim index f8343c1a3be50..77560e36bdaf1 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -577,7 +577,8 @@ type TTypeFlags* = set[TTypeFlag] TSymKind* = enum # the different symbols (start with the prefix sk); - # order is important for the documentation generator! + # *Order is important for the documentation generator!* + # *Keep this enum synced with `macros.NimSymKind`.* skUnknown, # unknown symbol: used for parsing assembler blocks # and first phase symbol lookup in generics skConditional, # symbol for the preprocessor (may become obsolete) diff --git a/lib/core/macros.nim b/lib/core/macros.nim index b370aaa7bbee1..0649da5e8363c 100644 --- a/lib/core/macros.nim +++ b/lib/core/macros.nim @@ -115,13 +115,16 @@ type TNimTypeKinds* {.deprecated.} = set[NimTypeKind] NimSymKind* = enum + # Contributors: + # * Keep the order of this enum synced with `ast.TSymKind`. + # * Test these values in `tests/macros/tsymkind.nim`. nskUnknown, nskConditional, nskDynLib, nskParam, nskGenericParam, nskTemp, nskModule, nskType, nskVar, nskLet, nskConst, nskResult, nskProc, nskFunc, nskMethod, nskIterator, nskConverter, nskMacro, nskTemplate, nskField, nskEnumField, nskForVar, nskLabel, - nskStub + nskStub, nskPackage, nskAlias TNimSymKinds* {.deprecated.} = set[NimSymKind] @@ -1755,3 +1758,26 @@ proc extractDocCommentsAndRunnables*(n: NimNode): NimNode = result.add ni else: break else: break + +func getModule*(n: NimNode): NimNode = + ## Returns the owning module of a node. + ## Returns `nil` if the node is package symbol `nskPackage`. + case n.symKind + of nskModule: return n + of nskPackage: return nil + else: + var n = n + while n.symKind != nskModule: + n = n.owner + return n + +func getPackage*(n: NimNode): NimNode = + ## Returns the owning package of a node. + case n.symKind + of nskPackage: return n + of nskModule: return n.owner + else: + var n = n + while n.symKind != nskPackage: + n = n.owner + return n diff --git a/tests/macros/tsymkind.nim b/tests/macros/tsymkind.nim new file mode 100644 index 0000000000000..2cc1e834d91df --- /dev/null +++ b/tests/macros/tsymkind.nim @@ -0,0 +1,77 @@ + +# Test `NimSymKind` and related procs. + +import std/macros + +# A package symbol can't be directly referenced, so this macro will return it. +macro getPackageSym(sym: typed): NimNode = + getPackage(sym) + +# these are used in tests below +method someMethod(n: NimNode) = discard +converter someConverter(a: char): byte = discard +type Obj = object + field: int + +block test_symKind: + macro kind(sym: typed): NimSymKind = + newLit(symKind(sym)) + template checkKind(sym) {.dirty.} = + doAssert kind(sym) == member, $kind(sym) + for member in NimSymKind: + case member + of nskUnknown: discard # how to test? + of nskConditional: discard # how to test? + of nskDynLib: discard # how to test? + of nskParam: + proc aProc(aParam = 0) = + checkKind aParam + aProc() + of nskGenericParam: discard # how to test? + # proc aGenericProc[T](aParam: T) = + # checkKind T + # aGenericProc(0) + of nskTemp: discard # how to test? + of nskModule: checkKind macros + of nskType: checkKind NimNode + of nskVar: + var someVar = 0 + checkKind someVar + of nskLet: + let someLet = 0 + checkKind someLet + of nskConst: discard # how to test? + # const someConst = 0 + # checkKind someConst + of nskResult: + proc aProc: int = + checkKind result + discard aProc() + of nskProc: checkKind symKind + of nskFunc: checkKind getModule + of nskMethod: checkKind someMethod + of nskIterator: checkKind items + of nskConverter: checkKind someConverter + of nskMacro: checkKind getPackageSym + of nskTemplate: checkKind checkKind + of nskField: discard # how to test? + of nskEnumField: discard # how to test? + of nskForVar: discard # how to test? + of nskLabel: checkKind test_symKind + of nskStub: discard # how to test? + of nskPackage: discard # checkKind getPackageSym(macros) + of nskAlias: discard # how to test? + +block test_getModule: + macro moduleName(sym: typed): string = + getModule(sym).toStrLit + doAssert moduleName(macros) == "macros" + # doAssert moduleName(getPackageSym(macros)) == "macros" + doAssert moduleName(getModule) == "macros", moduleName(getModule) + +block test_getPackage: + macro packageName(sym: typed): string = + getPackage(sym).toStrLit + # doAssert packageName(getPackageSym(macros)) == "stdlib" + doAssert packageName(macros) == "stdlib" + doAssert packageName(getModule) == "stdlib"