diff options
-rw-r--r-- | changelog.md | 3 | ||||
-rw-r--r-- | lib/pure/sugar.nim | 26 | ||||
-rw-r--r-- | tests/closure/tcapture.nim | 12 |
3 files changed, 41 insertions, 0 deletions
diff --git a/changelog.md b/changelog.md index 18eece00c..429d0bfe0 100644 --- a/changelog.md +++ b/changelog.md @@ -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` diff --git a/lib/pure/sugar.nim b/lib/pure/sugar.nim index 73ac44d04..c13695ebf 100644 --- a/lib/pure/sugar.nim +++ b/lib/pure/sugar.nim @@ -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 diff --git a/tests/closure/tcapture.nim b/tests/closure/tcapture.nim new file mode 100644 index 000000000..304a76285 --- /dev/null +++ b/tests/closure/tcapture.nim @@ -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] \ No newline at end of file |