@@ -2,14 +2,12 @@ import std/[macros, tables]
22import chronos
33import ../ ffi_types
44
5- var registeredRequests* {.threadvar .}: Table [cstring , FFIRequestProc ]
6-
75proc extractFieldsFromLambda (body: NimNode ): seq [NimNode ] =
86 # # Extracts the fields (params) from the given lambda body.
97 var procNode = body
108 if procNode.kind == nnkStmtList and procNode.len == 1 :
119 procNode = procNode[0 ]
12- if procNode.kind != nnkLambda:
10+ if procNode.kind != nnkLambda and procNode.kind != nnkProcDef :
1311 error " registerReqFFI expects a lambda proc, found: " & $ procNode.kind
1412
1513 let params = procNode[3 ] # parameters list
@@ -26,7 +24,7 @@ proc buildRequestType(reqTypeName: NimNode, body: NimNode): NimNode =
2624 var procNode = body
2725 if procNode.kind == nnkStmtList and procNode.len == 1 :
2826 procNode = procNode[0 ]
29- if procNode.kind != nnkLambda:
27+ if procNode.kind != nnkLambda and procNode.kind != nnkProcDef :
3028 error " registerReqFFI expects a lambda proc, found: " & $ procNode.kind
3129
3230 let params = procNode[3 ] # formal params of the lambda
@@ -62,7 +60,7 @@ proc buildFfiNewReqProc(reqTypeName, body: NimNode): NimNode =
6260 else :
6361 procNode = body
6462
65- if procNode.kind != nnkLambda:
63+ if procNode.kind != nnkLambda and procNode.kind != nnkProcDef :
6664 error " registerReqFFI expects a lambda definition. Found: " & $ procNode.kind
6765
6866 # T: typedesc[CreateNodeRequest]
@@ -188,7 +186,7 @@ proc buildProcessFFIRequestProc(reqTypeName, reqHandler, body: NimNode): NimNode
188186 var procNode = body
189187 if procNode.kind == nnkStmtList and procNode.len == 1 :
190188 procNode = procNode[0 ]
191- if procNode.kind != nnkLambda:
189+ if procNode.kind != nnkLambda and procNode.kind != nnkProcDef :
192190 error " registerReqFFI expects a lambda definition. Found: " & $ procNode.kind
193191
194192 let typedescParam =
@@ -317,31 +315,102 @@ macro registerReqFFI*(reqTypeName, reqHandler, body: untyped): untyped =
317315 let deleteProc = buildFfiDeleteReqProc (reqTypeName, fields)
318316 result = newStmtList (typeDef, ffiNewReqProc, deleteProc, processProc, addNewReqToReg)
319317
320- # echo "Registered FFI request: " & result.repr
321-
322- macro processReq * (reqType: typed , args: varargs [untyped ]): untyped =
323- # # Expands T.processReq(a,b,...) into the sendRequest boilerplate.
324-
325- # Collect the passed arguments as NimNodes
326- var callArgs = @ [reqType, ident (" callback" ), ident (" userData" )]
318+ macro processReq * (
319+ reqType, ctx, callback, userData: untyped , args: varargs [untyped ]
320+ ): untyped =
321+ # # Expands T.processReq(ctx, callback, userData, a, b, ...)
322+ var callArgs = @ [reqType, callback, userData]
327323 for a in args:
328324 callArgs.add a
329325
330- # Build: ffiNewReq(reqType, callback, userData, arg1, arg2, ...)
331326 let newReqCall = newCall (ident (" ffiNewReq" ), callArgs)
332327
333- # Build: ffi_context.sendRequestToFFIThread(ctx, <newReqCall>)
334328 let sendCall = newCall (
335- newDotExpr (ident (" ffi_context" ), ident (" sendRequestToFFIThread" )),
336- ident (" ctx" ),
337- newReqCall,
329+ newDotExpr (ident (" ffi_context" ), ident (" sendRequestToFFIThread" )), ctx, newReqCall
338330 )
339331
340332 result = quote:
341333 block :
342334 let res = `sendCall`
343- if res.isErr:
335+ if res.isErr () :
344336 let msg = " error in sendRequestToFFIThread: " & res.error
345- callback (RET_ERR , unsafeAddr msg [0 ], cast [csize_t ](msg.len), userData)
337+ ` callback` (RET_ERR , unsafeAddr msg [0 ], cast [csize_t ](msg.len), ` userData` )
346338 return RET_ERR
347339 return RET_OK
340+
341+ macro ffi * (prc: untyped ): untyped =
342+ let procName = prc[0 ]
343+ let formalParams = prc[3 ]
344+ let bodyNode = prc[^ 1 ]
345+
346+ if formalParams.len < 2 :
347+ error (" `.ffi.` procs require at least 1 parameter" )
348+
349+ let firstParam = formalParams[1 ]
350+ let paramIdent = firstParam[0 ]
351+ let paramType = firstParam[1 ]
352+
353+ let reqName = ident ($ procName & " Req" )
354+ let returnType = ident (" cint" )
355+
356+ # Build parameter list (skip return type)
357+ var newParams = newSeq [NimNode ]()
358+ newParams.add (returnType)
359+ for i in 1 ..< formalParams.len:
360+ newParams.add (newIdentDefs (formalParams[i][0 ], formalParams[i][1 ]))
361+
362+ # Build Future[Result[string, string]] return type
363+ let futReturnType = quote:
364+ Future [Result [string , string ]]
365+
366+ var userParams = newSeq [NimNode ]()
367+ userParams.add (futReturnType)
368+ if formalParams.len > 3 :
369+ for i in 4 ..< formalParams.len:
370+ userParams.add (newIdentDefs (formalParams[i][0 ], formalParams[i][1 ]))
371+
372+ # Build argument list for processReq
373+ var argsList = newSeq [NimNode ]()
374+ for i in 1 ..< formalParams.len:
375+ argsList.add (formalParams[i][0 ])
376+
377+ # 1. Build the dot expression. e.g.: waku_is_onlineReq.processReq
378+ let dotExpr = newTree (nnkDotExpr, reqName, ident " processReq" )
379+
380+ # 2. Build the call node with dotExpr as callee
381+ let callNode = newTree (nnkCall, dotExpr)
382+ for arg in argsList:
383+ callNode.add (arg)
384+
385+ # Proc body
386+ let ffiBody = newStmtList (
387+ quote do :
388+ initializeLibrary ()
389+ if not isNil (ctx):
390+ ctx[].userData = userData
391+ if isNil (callback):
392+ return RET_MISSING_CALLBACK
393+ )
394+
395+ ffiBody.add (callNode)
396+
397+ let ffiProc = newProc (
398+ name = procName,
399+ params = newParams,
400+ body = ffiBody,
401+ pragmas = newTree (nnkPragma, ident " dynlib" , ident " exportc" , ident " cdecl" ),
402+ )
403+
404+ var anonymousProcNode = newProc (
405+ name = newEmptyNode (), # anonymous proc
406+ params = userParams,
407+ body = newStmtList (bodyNode),
408+ pragmas = newTree (nnkPragma, ident " async" ),
409+ )
410+
411+ # registerReqFFI wrapper
412+ let registerReq = quote:
413+ registerReqFFI (`reqName`, `paramIdent`: `paramType`):
414+ `anonymousProcNode`
415+
416+ result = newStmtList (registerReq, ffiProc)
0 commit comments