diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/pure/asyncmacro.nim | 162 |
1 files changed, 30 insertions, 132 deletions
diff --git a/lib/pure/asyncmacro.nim b/lib/pure/asyncmacro.nim index 4faddb4f8..c82d24d9a 100644 --- a/lib/pure/asyncmacro.nim +++ b/lib/pure/asyncmacro.nim @@ -11,17 +11,6 @@ import macros, strutils, asyncfutures -proc skipUntilStmtList(node: NimNode): NimNode {.compileTime.} = - # Skips a nest of StmtList's. - result = node - if node[0].kind == nnkStmtList: - result = skipUntilStmtList(node[0]) - -proc skipStmtList(node: NimNode): NimNode {.compileTime.} = - result = node - if node[0].kind == nnkStmtList: - result = node[0] - template createCb(retFutureSym, iteratorNameSym, strName, identName, futureVarCompletions: untyped) = bind finished @@ -58,31 +47,6 @@ template createCb(retFutureSym, iteratorNameSym, retFutUnown.fail(getCurrentException()) identName() -template useVar(result: var NimNode, futureVarNode: NimNode, valueReceiver, - rootReceiver: untyped, fromNode: NimNode) = - ## Params: - ## futureVarNode: The NimNode which is a symbol identifying the Future[T] - ## variable to yield. - ## fromNode: Used for better debug information (to give context). - ## valueReceiver: The node which defines an expression that retrieves the - ## future's value. - ## - ## rootReceiver: ??? TODO - # -> yield future<x> - result.add newNimNode(nnkYieldStmt, fromNode).add(futureVarNode) - # -> future<x>.read - valueReceiver = newDotExpr(futureVarNode, newIdentNode("read")) - result.add rootReceiver - -template createVar(result: var NimNode, futSymName: string, - asyncProc: NimNode, - valueReceiver, rootReceiver: untyped, - fromNode: NimNode) = - result = newNimNode(nnkStmtList, fromNode) - var futSym = genSym(nskVar, "future") - result.add newVarStmt(futSym, asyncProc) # -> var future<x> = y - useVar(result, futSym, valueReceiver, rootReceiver, fromNode) - proc createFutureVarCompletions(futureVarIdents: seq[NimNode], fromNode: NimNode): NimNode {.compileTime.} = result = newNimNode(nnkStmtList, fromNode) @@ -128,51 +92,6 @@ proc processBody(node, retFutureSym: NimNode, result.add newNimNode(nnkReturnStmt, node).add(newNilLit()) return # Don't process the children of this return stmt - of nnkCommand, nnkCall: - if node[0].eqIdent("await"): - case node[1].kind - of nnkIdent, nnkInfix, nnkDotExpr, nnkCall, nnkCommand: - # await x - # await x or y - # await foo(p, x) - # await foo p, x - var futureValue: NimNode - result.createVar("future" & $node[1][0].toStrLit, node[1], futureValue, - futureValue, node) - else: - error("Invalid node kind in 'await', got: " & $node[1].kind) - elif node.len > 1 and node[1].kind == nnkCommand and - node[1][0].eqIdent("await"): - # foo await x - var newCommand = node - result.createVar("future" & $node[0].toStrLit, node[1][1], newCommand[1], - newCommand, node) - - of nnkVarSection, nnkLetSection: - case node[0][^1].kind - of nnkCommand: - if node[0][^1][0].eqIdent("await"): - # var x = await y - var newVarSection = node # TODO: Should this use copyNimNode? - result.createVar("future" & node[0][0].strVal, node[0][^1][1], - newVarSection[0][^1], newVarSection, node) - else: discard - of nnkAsgn: - case node[1].kind - of nnkCommand: - if node[1][0].eqIdent("await"): - # x = await y - var newAsgn = node - result.createVar("future" & $node[0].toStrLit, node[1][1], newAsgn[1], - newAsgn, node) - else: discard - of nnkDiscardStmt: - # discard await x - if node[0].kind == nnkCommand and - node[0][0].eqIdent("await"): - var newDiscard = node - result.createVar("futureDiscard_" & $toStrLit(node[0][1]), node[0][1], - newDiscard[0], newDiscard, node) of RoutineNodes-{nnkTemplateDef}: # skip all the nested procedure definitions return @@ -182,6 +101,8 @@ proc processBody(node, retFutureSym: NimNode, result[i] = processBody(result[i], retFutureSym, subTypeIsVoid, futureVarIdents) + # echo result.repr + proc getName(node: NimNode): string {.compileTime.} = case node.kind of nnkPostfix: @@ -332,8 +253,24 @@ proc asyncSingleProc(prc: NimNode): NimNode {.compileTime.} = if returnType.kind == nnkEmpty: # Add Future[void] result.params[0] = parseExpr("owned(Future[void])") + + # based on the yglukhov's patch to chronos: https://github.com/status-im/nim-chronos/pull/47 + # however here the overloads are placed inside each expanded async + var awaitDefinition = quote: + template await(f: typed): untyped = + static: + error "await expects Future[T], got " & $typeof(f) + + template await[T](f: Future[T]): auto = + var internalTmpFuture: FutureBase = f + yield internalTmpFuture + (cast[type(f)](internalTmpFuture)).read() + if procBody.kind != nnkEmpty: - result.body = outerProcBody + result.body = quote: + `awaitDefinition` + `outerProcBody` + #echo(treeRepr(result)) #if prcName == "recvLineInto": # echo(toStrLit(result)) @@ -350,50 +287,6 @@ macro async*(prc: untyped): untyped = when defined(nimDumpAsync): echo repr result - -# Multisync -proc emptyNoop[T](x: T): T = - # The ``await``s are replaced by a call to this for simplicity. - when T isnot void: - return x - -proc stripAwait(node: NimNode): NimNode = - ## Strips out all ``await`` commands from a procedure body, replaces them - ## with ``emptyNoop`` for simplicity. - result = node - - let emptyNoopSym = bindSym("emptyNoop") - - case node.kind - of nnkCommand, nnkCall: - if node[0].eqIdent("await"): - node[0] = emptyNoopSym - elif node.len > 1 and node[1].kind == nnkCommand and node[1][0].eqIdent("await"): - # foo await x - node[1][0] = emptyNoopSym - of nnkVarSection, nnkLetSection: - case node[0][^1].kind - of nnkCommand: - if node[0][^1][0].eqIdent("await"): - # var x = await y - node[0][^1][0] = emptyNoopSym - else: discard - of nnkAsgn: - case node[1].kind - of nnkCommand: - if node[1][0].eqIdent("await"): - # x = await y - node[1][0] = emptyNoopSym - else: discard - of nnkDiscardStmt: - # discard await x - if node[0].kind == nnkCommand and node[0][0].eqIdent("await"): - node[0][0] = emptyNoopSym - else: discard - - for i in 0 ..< result.len: - result[i] = stripAwait(result[i]) - proc splitParamType(paramType: NimNode, async: bool): NimNode = result = paramType if paramType.kind == nnkInfix and paramType[0].strVal in ["|", "or"]: @@ -426,8 +319,12 @@ proc splitProc(prc: NimNode): (NimNode, NimNode) = for i in 1 ..< result[0][3].len: # Sync proc (0) -> FormalParams (3) -> IdentDefs, the parameter (i) -> # parameter type (1). - result[0][3][i][1] = splitParamType(result[0][3][i][1], async = false) - result[0][6] = stripAwait(result[0][6]) + result[0][3][i][1] = splitParamType(result[0][3][i][1], async=false) + var multisyncAwait = quote: + template await(value: typed): untyped = + value + + result[0][^1] = nnkStmtList.newTree(multisyncAwait, result[0][^1]) result[1] = prc.copyNimTree() if result[1][3][0].kind == nnkBracketExpr: @@ -447,8 +344,9 @@ macro multisync*(prc: untyped): untyped = result = newStmtList() result.add(asyncSingleProc(asyncPrc)) result.add(sync) + # echo result.repr -proc await*[T](x: T) = - ## The 'await' keyword is also defined here for technical - ## reasons. (Generic symbol lookup prepass.) - {.error: "Await only available within .async".} +# overload for await as a fallback handler, based on the yglukhov's patch to chronos: https://github.com/status-im/nim-chronos/pull/47 +# template await*(f: typed): untyped = + # static: + # error "await only available within {.async.}" \ No newline at end of file |