mirror of
https://github.com/status-im/nim-chronos.git
synced 2025-01-31 05:25:09 +00:00
Add awaitne
command which will have yield
behavior in async cancellation world.
Add tests for both `await` and `awaitne`.
This commit is contained in:
parent
45ca9e1184
commit
8ba4fc9876
@ -6,5 +6,5 @@
|
||||
# Apache License, version 2.0, (LICENSE-APACHEv2)
|
||||
# MIT license (LICENSE-MIT)
|
||||
import chronos/[asyncloop, asyncfutures2, asyncsync, handles, transport,
|
||||
timer]
|
||||
export asyncloop, asyncfutures2, asyncsync, handles, transport, timer
|
||||
timer, version]
|
||||
export asyncloop, asyncfutures2, asyncsync, handles, transport, timer, version
|
||||
|
@ -66,7 +66,7 @@ template createCb(retFutureSym, iteratorNameSym,
|
||||
#{.pop.}
|
||||
|
||||
template useVar(result: var NimNode, futureVarNode: NimNode, valueReceiver,
|
||||
rootReceiver: untyped, fromNode: NimNode) =
|
||||
rootReceiver: untyped, fromNode: NimNode, isawait: bool) =
|
||||
## Params:
|
||||
## futureVarNode: The NimNode which is a symbol identifying the Future[T]
|
||||
## variable to yield.
|
||||
@ -75,16 +75,22 @@ template useVar(result: var NimNode, futureVarNode: NimNode, valueReceiver,
|
||||
## 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
|
||||
if isawait:
|
||||
# -> yield future<x>
|
||||
result.add newNimNode(nnkYieldStmt, fromNode).add(futureVarNode)
|
||||
# -> future<x>.read
|
||||
valueReceiver = newDotExpr(futureVarNode, newIdentNode("read"))
|
||||
result.add rootReceiver
|
||||
else:
|
||||
# -> yield future<x>
|
||||
result.add newNimNode(nnkYieldStmt, fromNode).add(futureVarNode)
|
||||
valueReceiver = futureVarNode
|
||||
result.add rootReceiver
|
||||
|
||||
template createVar(result: var NimNode, futSymName: string,
|
||||
asyncProc: NimNode,
|
||||
valueReceiver, rootReceiver, retFutSym: untyped,
|
||||
fromNode: NimNode) =
|
||||
fromNode: NimNode, isawait: bool) =
|
||||
result = newNimNode(nnkStmtList, fromNode)
|
||||
var futSym = genSym(nskVar, "future")
|
||||
result.add newVarStmt(futSym, asyncProc) # -> var future<x> = y
|
||||
@ -96,7 +102,7 @@ template createVar(result: var NimNode, futSymName: string,
|
||||
),
|
||||
newCall(newIdentNode("FutureBase"), copyNimNode(futSym))
|
||||
)
|
||||
useVar(result, futSym, valueReceiver, rootReceiver, fromNode)
|
||||
useVar(result, futSym, valueReceiver, rootReceiver, fromNode, isawait)
|
||||
|
||||
proc createFutureVarCompletions(futureVarIdents: seq[NimNode],
|
||||
fromNode: NimNode): NimNode {.compileTime.} =
|
||||
@ -144,7 +150,8 @@ 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].kind == nnkIdent and node[0].eqIdent("await"):
|
||||
if node[0].kind == nnkIdent and
|
||||
(node[0].eqIdent("await") or node[0].eqIdent("awaitne")):
|
||||
case node[1].kind
|
||||
of nnkIdent, nnkInfix, nnkDotExpr, nnkCall, nnkCommand:
|
||||
# await x
|
||||
@ -153,41 +160,48 @@ proc processBody(node, retFutureSym: NimNode,
|
||||
# await foo p, x
|
||||
var futureValue: NimNode
|
||||
result.createVar("future" & $node[1][0].toStrLit, node[1], futureValue,
|
||||
futureValue, retFutureSym, node)
|
||||
futureValue, retFutureSym, node,
|
||||
node[0].eqIdent("await"))
|
||||
else:
|
||||
error("Invalid node kind in 'await', got: " & $node[1].kind)
|
||||
elif node.len > 1 and node[1].kind == nnkCommand and
|
||||
node[1][0].kind == nnkIdent and node[1][0].eqIdent("await"):
|
||||
node[1][0].kind == nnkIdent and
|
||||
(node[1][0].eqIdent("await") or node[1][0].eqIdent("awaitne")):
|
||||
# foo await x
|
||||
var newCommand = node
|
||||
result.createVar("future" & $node[0].toStrLit, node[1][1], newCommand[1],
|
||||
newCommand, retFutureSym, node)
|
||||
newCommand, retFutureSym, node,
|
||||
node[1][0].eqIdent("await"))
|
||||
|
||||
of nnkVarSection, nnkLetSection:
|
||||
case node[0][2].kind
|
||||
of nnkCommand:
|
||||
if node[0][2][0].kind == nnkIdent and node[0][2][0].eqIdent("await"):
|
||||
if node[0][2][0].kind == nnkIdent and
|
||||
(node[0][2][0].eqIdent("await") or node[0][2][0].eqIdent("awaitne")):
|
||||
# var x = await y
|
||||
var newVarSection = node # TODO: Should this use copyNimNode?
|
||||
result.createVar("future" & node[0][0].strVal, node[0][2][1],
|
||||
newVarSection[0][2], newVarSection, retFutureSym, node)
|
||||
newVarSection[0][2], newVarSection, retFutureSym, node,
|
||||
node[0][2][0].eqIdent("await"))
|
||||
else: discard
|
||||
of nnkAsgn:
|
||||
case node[1].kind
|
||||
of nnkCommand:
|
||||
if node[1][0].eqIdent("await"):
|
||||
if node[1][0].eqIdent("await") or node[1][0].eqIdent("awaitne"):
|
||||
# x = await y
|
||||
var newAsgn = node
|
||||
result.createVar("future" & $node[0].toStrLit, node[1][1], newAsgn[1],
|
||||
newAsgn, retFutureSym, node)
|
||||
newAsgn, retFutureSym, node,
|
||||
node[1][0].eqIdent("await"))
|
||||
else: discard
|
||||
of nnkDiscardStmt:
|
||||
# discard await x
|
||||
if node[0].kind == nnkCommand and node[0][0].kind == nnkIdent and
|
||||
node[0][0].eqIdent("await"):
|
||||
(node[0][0].eqIdent("await") or node[0][0].eqIdent("awaitne")):
|
||||
var newDiscard = node
|
||||
result.createVar("futureDiscard_" & $toStrLit(node[0][1]), node[0][1],
|
||||
newDiscard[0], newDiscard, retFutureSym, node)
|
||||
newDiscard[0], newDiscard, retFutureSym, node,
|
||||
node[0][0].eqIdent("await"))
|
||||
else: discard
|
||||
|
||||
for i in 0 ..< result.len:
|
||||
|
@ -5,6 +5,6 @@
|
||||
# Licensed under either of
|
||||
# Apache License, version 2.0, (LICENSE-APACHEv2)
|
||||
# MIT license (LICENSE-MIT)
|
||||
import testsync, testsoon, testtime, testfut, testsignal, testaddress,
|
||||
testdatagram, teststream, testserver, testbugs, testnet,
|
||||
import testmacro, testsync, testsoon, testtime, testfut, testsignal,
|
||||
testaddress, testdatagram, teststream, testserver, testbugs, testnet,
|
||||
testasyncstream
|
||||
|
80
tests/testmacro.nim
Normal file
80
tests/testmacro.nim
Normal file
@ -0,0 +1,80 @@
|
||||
# Chronos Test Suite
|
||||
# (c) Copyright 2018-Present
|
||||
# Status Research & Development GmbH
|
||||
#
|
||||
# Licensed under either of
|
||||
# Apache License, version 2.0, (LICENSE-APACHEv2)
|
||||
# MIT license (LICENSE-MIT)
|
||||
import unittest
|
||||
import ../chronos
|
||||
|
||||
proc asyncRetValue(n: int): Future[int] {.async.} =
|
||||
await sleepAsync(n.milliseconds)
|
||||
result = n * 10
|
||||
|
||||
proc asyncRetVoid(n: int) {.async.} =
|
||||
await sleepAsync(n.milliseconds)
|
||||
|
||||
proc asyncRetExceptionValue(n: int): Future[int] {.async.} =
|
||||
await sleepAsync(n.milliseconds)
|
||||
result = n * 10
|
||||
if true:
|
||||
raise newException(ValueError, "Test exception")
|
||||
|
||||
proc asyncRetExceptionVoid(n: int) {.async.} =
|
||||
await sleepAsync(n.milliseconds)
|
||||
if true:
|
||||
raise newException(ValueError, "Test exception")
|
||||
|
||||
proc testAwait(): Future[bool] {.async.} =
|
||||
var res: int
|
||||
await asyncRetVoid(100)
|
||||
res = await asyncRetValue(100)
|
||||
if res != 1000:
|
||||
return false
|
||||
if (await asyncRetValue(100)) != 1000:
|
||||
return false
|
||||
try:
|
||||
await asyncRetExceptionVoid(100)
|
||||
return false
|
||||
except ValueError:
|
||||
discard
|
||||
res = 0
|
||||
try:
|
||||
var res = await asyncRetExceptionValue(100)
|
||||
return false
|
||||
except ValueError:
|
||||
discard
|
||||
if res != 0:
|
||||
return false
|
||||
return true
|
||||
|
||||
proc testAwaitne(): Future[bool] {.async.} =
|
||||
var res1: Future[void]
|
||||
var res2: Future[int]
|
||||
|
||||
res1 = awaitne asyncRetVoid(100)
|
||||
res2 = awaitne asyncRetValue(100)
|
||||
if res1.failed():
|
||||
return false
|
||||
if res2.read() != 1000:
|
||||
return false
|
||||
|
||||
res1 = awaitne asyncRetExceptionVoid(100)
|
||||
if not(res1.failed()):
|
||||
return false
|
||||
|
||||
res2 = awaitne asyncRetExceptionValue(100)
|
||||
try:
|
||||
var res = res2.read()
|
||||
return false
|
||||
except ValueError:
|
||||
discard
|
||||
|
||||
return true
|
||||
|
||||
suite "Macro transformations test suite":
|
||||
test "`await` command test":
|
||||
check waitFor(testAwait()) == true
|
||||
test "`awaitne` command test":
|
||||
check waitFor(testAwaitne()) == true
|
Loading…
x
Reference in New Issue
Block a user