From 086676782a6053158cc6da14bc65961205c4b014 Mon Sep 17 00:00:00 2001 From: cooldome Date: Wed, 21 Nov 2018 20:30:03 +0000 Subject: [PATCH] Add isInstanceOf for generic procs to the macros module (#9730) --- changelog.md | 4 ++++ compiler/ast.nim | 3 ++- compiler/condsyms.nim | 2 +- compiler/vm.nim | 11 +++++++++++ compiler/vmdef.nim | 3 ++- compiler/vmgen.nim | 1 + lib/core/macros.nim | 6 ++++++ tests/macros/tgetimpl.nim | 19 +++++++++++++++++++ 8 files changed, 46 insertions(+), 3 deletions(-) diff --git a/changelog.md b/changelog.md index 7cc2a3b63d..1a005639ae 100644 --- a/changelog.md +++ b/changelog.md @@ -61,6 +61,10 @@ proc enumToString*(enums: openArray[enum]): string = - Added `system.typeof` for more control over how `type` expressions can be deduced. +- Added `macros.isInstantiationOf` for checking if the proc symbol + is instantiation of generic proc symbol. + + ### Library changes - The string output of `macros.lispRepr` proc has been tweaked diff --git a/compiler/ast.nim b/compiler/ast.nim index bb0f95acd1..6a73df3c75 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -656,7 +656,8 @@ type mNHint, mNWarning, mNError, mInstantiationInfo, mGetTypeInfo, mNimvm, mIntDefine, mStrDefine, mRunnableExamples, - mException, mBuiltinType, mSymOwner, mUncheckedArray, mGetImplTransf + mException, mBuiltinType, mSymOwner, mUncheckedArray, mGetImplTransf, + mSymIsInstantiationOf # 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 ab89481b89..9a4c1701c2 100644 --- a/compiler/condsyms.nim +++ b/compiler/condsyms.nim @@ -86,7 +86,7 @@ proc initDefines*(symbols: StringTableRef) = defineSymbol("nimUncheckedArrayTyp") defineSymbol("nimHasTypeof") defineSymbol("nimErrorProcCanHaveBody") - + defineSymbol("nimHasInstantiationOfInMacro") defineSymbol("nimHasNilSeqs") for f in low(Feature)..high(Feature): defineSymbol("nimHas" & $f) diff --git a/compiler/vm.nim b/compiler/vm.nim index 5b5b807bb6..7e7ec8903c 100644 --- a/compiler/vm.nim +++ b/compiler/vm.nim @@ -960,6 +960,17 @@ 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 opcSymIsInstantiationOf: + decodeBC(rkInt) + let a = regs[rb].node + let b = regs[rc].node + if a.kind == nkSym and a.sym.kind in skProcKinds and + b.kind == nkSym and b.sym.kind in skProcKinds: + regs[ra].intVal = + if sfFromGeneric in a.sym.flags and a.sym.owner == b.sym: 1 + else: 0 + else: + stackTrace(c, tos, pc, "node is not a proc symbol") of opcEcho: let rb = instr.regB if rb == 1: diff --git a/compiler/vmdef.nim b/compiler/vmdef.nim index 25ace3cddb..493078f742 100644 --- a/compiler/vmdef.nim +++ b/compiler/vmdef.nim @@ -147,7 +147,8 @@ type opcTypeTrait, opcMarshalLoad, opcMarshalStore, opcToNarrowInt, - opcSymOwner + opcSymOwner, + opcSymIsInstantiationOf TBlock* = object label*: PSym diff --git a/compiler/vmgen.nim b/compiler/vmgen.nim index c37ec7c6bd..e52f460d29 100644 --- a/compiler/vmgen.nim +++ b/compiler/vmgen.nim @@ -1148,6 +1148,7 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) = of mGetImpl: genUnaryABC(c, n, dest, opcGetImpl) of mGetImplTransf: genUnaryABC(c, n, dest, opcGetImplTransf) of mSymOwner: genUnaryABC(c, n, dest, opcSymOwner) + of mSymIsInstantiationOf: genBinaryABC(c, n, dest, opcSymIsInstantiationOf) 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 d74d86bf63..f45ca3f821 100644 --- a/lib/core/macros.nim +++ b/lib/core/macros.nim @@ -274,6 +274,12 @@ when defined(nimHasSymOwnerInMacro): ## result is also mnde of kind nnkSym if owner exists otherwise ## nnkNilLit is returned +when defined(nimHasInstantiationOfInMacro): + proc isInstantiationOf*(instanceProcSym, genProcSym: NimNode): bool {.magic: "SymIsInstantiationOf", noSideEffect.} + ## check if proc symbol is instance of the generic proc symbol + ## useful to check proc symbols against generic symbols + ## returned by `bindSym` + 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 a546271ff8..aacfb703e8 100644 --- a/tests/macros/tgetimpl.nim +++ b/tests/macros/tgetimpl.nim @@ -46,3 +46,22 @@ static: doAssert isSameOwner(foo, poo) doAssert isSameOwner(foo, echo) == false doAssert isSameOwner(poo, len) == false + +#--------------------------------------------------------------- + +macro check_gen_proc(ex: typed): (bool, bool) = + let lenChoice = bindsym"len" + var is_equal = false + var is_instance_of = false + for child in lenChoice: + if not is_equal: + is_equal = ex[0] == child + if not is_instance_of: + is_instance_of = isInstantiationOf(ex[0], child) + + result = nnkTupleConstr.newTree(newLit(is_equal), newLit(is_instance_of)) + +# check that len(seq[int]) is not equal to bindSym"len", but is instance of it +let a = @[1,2,3] +assert: check_gen_proc(len(a)) == (false, true) +