Sugar improvements (#16802)

* Use runnableExamples in sugar

Remove unnecessary import

* Add trailing newline

* Address nits

* Remove unneccessary convolution

* Change wording

Co-authored-by: Clyybber <darkmine956@gmail.com>
This commit is contained in:
konsumlamm 2021-01-25 14:41:55 +01:00 • committed by GitHub
commit 20993047ce
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23

View file

@ -11,7 +11,7 @@
## macro system. ## macro system.
import std/private/since import std/private/since
import macros, typetraits import std/macros
proc checkPragma(ex, prag: var NimNode) = proc checkPragma(ex, prag: var NimNode) =
since (1, 3): since (1, 3):
@ -56,8 +56,7 @@ macro `=>`*(p, b: untyped): untyped =
## Syntax sugar for anonymous procedures. ## Syntax sugar for anonymous procedures.
## It also supports pragmas. ## It also supports pragmas.
runnableExamples: runnableExamples:
proc passTwoAndTwo(f: (int, int) -> int): int = proc passTwoAndTwo(f: (int, int) -> int): int = f(2, 2)
f(2, 2)
doAssert passTwoAndTwo((x, y) => x + y) == 4 doAssert passTwoAndTwo((x, y) => x + y) == 4
@ -142,16 +141,13 @@ macro `=>`*(p, b: untyped): untyped =
macro `->`*(p, b: untyped): untyped = macro `->`*(p, b: untyped): untyped =
## Syntax sugar for procedure types. ## Syntax sugar for procedure types.
## runnableExamples:
## .. code-block:: nim proc passTwoAndTwo(f: (int, int) -> int): int = f(2, 2)
##
## proc pass2(f: (float, float) -> float): float = # is the same as:
## f(2, 2) # proc passTwoAndTwo(f: proc (x, y: int): int): int = f(2, 2)
##
## # is the same as: doAssert passTwoAndTwo((x, y) => x + y) == 4
##
## proc pass2(f: proc (x, y: float): float): float =
## f(2, 2)
result = createProcType(p, b) result = createProcType(p, b)
@ -160,16 +156,12 @@ macro dump*(x: untyped): untyped =
## It accepts any expression and prints a textual representation ## It accepts any expression and prints a textual representation
## of the tree representing the expression - as it would appear in ## of the tree representing the expression - as it would appear in
## source code - together with the value of the expression. ## source code - together with the value of the expression.
## runnableExamples:
## As an example, let
## x = 10
## .. code-block:: nim y = 20
## let dump(x + y) # will print `x + y = 30`
## x = 10
## y = 20
## dump(x + y)
##
## will print ``x + y = 30``.
let s = x.toStrLit let s = x.toStrLit
let r = quote do: let r = quote do:
debugEcho `s`, " = ", `x` debugEcho `s`, " = ", `x`
@ -193,21 +185,24 @@ proc freshIdentNodes(ast: NimNode): NimNode =
macro capture*(locals: varargs[typed], body: untyped): untyped {.since: (1, 1).} = macro capture*(locals: varargs[typed], body: untyped): untyped {.since: (1, 1).} =
## Useful when creating a closure in a loop to capture some local loop variables ## Useful when creating a closure in a loop to capture some local loop variables
## by their current iteration values. Example: ## by their current iteration values.
## runnableExamples:
## .. code-block:: Nim import std/[strformat, sequtils]
## import strformat, sequtils, sugar
## var myClosure : proc() var myClosure: () -> string
## for i in 5..7: for i in 5..7:
## for j in 7..9: for j in 7..9:
## if i * j == 42: if i * j == 42:
## capture i, j: capture i, j:
## myClosure = proc () = echo fmt"{i} * {j} = 42" myClosure = () => fmt"{i} * {j} = 42"
## myClosure() # output: 6 * 7 == 42 doAssert myClosure() == "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 m = @[(s: string) => "to " & s,
## let r = l.mapIt(it("be")) (s: string) => "not to " & s]
## echo r[0] & ", or " & r[1] # output: to be, or not to be let l = m.mapIt(capture(it, (s: string) => it(s)))
let r = l.mapIt(it("be"))
doAssert fmt"{r[0]}, or {r[1]}" == "to be, or not to be"
var params = @[newIdentNode("auto")] var params = @[newIdentNode("auto")]
let locals = if locals.len == 1 and locals[0].kind == nnkBracket: locals[0] let locals = if locals.len == 1 and locals[0].kind == nnkBracket: locals[0]
else: locals else: locals
@ -228,40 +223,38 @@ since (1, 1):
## ##
## This macro also allows for (otherwise in-place) function chaining. ## This macro also allows for (otherwise in-place) function chaining.
## ##
## **Since**: Version 1.2. ## **Since:** Version 1.2.
runnableExamples: runnableExamples:
import algorithm import std/algorithm
var a = @[1, 2, 3, 4, 5, 6, 7, 8, 9] let a = @[1, 2, 3, 4, 5, 6, 7, 8, 9]
doAssert a.dup(sort) == sorted(a) doAssert a.dup(sort) == sorted(a)
# Chaining: # Chaining:
var aCopy = a var aCopy = a
aCopy.insert(10) aCopy.insert(10)
doAssert a.dup(insert(10), sort) == sorted(aCopy) doAssert a.dup(insert(10), sort) == sorted(aCopy)
var s1 = "abc" let s1 = "abc"
var s2 = "xyz" let s2 = "xyz"
doAssert s1 & s2 == s1.dup(&= s2) doAssert s1 & s2 == s1.dup(&= s2)
proc makePalindrome(s: var string) =
for i in countdown(s.len-2, 0):
s.add(s[i])
var c = "xyz"
# An underscore (_) can be used to denote the place of the argument you're passing: # An underscore (_) can be used to denote the place of the argument you're passing:
doAssert "".dup(addQuoted(_, "foo")) == "\"foo\"" doAssert "".dup(addQuoted(_, "foo")) == "\"foo\""
# but `_` is optional here since the substitution is in 1st position: # but `_` is optional here since the substitution is in 1st position:
doAssert "".dup(addQuoted("foo")) == "\"foo\"" doAssert "".dup(addQuoted("foo")) == "\"foo\""
proc makePalindrome(s: var string) =
for i in countdown(s.len-2, 0):
s.add(s[i])
let c = "xyz"
# chaining: # chaining:
# b = "xyz" let d = dup c:
var d = dup c:
makePalindrome # xyzyx makePalindrome # xyzyx
sort(_, SortOrder.Descending) # zyyxx sort(_, SortOrder.Descending) # zyyxx
makePalindrome # zyyxxxyyz makePalindrome # zyyxxxyyz
doAssert d == "zyyxxxyyz" doAssert d == "zyyxxxyyz"
result = newNimNode(nnkStmtListExpr, arg) result = newNimNode(nnkStmtListExpr, arg)
@ -344,51 +337,55 @@ macro collect*(init, body: untyped): untyped {.since: (1, 1).} =
# analyse the body, find the deepest expression 'it' and replace it via # analyse the body, find the deepest expression 'it' and replace it via
# 'result.add it' # 'result.add it'
runnableExamples: runnableExamples:
import sets, tables import std/[sets, tables]
let data = @["bird", "word"] let data = @["bird", "word"]
## seq: ## seq:
let k = collect(newSeq): let k = collect(newSeq):
for i, d in data.pairs: for i, d in data.pairs:
if i mod 2 == 0: d if i mod 2 == 0: d
doAssert k == @["bird"]
assert k == @["bird"]
## seq with initialSize: ## seq with initialSize:
let x = collect(newSeqOfCap(4)): let x = collect(newSeqOfCap(4)):
for i, d in data.pairs: for i, d in data.pairs:
if i mod 2 == 0: d if i mod 2 == 0: d
doAssert x == @["bird"]
assert x == @["bird"]
## HashSet: ## HashSet:
let y = initHashSet.collect: let y = collect(initHashSet()):
for d in data.items: {d} for d in data.items: {d}
doAssert y == data.toHashSet
assert y == data.toHashSet
## Table: ## Table:
let z = collect(initTable(2)): let z = collect(initTable(2)):
for i, d in data.pairs: {i: d} for i, d in data.pairs: {i: d}
doAssert z == {0: "bird", 1: "word"}.toTable
assert z == {0: "bird", 1: "word"}.toTable
result = collectImpl(init, body) result = collectImpl(init, body)
macro collect*(body: untyped): untyped {.since: (1, 5).} = macro collect*(body: untyped): untyped {.since: (1, 5).} =
## Same as `collect` but without an `init` parameter. ## Same as `collect` but without an `init` parameter.
runnableExamples: runnableExamples:
import sets, tables import std/[sets, tables]
# Seq:
let data = @["bird", "word"] let data = @["bird", "word"]
# seq:
let k = collect: let k = collect:
for i, d in data.pairs: for i, d in data.pairs:
if i mod 2 == 0: d if i mod 2 == 0: d
doAssert k == @["bird"]
assert k == @["bird"]
## HashSet: ## HashSet:
let n = collect: let n = collect:
for d in data.items: {d} for d in data.items: {d}
doAssert n == data.toHashSet
assert n == data.toHashSet
## Table: ## Table:
let m = collect: let m = collect:
for i, d in data.pairs: {i: d} for i, d in data.pairs: {i: d}
doAssert m == {0: "bird", 1: "word"}.toTable
assert m == {0: "bird", 1: "word"}.toTable
result = collectImpl(nil, body) result = collectImpl(nil, body)