asyncmacro: code cleanups (#392)
* prefer `let` * prefer expressions * renames
This commit is contained in:
parent
4c07da6abb
commit
2fa6df0880
|
@ -11,12 +11,13 @@ import std/[macros]
|
||||||
|
|
||||||
proc skipUntilStmtList(node: NimNode): NimNode {.compileTime.} =
|
proc skipUntilStmtList(node: NimNode): NimNode {.compileTime.} =
|
||||||
# Skips a nest of StmtList's.
|
# Skips a nest of StmtList's.
|
||||||
result = node
|
|
||||||
if node[0].kind == nnkStmtList:
|
if node[0].kind == nnkStmtList:
|
||||||
result = skipUntilStmtList(node[0])
|
skipUntilStmtList(node[0])
|
||||||
|
else:
|
||||||
|
node
|
||||||
|
|
||||||
proc processBody(node, retFutureSym: NimNode,
|
proc processBody(node, retFutureSym: NimNode,
|
||||||
subTypeIsVoid: bool): NimNode {.compileTime.} =
|
baseTypeIsVoid: bool): NimNode {.compileTime.} =
|
||||||
#echo(node.treeRepr)
|
#echo(node.treeRepr)
|
||||||
result = node
|
result = node
|
||||||
case node.kind
|
case node.kind
|
||||||
|
@ -25,13 +26,13 @@ proc processBody(node, retFutureSym: NimNode,
|
||||||
|
|
||||||
# As I've painfully found out, the order here really DOES matter.
|
# As I've painfully found out, the order here really DOES matter.
|
||||||
if node[0].kind == nnkEmpty:
|
if node[0].kind == nnkEmpty:
|
||||||
if not subTypeIsVoid:
|
if not baseTypeIsVoid:
|
||||||
result.add newCall(newIdentNode("complete"), retFutureSym,
|
result.add newCall(newIdentNode("complete"), retFutureSym,
|
||||||
newIdentNode("result"))
|
newIdentNode("result"))
|
||||||
else:
|
else:
|
||||||
result.add newCall(newIdentNode("complete"), retFutureSym)
|
result.add newCall(newIdentNode("complete"), retFutureSym)
|
||||||
else:
|
else:
|
||||||
let x = node[0].processBody(retFutureSym, subTypeIsVoid)
|
let x = node[0].processBody(retFutureSym, baseTypeIsVoid)
|
||||||
if x.kind == nnkYieldStmt: result.add x
|
if x.kind == nnkYieldStmt: result.add x
|
||||||
else:
|
else:
|
||||||
result.add newCall(newIdentNode("complete"), retFutureSym, x)
|
result.add newCall(newIdentNode("complete"), retFutureSym, x)
|
||||||
|
@ -47,7 +48,7 @@ proc processBody(node, retFutureSym: NimNode,
|
||||||
# We must not transform nested procedures of any form, otherwise
|
# We must not transform nested procedures of any form, otherwise
|
||||||
# `retFutureSym` will be used for all nested procedures as their own
|
# `retFutureSym` will be used for all nested procedures as their own
|
||||||
# `retFuture`.
|
# `retFuture`.
|
||||||
result[i] = processBody(result[i], retFutureSym, subTypeIsVoid)
|
result[i] = processBody(result[i], retFutureSym, baseTypeIsVoid)
|
||||||
|
|
||||||
proc getName(node: NimNode): string {.compileTime.} =
|
proc getName(node: NimNode): string {.compileTime.} =
|
||||||
case node.kind
|
case node.kind
|
||||||
|
@ -62,11 +63,8 @@ proc getName(node: NimNode): string {.compileTime.} =
|
||||||
else:
|
else:
|
||||||
error("Unknown name.")
|
error("Unknown name.")
|
||||||
|
|
||||||
proc isInvalidReturnType(typeName: string): bool =
|
|
||||||
return typeName notin ["Future"] #, "FutureStream"]
|
|
||||||
|
|
||||||
proc verifyReturnType(typeName: string) {.compileTime.} =
|
proc verifyReturnType(typeName: string) {.compileTime.} =
|
||||||
if typeName.isInvalidReturnType:
|
if typeName != "Future":
|
||||||
error("Expected return type of 'Future' got '" & typeName & "'")
|
error("Expected return type of 'Future' got '" & typeName & "'")
|
||||||
|
|
||||||
macro unsupported(s: static[string]): untyped =
|
macro unsupported(s: static[string]): untyped =
|
||||||
|
@ -112,7 +110,7 @@ proc asyncSingleProc(prc: NimNode): NimNode {.compileTime.} =
|
||||||
else:
|
else:
|
||||||
raiseAssert("Unhandled async return type: " & $prc.kind)
|
raiseAssert("Unhandled async return type: " & $prc.kind)
|
||||||
|
|
||||||
let subtypeIsVoid = baseType.eqIdent("void")
|
let baseTypeIsVoid = baseType.eqIdent("void")
|
||||||
|
|
||||||
if prc.kind in {nnkProcDef, nnkLambda, nnkMethodDef, nnkDo}:
|
if prc.kind in {nnkProcDef, nnkLambda, nnkMethodDef, nnkDo}:
|
||||||
let
|
let
|
||||||
|
@ -123,57 +121,64 @@ proc asyncSingleProc(prc: NimNode): NimNode {.compileTime.} =
|
||||||
if prc.body.len > 0 and prc.body[0].kind == nnkCommentStmt:
|
if prc.body.len > 0 and prc.body[0].kind == nnkCommentStmt:
|
||||||
outerProcBody.add(prc.body[0])
|
outerProcBody.add(prc.body[0])
|
||||||
|
|
||||||
# -> iterator nameIter(chronosInternalRetFuture: Future[T]): FutureBase {.closure.} =
|
|
||||||
# -> {.push warning[resultshadowed]: off.}
|
|
||||||
# -> var result: T
|
|
||||||
# -> {.pop.}
|
|
||||||
# -> <proc_body>
|
|
||||||
# -> complete(chronosInternalRetFuture, result)
|
|
||||||
let
|
let
|
||||||
internalFutureSym = ident "chronosInternalRetFuture"
|
internalFutureSym = ident "chronosInternalRetFuture"
|
||||||
iteratorNameSym = genSym(nskIterator, $prcName)
|
procBody = prc.body.processBody(internalFutureSym, baseTypeIsVoid)
|
||||||
var
|
|
||||||
procBody = prc.body.processBody(internalFutureSym, subtypeIsVoid)
|
|
||||||
|
|
||||||
# don't do anything with forward bodies (empty)
|
# don't do anything with forward bodies (empty)
|
||||||
if procBody.kind != nnkEmpty:
|
if procBody.kind != nnkEmpty:
|
||||||
if subtypeIsVoid:
|
# fix #13899, `defer` should not escape its original scope
|
||||||
|
let procBodyBlck =
|
||||||
|
newStmtList(newTree(nnkBlockStmt, newEmptyNode(), procBody))
|
||||||
|
|
||||||
|
# Avoid too much quote do to not lose original line numbers
|
||||||
|
let closureBody = if baseTypeIsVoid:
|
||||||
let resultTemplate = quote do:
|
let resultTemplate = quote do:
|
||||||
template result: auto {.used.} =
|
template result: auto {.used.} =
|
||||||
{.fatal: "You should not reference the `result` variable inside" &
|
{.fatal: "You should not reference the `result` variable inside" &
|
||||||
" a void async proc".}
|
" a void async proc".}
|
||||||
procBody = newStmtList(resultTemplate, procBody)
|
|
||||||
|
|
||||||
# fix #13899, `defer` should not escape its original scope
|
|
||||||
procBody = newStmtList(newTree(nnkBlockStmt, newEmptyNode(), procBody))
|
|
||||||
|
|
||||||
if not subtypeIsVoid:
|
|
||||||
procBody.insert(0, newNimNode(nnkPragma).add(newIdentNode("push"),
|
|
||||||
newNimNode(nnkExprColonExpr).add(newNimNode(nnkBracketExpr).add(
|
|
||||||
newIdentNode("warning"), newIdentNode("resultshadowed")),
|
|
||||||
newIdentNode("off")))) # -> {.push warning[resultshadowed]: off.}
|
|
||||||
|
|
||||||
procBody.insert(1, newNimNode(nnkVarSection, prc.body).add(
|
|
||||||
newIdentDefs(newIdentNode("result"), baseType))) # -> var result: T
|
|
||||||
|
|
||||||
procBody.insert(2, newNimNode(nnkPragma).add(
|
|
||||||
newIdentNode("pop"))) # -> {.pop.})
|
|
||||||
|
|
||||||
procBody.add(
|
|
||||||
newCall(newIdentNode("complete"),
|
|
||||||
internalFutureSym, newIdentNode("result"))) # -> complete(chronosInternalRetFuture, result)
|
|
||||||
else:
|
|
||||||
# -> complete(chronosInternalRetFuture)
|
# -> complete(chronosInternalRetFuture)
|
||||||
procBody.add(newCall(newIdentNode("complete"), internalFutureSym))
|
let complete =
|
||||||
|
newCall(newIdentNode("complete"), internalFutureSym)
|
||||||
|
|
||||||
|
newStmtList(resultTemplate, procBodyBlck, complete)
|
||||||
|
else:
|
||||||
|
# -> iterator nameIter(chronosInternalRetFuture: Future[T]): FutureBase {.closure.} =
|
||||||
|
# -> {.push warning[resultshadowed]: off.}
|
||||||
|
# -> var result: T
|
||||||
|
# -> {.pop.}
|
||||||
|
# -> <proc_body>
|
||||||
|
# -> complete(chronosInternalRetFuture, result)
|
||||||
|
newStmtList(
|
||||||
|
# -> {.push warning[resultshadowed]: off.}
|
||||||
|
newNimNode(nnkPragma).add(newIdentNode("push"),
|
||||||
|
newNimNode(nnkExprColonExpr).add(newNimNode(nnkBracketExpr).add(
|
||||||
|
newIdentNode("warning"), newIdentNode("resultshadowed")),
|
||||||
|
newIdentNode("off"))),
|
||||||
|
|
||||||
|
# -> var result: T
|
||||||
|
newNimNode(nnkVarSection, prc.body).add(
|
||||||
|
newIdentDefs(newIdentNode("result"), baseType)),
|
||||||
|
|
||||||
|
# -> {.pop.})
|
||||||
|
newNimNode(nnkPragma).add(
|
||||||
|
newIdentNode("pop")),
|
||||||
|
|
||||||
|
procBodyBlck,
|
||||||
|
|
||||||
|
# -> complete(chronosInternalRetFuture, result)
|
||||||
|
newCall(newIdentNode("complete"),
|
||||||
|
internalFutureSym, newIdentNode("result")))
|
||||||
|
|
||||||
let
|
let
|
||||||
internalFutureType =
|
internalFutureType =
|
||||||
if subtypeIsVoid:
|
if baseTypeIsVoid:
|
||||||
newNimNode(nnkBracketExpr, prc).add(newIdentNode("Future")).add(newIdentNode("void"))
|
newNimNode(nnkBracketExpr, prc).add(newIdentNode("Future")).add(newIdentNode("void"))
|
||||||
else: returnType
|
else: returnType
|
||||||
internalFutureParameter = nnkIdentDefs.newTree(internalFutureSym, internalFutureType, newEmptyNode())
|
internalFutureParameter = nnkIdentDefs.newTree(internalFutureSym, internalFutureType, newEmptyNode())
|
||||||
|
iteratorNameSym = genSym(nskIterator, $prcName)
|
||||||
closureIterator = newProc(iteratorNameSym, [newIdentNode("FutureBase"), internalFutureParameter],
|
closureIterator = newProc(iteratorNameSym, [newIdentNode("FutureBase"), internalFutureParameter],
|
||||||
procBody, nnkIteratorDef)
|
closureBody, nnkIteratorDef)
|
||||||
|
|
||||||
closureIterator.pragma = newNimNode(nnkPragma, lineInfoFrom=prc.body)
|
closureIterator.pragma = newNimNode(nnkPragma, lineInfoFrom=prc.body)
|
||||||
closureIterator.addPragma(newIdentNode("closure"))
|
closureIterator.addPragma(newIdentNode("closure"))
|
||||||
|
@ -211,21 +216,17 @@ proc asyncSingleProc(prc: NimNode): NimNode {.compileTime.} =
|
||||||
closureIterator.addPragma(newIdentNode("gcsafe"))
|
closureIterator.addPragma(newIdentNode("gcsafe"))
|
||||||
outerProcBody.add(closureIterator)
|
outerProcBody.add(closureIterator)
|
||||||
|
|
||||||
# -> var resultFuture = newFuture[T]()
|
# -> let resultFuture = newFuture[T]()
|
||||||
# declared at the end to be sure that the closure
|
# declared at the end to be sure that the closure
|
||||||
# doesn't reference it, avoid cyclic ref (#203)
|
# doesn't reference it, avoid cyclic ref (#203)
|
||||||
var retFutureSym = ident "resultFuture"
|
let
|
||||||
var subRetType =
|
retFutureSym = ident "resultFuture"
|
||||||
if returnType.kind == nnkEmpty:
|
|
||||||
newIdentNode("void")
|
|
||||||
else:
|
|
||||||
baseType
|
|
||||||
# Do not change this code to `quote do` version because `instantiationInfo`
|
# Do not change this code to `quote do` version because `instantiationInfo`
|
||||||
# will be broken for `newFuture()` call.
|
# will be broken for `newFuture()` call.
|
||||||
outerProcBody.add(
|
outerProcBody.add(
|
||||||
newVarStmt(
|
newLetStmt(
|
||||||
retFutureSym,
|
retFutureSym,
|
||||||
newCall(newTree(nnkBracketExpr, ident "newFuture", subRetType),
|
newCall(newTree(nnkBracketExpr, ident "newFuture", baseType),
|
||||||
newLit(prcName))
|
newLit(prcName))
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
@ -262,7 +263,7 @@ proc asyncSingleProc(prc: NimNode): NimNode {.compileTime.} =
|
||||||
raises
|
raises
|
||||||
))
|
))
|
||||||
|
|
||||||
if subtypeIsVoid:
|
if baseTypeIsVoid:
|
||||||
# Add discardable pragma.
|
# Add discardable pragma.
|
||||||
if returnType.kind == nnkEmpty:
|
if returnType.kind == nnkEmpty:
|
||||||
# Add Future[void]
|
# Add Future[void]
|
||||||
|
|
Loading…
Reference in New Issue