From 7f6afa9e9b554799cf9a39d0f8cc7d35e47a2cb4 Mon Sep 17 00:00:00 2001 From: Alexander Ivanov Date: Tue, 19 Dec 2017 13:57:37 +0200 Subject: [PATCH 1/4] Make asyncjs Future[void] play nicely with last line discardable calls --- lib/js/asyncjs.nim | 32 +++++++++++++++++++++++++++++--- tests/js/tasync.nim | 9 +++++++-- 2 files changed, 36 insertions(+), 5 deletions(-) diff --git a/lib/js/asyncjs.nim b/lib/js/asyncjs.nim index bde3d787f..73dbfb1e7 100644 --- a/lib/js/asyncjs.nim +++ b/lib/js/asyncjs.nim @@ -83,20 +83,46 @@ proc replaceReturn(node: var NimNode) = replaceReturn(son) inc z +proc isFutureVoid(node: NimNode): bool = + result = node.kind == nnkBracketExpr and + node[0].kind == nnkIdent and $node[0] == "Future" and + node[1].kind == nnkIdent and $node[1] == "void" + proc generateJsasync(arg: NimNode): NimNode = assert arg.kind == nnkProcDef result = arg + var isVoid = false if arg.params[0].kind == nnkEmpty: result.params[0] = nnkBracketExpr.newTree(ident("Future"), ident("void")) + isVoid = true + elif isFutureVoid(arg.params[0]): + isVoid = true var code = result.body replaceReturn(code) result.body = nnkStmtList.newTree() - var q = quote: + + var awaitFunction = quote: proc await[T](f: Future[T]): T {.importcpp: "(await #)".} - proc jsResolve[T](a: T): Future[T] {.importcpp: "#".} - result.body.add(q) + result.body.add(awaitFunction) + + var resolve: NimNode + var jsResolveNode = ident("jsResolve") + if isVoid: + resolve = quote: + var `jsResolveNode` {.importcpp: "undefined".}: Future[void] + else: + resolve = quote: + proc jsResolve[T](a: T): Future[T] {.importcpp: "#".} + result.body.add(resolve) + for child in code: result.body.add(child) + + if isVoid: + var voidFix = quote: + return `jsResolveNode` + result.body.add(voidFix) + result.pragma = quote: {.codegenDecl: "async function $2($3)".} diff --git a/tests/js/tasync.nim b/tests/js/tasync.nim index a164827d2..8cc972a62 100644 --- a/tests/js/tasync.nim +++ b/tests/js/tasync.nim @@ -3,6 +3,7 @@ discard """ output: ''' 0 x +e ''' """ @@ -12,15 +13,19 @@ import asyncjs # for js proc y(e: int): Future[string] -proc x(e: int) {.async.} = +proc e: int {.discardable.} = + echo "e" + return 2 + +proc x(e: int): Future[void] {.async.} = var s = await y(e) echo s + e() proc y(e: int): Future[string] {.async.} = echo 0 return "x" - discard x(2) From b3dfc93beee2ac47a907ea77c1ed2da84ba4b672 Mon Sep 17 00:00:00 2001 From: Alexander Ivanov Date: Tue, 19 Dec 2017 20:50:37 +0200 Subject: [PATCH 2/4] Fix forward --- lib/js/asyncjs.nim | 31 ++++++++++++++++++------------- 1 file changed, 18 insertions(+), 13 deletions(-) diff --git a/lib/js/asyncjs.nim b/lib/js/asyncjs.nim index 73dbfb1e7..c99170a49 100644 --- a/lib/js/asyncjs.nim +++ b/lib/js/asyncjs.nim @@ -92,33 +92,37 @@ proc generateJsasync(arg: NimNode): NimNode = assert arg.kind == nnkProcDef result = arg var isVoid = false + var jsResolveNode = ident("jsResolve") + if arg.params[0].kind == nnkEmpty: result.params[0] = nnkBracketExpr.newTree(ident("Future"), ident("void")) isVoid = true elif isFutureVoid(arg.params[0]): isVoid = true + var code = result.body replaceReturn(code) result.body = nnkStmtList.newTree() - var awaitFunction = quote: - proc await[T](f: Future[T]): T {.importcpp: "(await #)".} - result.body.add(awaitFunction) + if len(code) > 0: + var awaitFunction = quote: + proc await[T](f: Future[T]): T {.importcpp: "(await #)".} + result.body.add(awaitFunction) - var resolve: NimNode - var jsResolveNode = ident("jsResolve") - if isVoid: - resolve = quote: - var `jsResolveNode` {.importcpp: "undefined".}: Future[void] + var resolve: NimNode + if isVoid: + resolve = quote: + var `jsResolveNode` {.importcpp: "undefined".}: Future[void] + else: + resolve = quote: + proc jsResolve[T](a: T): Future[T] {.importcpp: "#".} + result.body.add(resolve) else: - resolve = quote: - proc jsResolve[T](a: T): Future[T] {.importcpp: "#".} - result.body.add(resolve) - + result.body = newEmptyNode() for child in code: result.body.add(child) - if isVoid: + if len(code) > 0 and isVoid: var voidFix = quote: return `jsResolveNode` result.body.add(voidFix) @@ -126,6 +130,7 @@ proc generateJsasync(arg: NimNode): NimNode = result.pragma = quote: {.codegenDecl: "async function $2($3)".} + macro async*(arg: untyped): untyped = ## Macro which converts normal procedures into ## javascript-compatible async procedures From 7b495e23d453c6528c9eee3ac8ae6982744ef403 Mon Sep 17 00:00:00 2001 From: Alexander Ivanov Date: Wed, 20 Dec 2017 14:09:02 +0200 Subject: [PATCH 3/4] Fix the forward test --- tests/js/tasync.nim | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/tests/js/tasync.nim b/tests/js/tasync.nim index 8cc972a62..34ef97b8b 100644 --- a/tests/js/tasync.nim +++ b/tests/js/tasync.nim @@ -1,7 +1,6 @@ discard """ disabled: true output: ''' -0 x e ''' @@ -11,7 +10,7 @@ import asyncjs # demonstrate forward definition # for js -proc y(e: int): Future[string] +proc y(e: int): Future[string] {.async.} proc e: int {.discardable.} = echo "e" @@ -23,8 +22,10 @@ proc x(e: int): Future[void] {.async.} = e() proc y(e: int): Future[string] {.async.} = - echo 0 - return "x" + if e > 0: + return await y(0) + else: + return "x" discard x(2) From eba544996d5629943dbf84c0eeedaf5b958d6363 Mon Sep 17 00:00:00 2001 From: Alexander Ivanov Date: Wed, 20 Dec 2017 14:11:22 +0200 Subject: [PATCH 4/4] Fix docs! --- lib/js/asyncjs.nim | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/js/asyncjs.nim b/lib/js/asyncjs.nim index c99170a49..ec410ee39 100644 --- a/lib/js/asyncjs.nim +++ b/lib/js/asyncjs.nim @@ -44,10 +44,10 @@ ## resolve(game) ## return promise ## -## Forward definitions work properly, you just don't need to add the ``{.async.}`` pragma: +## Forward definitions work properly, you just need to always add the ``{.async.}`` pragma: ## ## .. code-block:: nim -## proc loadGame(name: string): Future[Game] +## proc loadGame(name: string): Future[Game] {.async.} ## ## JavaScript compatibility ## ~~~~~~~~~~~~~~~~~~~~~~~~~