Merge pull request #7973 from yglukhov/async-try-ripout

Async try ripout
This commit is contained in:
Dominik Picheta 2018-06-06 20:15:17 +01:00 • committed by GitHub
commit 68378c857d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 30 additions and 113 deletions

View file

@ -62,52 +62,6 @@ template createCb(retFutureSym, iteratorNameSym,
identName() identName()
#{.pop.} #{.pop.}
proc generateExceptionCheck(futSym,
tryStmt, rootReceiver, fromNode: NimNode): NimNode {.compileTime.} =
if tryStmt.kind == nnkNilLit:
result = rootReceiver
else:
var exceptionChecks: seq[tuple[cond, body: NimNode]] = @[]
let errorNode = newDotExpr(futSym, newIdentNode("error"))
for i in 1 ..< tryStmt.len:
let exceptBranch = tryStmt[i]
if exceptBranch[0].kind == nnkStmtList:
exceptionChecks.add((newIdentNode("true"), exceptBranch[0]))
else:
var exceptIdentCount = 0
var ifCond: NimNode
for i in 0 ..< exceptBranch.len:
let child = exceptBranch[i]
if child.kind == nnkIdent:
let cond = infix(errorNode, "of", child)
if exceptIdentCount == 0:
ifCond = cond
else:
ifCond = infix(ifCond, "or", cond)
else:
break
exceptIdentCount.inc
expectKind(exceptBranch[exceptIdentCount], nnkStmtList)
exceptionChecks.add((ifCond, exceptBranch[exceptIdentCount]))
# -> -> else: raise futSym.error
exceptionChecks.add((newIdentNode("true"),
newNimNode(nnkRaiseStmt).add(errorNode)))
# Read the future if there is no error.
# -> else: futSym.read
let elseNode = newNimNode(nnkElse, fromNode)
elseNode.add newNimNode(nnkStmtList, fromNode)
elseNode[0].add rootReceiver
let ifBody = newStmtList()
ifBody.add newCall(newIdentNode("setCurrentException"), errorNode)
ifBody.add newIfStmt(exceptionChecks)
ifBody.add newCall(newIdentNode("setCurrentException"), newNilLit())
result = newIfStmt(
(newDotExpr(futSym, newIdentNode("failed")), ifBody)
)
result.add elseNode
template useVar(result: var NimNode, futureVarNode: NimNode, valueReceiver, template useVar(result: var NimNode, futureVarNode: NimNode, valueReceiver,
rootReceiver: untyped, fromNode: NimNode) = rootReceiver: untyped, fromNode: NimNode) =
@ -123,8 +77,7 @@ template useVar(result: var NimNode, futureVarNode: NimNode, valueReceiver,
result.add newNimNode(nnkYieldStmt, fromNode).add(futureVarNode) result.add newNimNode(nnkYieldStmt, fromNode).add(futureVarNode)
# -> future<x>.read # -> future<x>.read
valueReceiver = newDotExpr(futureVarNode, newIdentNode("read")) valueReceiver = newDotExpr(futureVarNode, newIdentNode("read"))
result.add generateExceptionCheck(futureVarNode, tryStmt, rootReceiver, result.add rootReceiver
fromNode)
template createVar(result: var NimNode, futSymName: string, template createVar(result: var NimNode, futSymName: string,
asyncProc: NimNode, asyncProc: NimNode,
@ -154,8 +107,8 @@ proc createFutureVarCompletions(futureVarIdents: seq[NimNode],
) )
proc processBody(node, retFutureSym: NimNode, proc processBody(node, retFutureSym: NimNode,
subTypeIsVoid: bool, futureVarIdents: seq[NimNode], subTypeIsVoid: bool,
tryStmt: NimNode): NimNode {.compileTime.} = futureVarIdents: seq[NimNode]): NimNode {.compileTime.} =
#echo(node.treeRepr) #echo(node.treeRepr)
result = node result = node
case node.kind case node.kind
@ -173,7 +126,7 @@ proc processBody(node, retFutureSym: NimNode,
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, subTypeIsVoid,
futureVarIdents, tryStmt) futureVarIdents)
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)
@ -224,63 +177,11 @@ proc processBody(node, retFutureSym: NimNode,
var newDiscard = node var newDiscard = node
result.createVar("futureDiscard_" & $toStrLit(node[0][1]), node[0][1], result.createVar("futureDiscard_" & $toStrLit(node[0][1]), node[0][1],
newDiscard[0], newDiscard, node) newDiscard[0], newDiscard, node)
of nnkTryStmt:
# try: await x; except: ...
result = newNimNode(nnkStmtList, node)
template wrapInTry(n, tryBody: untyped) =
var temp = n
n[0] = tryBody
tryBody = temp
# Transform ``except`` body.
# TODO: Could we perform some ``await`` transformation here to get it
# working in ``except``?
tryBody[1] = processBody(n[1], retFutureSym, subTypeIsVoid,
futureVarIdents, nil)
proc processForTry(n: NimNode, i: var int,
res: NimNode): bool {.compileTime.} =
## Transforms the body of the tryStmt. Does not transform the
## body in ``except``.
## Returns true if the tryStmt node was transformed into an ifStmt.
result = false
var skipped = n.skipStmtList()
while i < skipped.len:
var processed = processBody(skipped[i], retFutureSym,
subTypeIsVoid, futureVarIdents, n)
# Check if we transformed the node into an exception check.
# This suggests skipped[i] contains ``await``.
if processed.kind != skipped[i].kind or processed.len != skipped[i].len:
processed = processed.skipUntilStmtList()
expectKind(processed, nnkStmtList)
expectKind(processed[2][1], nnkElse)
i.inc
if not processForTry(n, i, processed[2][1][0]):
# We need to wrap the nnkElse nodes back into a tryStmt.
# As they are executed if an exception does not happen
# inside the awaited future.
# The following code will wrap the nodes inside the
# original tryStmt.
wrapInTry(n, processed[2][1][0])
res.add processed
result = true
else:
res.add skipped[i]
i.inc
var i = 0
if not processForTry(node, i, result):
# If the tryStmt hasn't been transformed we can just put the body
# back into it.
wrapInTry(node, result)
return
else: discard else: discard
for i in 0 ..< result.len: for i in 0 ..< result.len:
result[i] = processBody(result[i], retFutureSym, subTypeIsVoid, result[i] = processBody(result[i], retFutureSym, subTypeIsVoid,
futureVarIdents, nil) futureVarIdents)
proc getName(node: NimNode): string {.compileTime.} = proc getName(node: NimNode): string {.compileTime.} =
case node.kind case node.kind
@ -362,7 +263,7 @@ proc asyncSingleProc(prc: NimNode): NimNode {.compileTime.} =
# -> complete(retFuture, result) # -> complete(retFuture, result)
var iteratorNameSym = genSym(nskIterator, $prcName & "Iter") var iteratorNameSym = genSym(nskIterator, $prcName & "Iter")
var procBody = prc.body.processBody(retFutureSym, subtypeIsVoid, var procBody = prc.body.processBody(retFutureSym, subtypeIsVoid,
futureVarIdents, nil) futureVarIdents)
# don't do anything with forward bodies (empty) # don't do anything with forward bodies (empty)
if procBody.kind != nnkEmpty: if procBody.kind != nnkEmpty:
procBody.add(createFutureVarCompletions(futureVarIdents, nil)) procBody.add(createFutureVarCompletions(futureVarIdents, nil))

View file

@ -3,7 +3,7 @@ discard """
disabled: "windows" disabled: "windows"
output: "Matched" output: "Matched"
""" """
import asyncdispatch import asyncdispatch, strutils
# Tests to ensure our exception trace backs are friendly. # Tests to ensure our exception trace backs are friendly.
@ -117,10 +117,26 @@ Exception message: bar failure
Exception type: Exception type:
""" """
if result.match(re(expected)): let resLines = splitLines(result.strip)
echo("Matched") let expLines = splitLines(expected.strip)
else:
echo("Not matched!") if resLines.len != expLines.len:
echo("Not matched! Wrong number of lines!")
echo() echo()
echo(result) echo(result)
quit(QuitFailure) quit(QuitFailure)
var ok = true
for i in 0 ..< resLines.len:
if not resLines[i].match(re(expLines[i])):
echo "Not matched! Line ", i + 1
echo "Expected:"
echo expLines[i]
echo "Actual:"
echo resLines[i]
ok = false
if ok:
echo("Matched")
else:
quit(QuitFailure)

View file

@ -9,7 +9,7 @@ Multiple except branches
Multiple except branches 2 Multiple except branches 2
''' '''
""" """
import asyncdispatch import asyncdispatch, strutils
# Here we are testing the ability to catch exceptions. # Here we are testing the ability to catch exceptions.
@ -22,7 +22,7 @@ proc catch() {.async.} =
try: try:
await foobar() await foobar()
except: except:
echo("Generic except: ", getCurrentExceptionMsg()) echo("Generic except: ", getCurrentExceptionMsg().splitLines[0])
try: try:
await foobar() await foobar()

View file

@ -1,7 +1,7 @@
discard """ discard """
file: "tasynctry2.nim" file: "tasynctry2.nim"
errormsg: "\'yield\' cannot be used within \'try\' in a non-inlined iterator" errormsg: "\'yield\' cannot be used within \'try\' in a non-inlined iterator"
line: 17 line: 14
""" """
import asyncdispatch import asyncdispatch