summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorslangmgh <37659406+slangmgh@users.noreply.github.com>2020-08-15 07:33:21 +0800
committerGitHub <noreply@github.com>2020-08-15 01:33:21 +0200
commitba042af9cc6194cd3c3e67e5daf0165b4b3630c0 (patch)
tree960fe34914af04ed3cacb294cd70b5858a49b3f8
parent957bf15a08d5443a50452909743747d19b5f29f8 (diff)
downloadNim-ba042af9cc6194cd3c3e67e5daf0165b4b3630c0.tar.gz
std/with support field assign (#14484)
* std/with support filed assign

* add changelog

* add support x.dup.with

* add example

* revert support x.dup.with; add example

* update changelog; fix assignment in parameter

* Update changelog.md

* add example for assignment in parameter

* Remove colon style assign

Co-authored-by: Clyybber <darkmine956@gmail.com>
-rw-r--r--changelog.md15
-rw-r--r--lib/pure/sugar.nim26
-rw-r--r--lib/std/private/underscored_calls.nim25
-rw-r--r--lib/std/with.nim7
4 files changed, 60 insertions, 13 deletions
diff --git a/changelog.md b/changelog.md
index f6f1f94cd..eebccb62f 100644
--- a/changelog.md
+++ b/changelog.md
@@ -148,6 +148,21 @@
 - Added `deques.toDeque`, which creates a deque from an openArray. The usage is
   similar to procs such as `sets.toHashSet` and `tables.toTable`. Previously,
   it was necessary to create an empty deque and add items manually.
+  
+- `std/with`, `sugar.dup` now support object field assignment expression:
+  ```nim
+  import std/with
+
+  type Foo = object
+    x, y: int
+
+  var foo = Foo()
+  with foo:
+    x = 10
+    y = 20
+
+  echo foo
+  ```
 
 ## Language changes
 - The `=destroy` hook no longer has to reset its target, as the compiler now automatically inserts
diff --git a/lib/pure/sugar.nim b/lib/pure/sugar.nim
index 00f4de5d8..0edcc5697 100644
--- a/lib/pure/sugar.nim
+++ b/lib/pure/sugar.nim
@@ -337,6 +337,32 @@ macro collect*(init, body: untyped): untyped {.since: (1, 1).} =
 
 when isMainModule:
   since (1, 1):
+    block dup_with_field:
+      type
+        Foo = object
+          col, pos: int
+          name: string
+
+      proc inc_col(foo: var Foo) = inc(foo.col)
+      proc inc_pos(foo: var Foo) = inc(foo.pos)
+      proc name_append(foo: var Foo, s: string) = foo.name &= s
+
+      let a = Foo(col: 1, pos: 2, name: "foo")
+      block:
+        let b = a.dup(inc_col, inc_pos):
+          _.pos = 3
+          name_append("bar")
+          inc_pos
+
+        doAssert(b == Foo(col: 2, pos: 4, name: "foobar"))
+
+      block:
+        let b = a.dup(inc_col, pos = 3, name = "bar"):
+          name_append("bar")
+          inc_pos
+
+        doAssert(b == Foo(col: 2, pos: 4, name: "barbar"))
+
     import algorithm
 
     var a = @[1, 2, 3, 4, 5, 6, 7, 8, 9]
diff --git a/lib/std/private/underscored_calls.nim b/lib/std/private/underscored_calls.nim
index c7aeb6ae2..f0bcbcc74 100644
--- a/lib/std/private/underscored_calls.nim
+++ b/lib/std/private/underscored_calls.nim
@@ -26,6 +26,12 @@ proc underscoredCall(n, arg0: NimNode): NimNode =
     for i in 1..u-1: result.add n[i]
     result.add arg0
     for i in u+1..n.len-1: result.add n[i]
+  elif n.kind in {nnkAsgn, nnkExprEqExpr}:
+    var field = n[0]
+    if n[0].kind == nnkDotExpr and n[0][0].eqIdent("_"):
+      # handle _.field = ...
+      field = n[0][1]
+    result = newDotExpr(arg0, field).newAssignment n[1]
   else:
     # handle e.g. 'x.dup(sort)'
     result = newNimNode(nnkCall, n)
@@ -33,17 +39,10 @@ proc underscoredCall(n, arg0: NimNode): NimNode =
     result.add arg0
 
 proc underscoredCalls*(result, calls, arg0: NimNode) =
-  proc handleStmtList(result, n, arg0: NimNode) =
-    for a in n:
-      if a.kind in {nnkStmtList, nnkStmtListExpr}:
-        handleStmtList(result, a, arg0)
-      else:
-        result.add underscoredCall(a, arg0)
-
-  expectKind calls, nnkArgList
-  if calls.len == 1 and calls[0].kind in {nnkStmtList, nnkStmtListExpr}:
-    # the 'macro: body' syntax is used:
-    handleStmtList(result, calls[0], arg0)
-  else:
-    for call in calls:
+  expectKind calls, {nnkArgList, nnkStmtList, nnkStmtListExpr}
+
+  for call in calls:
+    if call.kind in {nnkStmtList, nnkStmtListExpr}:
+      underscoredCalls(result, call, arg0)
+    else:
       result.add underscoredCall(call, arg0)
diff --git a/lib/std/with.nim b/lib/std/with.nim
index c1ac96fcb..ea26065a1 100644
--- a/lib/std/with.nim
+++ b/lib/std/with.nim
@@ -41,6 +41,7 @@ when isMainModule:
   type
     Foo = object
       col, pos: string
+      name: string
 
   proc setColor(f: var Foo; r, g, b: int) = f.col = $(r, g, b)
   proc setPosition(f: var Foo; x, y: float) = f.pos = $(x, y)
@@ -49,3 +50,9 @@ when isMainModule:
   with(f, setColor(2, 3, 4), setPosition(0.0, 1.0))
   echo f
 
+  f = Foo()
+  with f:
+    col = $(2, 3, 4)
+    pos = $(0.0, 1.0)
+    _.name = "bar"
+  echo f
n102' href='#n102'>102 103