"for-loop macros" are no longer an experimental feature (#15288)

This commit is contained in:
Miran
2020-09-08 14:25:25 +02:00
committed by GitHub
parent a81610230d
commit c49b88163c
6 changed files with 50 additions and 51 deletions

View File

@@ -250,6 +250,10 @@ proc mydiv(a, b): int {.raises: [].} =
`.noSideEffect` stricter. [See](manual_experimental.html#stricts-funcs)
for more information.
- "for-loop macros" (see [the manual](manual.html#macros-for-loop-macros)) are no longer
an experimental feature. In other words, you don't have to write pragma
`{.experimental: "forLoopMacros".}` if you want to use them.
## Compiler changes

View File

@@ -154,7 +154,7 @@ type
destructor,
notnil,
dynamicBindSym,
forLoopMacros,
forLoopMacros, # not experimental anymore; remains here for backwards compatibility
caseStmtMacros,
codeReordering,
compiletimeFFI,

View File

@@ -890,9 +890,8 @@ proc handleCaseStmtMacro(c: PContext; n: PNode; flags: TExprFlags): PNode =
proc semFor(c: PContext, n: PNode; flags: TExprFlags): PNode =
checkMinSonsLen(n, 3, c.config)
if forLoopMacros in c.features:
result = handleForLoopMacro(c, n, flags)
if result != nil: return result
result = handleForLoopMacro(c, n, flags)
if result != nil: return result
openScope(c)
result = n
n[^2] = semExprNoDeref(c, n[^2], {efWantIterator})

View File

@@ -5469,6 +5469,48 @@ powerful programming construct that still suffices. So the "check list" is:
(4) Else: Use a macro.
For loop macros
---------------
A macro that takes as its only input parameter an expression of the special
type ``system.ForLoopStmt`` can rewrite the entirety of a ``for`` loop:
.. code-block:: nim
:test: "nim c $1"
import macros
macro enumerate(x: ForLoopStmt): untyped =
expectKind x, nnkForStmt
# we strip off the first for loop variable and use
# it as an integer counter:
result = newStmtList()
result.add newVarStmt(x[0], newLit(0))
var body = x[^1]
if body.kind != nnkStmtList:
body = newTree(nnkStmtList, body)
body.add newCall(bindSym"inc", x[0])
var newFor = newTree(nnkForStmt)
for i in 1..x.len-3:
newFor.add x[i]
# transform enumerate(X) to 'X'
newFor.add x[^2][1]
newFor.add body
result.add newFor
# now wrap the whole macro in a block to create a new scope
result = quote do:
block: `result`
for a, b in enumerate(items([1, 2, 3])):
echo a, " ", b
# without wrapping the macro in a block, we'd need to choose different
# names for `a` and `b` here to avoid redefinition errors
for a, b in enumerate([1, 2, 3, 5]):
echo a, " ", b
Special Types
=============

View File

@@ -1030,52 +1030,6 @@ but only the statement's selector expression is used to determine which
macro to call.
For loop macros
---------------
A macro that takes as its only input parameter an expression of the special
type ``system.ForLoopStmt`` can rewrite the entirety of a ``for`` loop:
.. code-block:: nim
:test: "nim c $1"
import macros
{.experimental: "forLoopMacros".}
macro enumerate(x: ForLoopStmt): untyped =
expectKind x, nnkForStmt
# we strip off the first for loop variable and use
# it as an integer counter:
result = newStmtList()
result.add newVarStmt(x[0], newLit(0))
var body = x[^1]
if body.kind != nnkStmtList:
body = newTree(nnkStmtList, body)
body.add newCall(bindSym"inc", x[0])
var newFor = newTree(nnkForStmt)
for i in 1..x.len-3:
newFor.add x[i]
# transform enumerate(X) to 'X'
newFor.add x[^2][1]
newFor.add body
result.add newFor
# now wrap the whole macro in a block to create a new scope
result = quote do:
block: `result`
for a, b in enumerate(items([1, 2, 3])):
echo a, " ", b
# without wrapping the macro in a block, we'd need to choose different
# names for `a` and `b` here to avoid redefinition errors
for a, b in enumerate([1, 2, 3, 5]):
echo a, " ", b
Currently for loop macros must be enabled explicitly
via ``{.experimental: "forLoopMacros".}``.
Term rewriting macros
=====================

View File

@@ -12,7 +12,7 @@ discard """
"""
import macros
{.experimental: "forLoopMacros".}
macro mymacro(): untyped =
result = newLit([1, 2, 3])