Yes, you can do this. You need to store proc address somewhere and it's args in
simple case.
Essentially, you need to wrap this code into nice macro:
proc testProc(abc: int, bca: int) {.cdecl.} =
echo "testProc: ", abc, ", ", bca
var testProcAddr = cast[pointer](testProc)
var testProcCall = cast[proc(a: int, b: int) {.cdecl.}](testProcAddr)
testProcCall(6, 7)
I created this sample macro for you. This isn't ideal, actually this is pretty
crappy but you get an idea how it works. Code doesn't support any argument
types other than int and requires cdecl calling convention. callProc proc is
actually should be generated by macro.
import macros, strutils
type
ProcInfo = ref object
name: string
procAddr: pointer
args: seq[string]
# callConv: int
var procInfos: seq[ProcInfo] = @[]
proc anotherTestProc(abc: int) {.cdecl.} =
echo "anotherTestProc: ", abc
proc testProc(abc: int, bca: int) {.cdecl.} =
echo "testProc: ", abc, ", ", bca
macro registerProc(p: typed): typed =
let impl = getImpl(p.symbol)
#echo impl.treeRepr
var xprocName = impl[0].symbol.`$`
var xprocArgs: seq[string] = @[]
for formalParam in impl.findChild(it.kind == nnkFormalParams):
if formalParam.kind != nnkIdentDefs:
continue
var argSym = formalParam[1]
xprocArgs.add(argSym.symbol.`$`)
result = parseStmt("""
block:
var prcInfo = new(ProcInfo)
prcInfo.name = "$1"
prcInfo.args = @$2
prcInfo.procAddr = cast[pointer]($3)
procInfos.add(prcInfo)
""" % [xprocName, xProcArgs.repr, xprocName])
#echo result.treeRepr
proc findProcInfo(procName: string, argCount: int): ProcInfo =
for procInfo in procInfos:
if procInfo.name == procName and
procInfo.args.len == argCount:
return procInfo
return nil
proc callProc(procName: string, args: varargs[int]) =
var p = findProcInfo(procName, args.len)
assert(p != nil)
case args.len:
of 0:
var procToCall = cast[proc() {.cdecl.}](p.procAddr)
procToCall()
of 1:
var procToCall = cast[proc(a: int) {.cdecl.}](p.procAddr)
procToCall(args[0])
of 2:
var procToCall = cast[proc(a: int, b: int) {.cdecl.}](p.procAddr)
procToCall(args[0], args[1])
else: discard
registerProc(testProc)
registerProc(anotherTestProc)
callProc("testProc", 123, 321)
callProc("anotherTestProc", 666)