diff --git a/changelog.md b/changelog.md index f32d6f19f6..287bce3dad 100644 --- a/changelog.md +++ b/changelog.md @@ -116,6 +116,7 @@ - Add `random.gauss`, that uses the ratio of uniforms method of sampling from a Gaussian distribution. - Add `typetraits.elementType` to get element type of an iterable. - `typetraits.$`: `$(int,)` is now `"(int,)"`; `$tuple[]` is now `"tuple[]"` +- add `macros.extractDocCommentsAndRunnables` helper - `strformat.fmt` and `strformat.&` support `= specifier`. `fmt"{expr=}"` now expands to `fmt"expr={expr}"`. diff --git a/lib/core/macros.nim b/lib/core/macros.nim index 5be3a2cce0..8387072803 100644 --- a/lib/core/macros.nim +++ b/lib/core/macros.nim @@ -1692,3 +1692,39 @@ when defined(nimMacrosSizealignof): proc isExported*(n: NimNode): bool {.noSideEffect.} = ## Returns whether the symbol is exported or not. + +proc extractDocCommentsAndRunnables*(n: NimNode): NimNode = + ## returns a `nnkStmtList` containing the top-level doc comments and + ## runnableExamples in `a`, stopping at the first child that is neither. + ## Example: + ## + ## .. code-block:: nim + ## import macros + ## macro transf(a): untyped = + ## result = quote do: + ## proc fun2*() = discard + ## let header = extractDocCommentsAndRunnables(a.body) + ## # correct usage: rest is appended + ## result.body = header + ## result.body.add quote do: discard # just an example + ## # incorrect usage: nesting inside a nnkStmtList: + ## # result.body = quote do: (`header`; discard) + ## + ## proc fun*() {.transf.} = + ## ## first comment + ## runnableExamples: discard + ## runnableExamples: discard + ## ## last comment + ## discard # first statement after doc comments + runnableExamples + ## ## not docgen'd + + result = newStmtList() + for ni in n: + case ni.kind + of nnkCommentStmt: + result.add ni + of nnkCall: + if ni[0].kind == nnkIdent and ni[0].strVal == "runnableExamples": + result.add ni + else: break + else: break diff --git a/lib/pure/asyncmacro.nim b/lib/pure/asyncmacro.nim index 621a4b00c5..219ef6c675 100644 --- a/lib/pure/asyncmacro.nim +++ b/lib/pure/asyncmacro.nim @@ -180,8 +180,7 @@ proc asyncSingleProc(prc: NimNode): NimNode {.compileTime.} = # Extract the documentation comment from the original procedure declaration. # Note that we're not removing it from the body in order not to make this # transformation even more complex. - if prc.body.len > 1 and prc.body[0].kind == nnkCommentStmt: - outerProcBody.add(prc.body[0]) + let body2 = extractDocCommentsAndRunnables(prc.body) # -> var retFuture = newFuture[T]() var retFutureSym = genSym(nskVar, "retFuture") @@ -276,9 +275,10 @@ proc asyncSingleProc(prc: NimNode): NimNode {.compileTime.} = (cast[type(f)](internalTmpFuture)).read() if procBody.kind != nnkEmpty: - result.body = quote: + body2.add quote do: `awaitDefinition` `outerProcBody` + result.body = body2 #echo(treeRepr(result)) #if prcName == "recvLineInto": diff --git a/nimdoc/testproject/expected/testproject.html b/nimdoc/testproject/expected/testproject.html index a4f8876fd8..648ecb6294 100644 --- a/nimdoc/testproject/expected/testproject.html +++ b/nimdoc/testproject/expected/testproject.html @@ -200,6 +200,12 @@ function main() { title="low2[T: Ordinal | enum | range](x: T): T">low2
  • tripleStrLitTest
  • +
  • asyncFun1
  • +
  • asyncFun2
  • +
  • asyncFun3
  • @@ -655,6 +661,29 @@ at indent 0 discard # should be in + + +
    proc asyncFun1(): Future[int] {...}{.raises: [Exception, ValueError], tags: [RootEffect].}
    +
    + +ok1 + +
    + +
    proc asyncFun2(): owned(Future[void]) {...}{.raises: [Exception], tags: [RootEffect].}
    +
    + + + +
    + +
    proc asyncFun3(): owned(Future[void]) {...}{.raises: [Exception], tags: [RootEffect].}
    +
    + + +

    Example:

    +
    discard
    ok1 +
    diff --git a/nimdoc/testproject/expected/testproject.idx b/nimdoc/testproject/expected/testproject.idx index 6d0bc6c5e7..0b75b29d2e 100644 --- a/nimdoc/testproject/expected/testproject.idx +++ b/nimdoc/testproject/expected/testproject.idx @@ -50,4 +50,7 @@ foo testproject.html#foo.t,SomeType,SomeType testproject: foo(a, b: SomeType) myfn testproject.html#myfn.t testproject: myfn() z14 testproject.html#z14.t testproject: z14() z15 testproject.html#z15.t testproject: z15() +asyncFun1 testproject.html#asyncFun1 testproject: asyncFun1(): Future[int] +asyncFun2 testproject.html#asyncFun2 testproject: asyncFun2(): owned(Future[void]) +asyncFun3 testproject.html#asyncFun3 testproject: asyncFun3(): owned(Future[void]) testNimDocTrailingExample testproject.html#testNimDocTrailingExample.t testproject: testNimDocTrailingExample() diff --git a/nimdoc/testproject/expected/theindex.html b/nimdoc/testproject/expected/theindex.html index 8d34506a61..0b835c4091 100644 --- a/nimdoc/testproject/expected/theindex.html +++ b/nimdoc/testproject/expected/theindex.html @@ -85,6 +85,18 @@ function main() {
  • utils: aEnum(): untyped
  • +
    asyncFun1:
    +
    asyncFun2:
    +
    asyncFun3:
    aVariable: