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:
parent
8395abab5f
commit
20993047ce
1 changed files with 63 additions and 66 deletions
|
|
@ -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
|
||||||
|
|
@ -220,7 +215,7 @@ macro capture*(locals: varargs[typed], body: untyped): untyped {.since: (1, 1).}
|
||||||
for arg in locals: result.add(arg)
|
for arg in locals: result.add(arg)
|
||||||
|
|
||||||
since (1, 1):
|
since (1, 1):
|
||||||
import std / private / underscored_calls
|
import std/private/underscored_calls
|
||||||
|
|
||||||
macro dup*[T](arg: T, calls: varargs[untyped]): T =
|
macro dup*[T](arg: T, calls: varargs[untyped]): T =
|
||||||
## Turns an `in-place`:idx: algorithm into one that works on
|
## Turns an `in-place`:idx: algorithm into one that works on
|
||||||
|
|
@ -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)
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue