"for-loop macros" are no longer an experimental feature (#15288)
This commit is contained in:
parent
a81610230d
commit
c49b88163c
6 changed files with 50 additions and 51 deletions
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
|
|
||||||
|
|
@ -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})
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
=============
|
=============
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
=====================
|
=====================
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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])
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue