fix #14846; add macros.extractDocCommentsAndRunnables (#14849)

* fix #14846; add macros.extractDocCommentsAndRunnables

* fixup

* update tests

* address comment
This commit is contained in:
Timothee Cour
2020-07-01 00:26:23 -07:00
committed by GitHub
parent 05384efec5
commit 2867a33ebc
7 changed files with 98 additions and 3 deletions

View File

@@ -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}"`.

View File

@@ -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

View File

@@ -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":

View File

@@ -200,6 +200,12 @@ function main() {
title="low2[T: Ordinal | enum | range](x: T): T"><wbr />low2<span class="attachedType"></span></a></li>
<li><a class="reference" href="#tripleStrLitTest"
title="tripleStrLitTest()"><wbr />triple<wbr />Str<wbr />Lit<wbr />Test<span class="attachedType"></span></a></li>
<li><a class="reference" href="#asyncFun1"
title="asyncFun1(): Future[int]"><wbr />async<wbr />Fun1<span class="attachedType"></span></a></li>
<li><a class="reference" href="#asyncFun2"
title="asyncFun2(): owned(Future[void])"><wbr />async<wbr />Fun2<span class="attachedType"></span></a></li>
<li><a class="reference" href="#asyncFun3"
title="asyncFun3(): owned(Future[void])"><wbr />async<wbr />Fun3<span class="attachedType"></span></a></li>
</ul>
</li>
@@ -655,6 +661,29 @@ at indent 0
</span><span class="Keyword">discard</span><span class="Whitespace">
</span><span class="Comment"># should be in</span></pre>
</dd>
<a id="asyncFun1"></a>
<dt><pre><span class="Keyword">proc</span> <a href="#asyncFun1"><span class="Identifier">asyncFun1</span></a><span class="Other">(</span><span class="Other">)</span><span class="Other">:</span> <span class="Identifier">Future</span><span class="Other">[</span><span class="Identifier">int</span><span class="Other">]</span> <span><span class="Other">{</span><span class="Other pragmadots">...</span><span class="Other">}</span></span><span class="pragmawrap"><span class="Other">{.</span><span class="pragma"><span class="Identifier">raises</span><span class="Other">:</span> <span class="Other">[</span><span class="Identifier">Exception</span><span class="Other">,</span> <span class="Identifier">ValueError</span><span class="Other">]</span><span class="Other">,</span> <span class="Identifier">tags</span><span class="Other">:</span> <span class="Other">[</span><span class="Identifier">RootEffect</span><span class="Other">]</span></span><span class="Other">.}</span></span></pre></dt>
<dd>
ok1
</dd>
<a id="asyncFun2"></a>
<dt><pre><span class="Keyword">proc</span> <a href="#asyncFun2"><span class="Identifier">asyncFun2</span></a><span class="Other">(</span><span class="Other">)</span><span class="Other">:</span> <span class="Identifier">owned</span><span class="Other">(</span><span class="Identifier">Future</span><span class="Other">[</span><span class="Identifier">void</span><span class="Other">]</span><span class="Other">)</span> <span><span class="Other">{</span><span class="Other pragmadots">...</span><span class="Other">}</span></span><span class="pragmawrap"><span class="Other">{.</span><span class="pragma"><span class="Identifier">raises</span><span class="Other">:</span> <span class="Other">[</span><span class="Identifier">Exception</span><span class="Other">]</span><span class="Other">,</span> <span class="Identifier">tags</span><span class="Other">:</span> <span class="Other">[</span><span class="Identifier">RootEffect</span><span class="Other">]</span></span><span class="Other">.}</span></span></pre></dt>
<dd>
</dd>
<a id="asyncFun3"></a>
<dt><pre><span class="Keyword">proc</span> <a href="#asyncFun3"><span class="Identifier">asyncFun3</span></a><span class="Other">(</span><span class="Other">)</span><span class="Other">:</span> <span class="Identifier">owned</span><span class="Other">(</span><span class="Identifier">Future</span><span class="Other">[</span><span class="Identifier">void</span><span class="Other">]</span><span class="Other">)</span> <span><span class="Other">{</span><span class="Other pragmadots">...</span><span class="Other">}</span></span><span class="pragmawrap"><span class="Other">{.</span><span class="pragma"><span class="Identifier">raises</span><span class="Other">:</span> <span class="Other">[</span><span class="Identifier">Exception</span><span class="Other">]</span><span class="Other">,</span> <span class="Identifier">tags</span><span class="Other">:</span> <span class="Other">[</span><span class="Identifier">RootEffect</span><span class="Other">]</span></span><span class="Other">.}</span></span></pre></dt>
<dd>
<p><strong class="examples_text">Example:</strong></p>
<pre class="listing"><span class="Keyword">discard</span></pre>ok1
</dd>
</dl></div>

View File

@@ -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()

View File

@@ -85,6 +85,18 @@ function main() {
<li><a class="reference external"
data-doc-search-tag="utils: aEnum(): untyped" href="subdir/subdir_b/utils.html#aEnum.t">utils: aEnum(): untyped</a></li>
</ul></dd>
<dt><a name="asyncFun1" href="#asyncFun1"><span>asyncFun1:</span></a></dt><dd><ul class="simple">
<li><a class="reference external"
data-doc-search-tag="testproject: asyncFun1(): Future[int]" href="testproject.html#asyncFun1">testproject: asyncFun1(): Future[int]</a></li>
</ul></dd>
<dt><a name="asyncFun2" href="#asyncFun2"><span>asyncFun2:</span></a></dt><dd><ul class="simple">
<li><a class="reference external"
data-doc-search-tag="testproject: asyncFun2(): owned(Future[void])" href="testproject.html#asyncFun2">testproject: asyncFun2(): owned(Future[void])</a></li>
</ul></dd>
<dt><a name="asyncFun3" href="#asyncFun3"><span>asyncFun3:</span></a></dt><dd><ul class="simple">
<li><a class="reference external"
data-doc-search-tag="testproject: asyncFun3(): owned(Future[void])" href="testproject.html#asyncFun3">testproject: asyncFun3(): owned(Future[void])</a></li>
</ul></dd>
<dt><a name="aVariable" href="#aVariable"><span>aVariable:</span></a></dt><dd><ul class="simple">
<li><a class="reference external"
data-doc-search-tag="testproject: aVariable" href="testproject.html#aVariable">testproject: aVariable</a></li>

View File

@@ -343,6 +343,20 @@ when true: # issue #14473
toSeq([1,2])
echo doit() # using doAssert or similar to avoid echo would "hide" the original bug
when true: # issue #14846
import asyncdispatch
proc asyncFun1*(): Future[int] {.async.} =
## ok1
result = 1
proc asyncFun2*() {.async.} = discard
proc asyncFun3*() {.async.} =
runnableExamples:
discard
## ok1
discard
## should be out
discard
when true:
template testNimDocTrailingExample*() =
# this must be last entry in this file, it checks against a bug (that got fixed)