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)
    

Reply via email to