I'm trying to associate some data to a function symbol inside said function, so
that later I can retrieve this data given a function call. Here's an example:
import macros, tables, hashes
proc hash(n: NimNode): Hash = hash($n) # Make Table compile
var registry {.compiletime.}: Table[NimNode, NimNode] # Map function symbol
=> internal function symbol
macro register(functionSymbol, internalFunctionSymbol: typed): untyped =
registry[functionSymbol] = internalFunctionSymbol
macro inst(someCall: typed): untyped =
let functionSymbol = someCall[0]
let internalFunctionSymbol = registry[functionSymbol]
result = newCall(internalFunctionSymbol)
# So it can be used like this
proc foo(a: int) =
proc bar() =
echo "foo int"
register(foo, bar)
foo(5) # Make sure `foo` is instantiated
inst foo(5) # I expect this to be replaced with corresponding `bar()`
Run
The example above works as expected, however it quickly gets flaky with `foo`
overloads:
proc foo(a: string) =
proc bar() =
echo "foo string"
register(foo, bar)
foo("hi") # Make sure `foo` is instantiated
inst foo("hi") # I expect this to be replaced with corresponding `bar()`
Run
The snippet above will fail with KeyError on registry lookup, even though
there's 2 keys in the registry by this time.
It gets even worse with generics:
proc baz[T](a: T) =
proc bar() =
when T is string:
echo "baz string"
else:
echo "baz not string"
register(baz, bar)
baz("hi") # Make sure `baz[string]` is instantiated
inst baz("hi") # I expect this to be replaced with corresponding `bar()`
baz(5) # Make sure `baz[int]` is instantiated
inst baz(5) # I expect this to be replaced with corresponding `bar()`
Run
In the snippet above the registry is populated only with one symbol, even
though `register` is called once per every instance of `baz`, thus twice in
total. And both `inst` fail on lookup, as neither `baz[string]` nor `baz[int]`
match that single key in the registry.
So the question is am I wrong in my expectations and why? Or is it a bug?