"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
commit c49b88163c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
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) `.noSideEffect` stricter. [See](manual_experimental.html#stricts-funcs)
for more information. 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 ## Compiler changes

View file

@ -154,7 +154,7 @@ type
destructor, destructor,
notnil, notnil,
dynamicBindSym, dynamicBindSym,
forLoopMacros, forLoopMacros, # not experimental anymore; remains here for backwards compatibility
caseStmtMacros, caseStmtMacros,
codeReordering, codeReordering,
compiletimeFFI, 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 = proc semFor(c: PContext, n: PNode; flags: TExprFlags): PNode =
checkMinSonsLen(n, 3, c.config) checkMinSonsLen(n, 3, c.config)
if forLoopMacros in c.features: result = handleForLoopMacro(c, n, flags)
result = handleForLoopMacro(c, n, flags) if result != nil: return result
if result != nil: return result
openScope(c) openScope(c)
result = n result = n
n[^2] = semExprNoDeref(c, n[^2], {efWantIterator}) 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. (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 Special Types
============= =============

View file

@ -1030,52 +1030,6 @@ but only the statement's selector expression is used to determine which
macro to call. 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 Term rewriting macros
===================== =====================

View file

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