introduce capture macro (#12712)

capture works for more cases than `closureScope`.
This commit is contained in:
Judd
2019-12-10 20:16:37 +08:00
committed by Andreas Rumpf
parent 65fd95bf85
commit 56cf3403b4
3 changed files with 41 additions and 0 deletions

View File

@@ -42,6 +42,9 @@
`sorted` does.
- Added `sugar.collect` that does comprehension for seq/set/table collections.
- Added `sugar.capture` for capturing some local loop variables when creating a closure.
This is an enhanced version of `closureScope`.
## Library changes
- `asyncdispatch.drain` now properly takes into account `selector.hasPendingOperations`

View File

@@ -10,6 +10,8 @@
## This module implements nice syntactic sugar based on Nim's
## macro system.
include system/inclrtl
import macros
proc createProcType(p, b: NimNode): NimNode {.compileTime.} =
@@ -180,6 +182,30 @@ macro distinctBase*(T: typedesc): untyped =
typeSym = getTypeImpl(typeSym)[0]
typeSym.freshIdentNodes
macro capture*(locals: openArray[typed], body: untyped): untyped {.since: (1, 1).} =
## Useful when creating a closure in a loop to capture some local loop variables
## by their current iteration values. Example:
##
## .. code-block:: Nim
## import strformat, sequtils, sugar
## var myClosure : proc()
## for i in 5..7:
## for j in 7..9:
## if i * j == 42:
## capture [i, j]:
## myClosure = proc () = echo fmt"{i} * {j} = 42"
## myClosure() # output: 6 * 7 == 42
## let m = @[proc (s: string): string = "to " & s, proc (s: string): string = "not to " & s]
## var l = m.mapIt(capture([it], proc (s: string): string = it(s)))
## let r = l.mapIt(it("be"))
## echo r[0] & ", or " & r[1] # output: to be, or not to be
var params = @[newIdentNode("auto")]
for arg in locals:
params.add(newIdentDefs(ident(arg.strVal), freshIdentNodes getTypeImpl arg))
result = newNimNode(nnkCall)
result.add(newProc(newEmptyNode(), params, body, nnkProcDef))
for arg in locals: result.add(arg)
when (NimMajor, NimMinor) >= (1, 1):
macro outplace*[T](arg: T, call: untyped; inplaceArgPosition: static[int] = 1): T =
## Turns an `in-place`:idx: algorithm into one that works on

View File

@@ -0,0 +1,12 @@
discard """
output: '''
to be, or not to be'''
joinable: false
"""
import sequtils, sugar
let m = @[proc (s: string): string = "to " & s, proc (s: string): string = "not to " & s]
var l = m.mapIt(capture([it], proc (s: string): string = it(s)))
let r = l.mapIt(it("be"))
echo r[0] & ", or " & r[1]