Source Edit

This module implements nice syntactic sugar based on Nim’s macro system.

Imports

since, macros, underscored_calls

Macros

  1. macro `->`(p, b: untyped): untyped

Syntax sugar for procedure types. It also supports pragmas.

Warning: Semicolons can not be used to separate procedure arguments.

Example:

  1. proc passTwoAndTwo(f: (int, int) -> int): int = f(2, 2)
  2. # is the same as:
  3. # proc passTwoAndTwo(f: proc (x, y: int): int): int = f(2, 2)
  4. assert passTwoAndTwo((x, y) => x + y) == 4
  5. proc passOne(f: (int {.noSideEffect.} -> int)): int = f(1)
  6. # is the same as:
  7. # proc passOne(f: proc (x: int): int {.noSideEffect.}): int = f(1)
  8. assert passOne(x {.noSideEffect.} => x + 1) == 2

Source Edit

  1. macro `=>`(p, b: untyped): untyped

Syntax sugar for anonymous procedures. It also supports pragmas.

Warning: Semicolons can not be used to separate procedure arguments.

Example:

  1. proc passTwoAndTwo(f: (int, int) -> int): int = f(2, 2)
  2. assert passTwoAndTwo((x, y) => x + y) == 4
  3. type
  4. Bot = object
  5. call: (string {.noSideEffect.} -> string)
  6. var myBot = Bot()
  7. myBot.call = (name: string) {.noSideEffect.} => "Hello " & name & ", I'm a bot."
  8. assert myBot.call("John") == "Hello John, I'm a bot."
  9. let f = () => (discard) # simplest proc that returns void
  10. f()

Source Edit

  1. macro capture(locals: varargs[typed]; body: untyped): untyped

Useful when creating a closure in a loop to capture some local loop variables by their current iteration values.

Example:

  1. import std/strformat
  2. var myClosure: () -> string
  3. for i in 5..7:
  4. for j in 7..9:
  5. if i * j == 42:
  6. capture i, j:
  7. myClosure = () => fmt"{i} * {j} = 42"
  8. assert myClosure() == "6 * 7 = 42"

Source Edit

  1. macro collect(body: untyped): untyped

Same as collect but without an init parameter.

See also:

Example:

  1. import std/[sets, tables]
  2. let data = @["bird", "word"]
  3. # seq:
  4. let k = collect:
  5. for i, d in data.pairs:
  6. if i mod 2 == 0: d
  7. assert k == @["bird"]
  8. ## HashSet:
  9. let n = collect:
  10. for d in data.items: {d}
  11. assert n == data.toHashSet
  12. ## Table:
  13. let m = collect:
  14. for i, d in data.pairs: {i: d}
  15. assert m == {0: "bird", 1: "word"}.toTable

Source Edit

  1. macro collect(init, body: untyped): untyped

Comprehension for seqs/sets/tables.

The last expression of body has special syntax that specifies the collection’s add operation. Use {e} for set’s incl, {k: v} for table’s []= and e for seq’s add.

Example:

  1. import std/[sets, tables]
  2. let data = @["bird", "word"]
  3. ## seq:
  4. let k = collect(newSeq):
  5. for i, d in data.pairs:
  6. if i mod 2 == 0: d
  7. assert k == @["bird"]
  8. ## seq with initialSize:
  9. let x = collect(newSeqOfCap(4)):
  10. for i, d in data.pairs:
  11. if i mod 2 == 0: d
  12. assert x == @["bird"]
  13. ## HashSet:
  14. let y = collect(initHashSet()):
  15. for d in data.items: {d}
  16. assert y == data.toHashSet
  17. ## Table:
  18. let z = collect(initTable(2)):
  19. for i, d in data.pairs: {i: d}
  20. assert z == {0: "bird", 1: "word"}.toTable

Source Edit

  1. macro dump(x: untyped): untyped

Dumps the content of an expression, useful for debugging. It accepts any expression and prints a textual representation of the tree representing the expression - as it would appear in source code - together with the value of the expression.

See also: dumpToString which is more convenient and useful since it expands intermediate templates/macros, returns a string instead of calling echo, and works with statements and expressions.

Example: cmd: -r:off

  1. let
  2. x = 10
  3. y = 20
  4. dump(x + y) # prints: `x + y = 30`

Source Edit

  1. macro dumpToString(x: untyped): string

Returns the content of a statement or expression x after semantic analysis, useful for debugging.

Example:

  1. const a = 1
  2. let x = 10
  3. assert dumpToString(a + 2) == "a + 2: 3 = 3"
  4. assert dumpToString(a + x) == "a + x: 1 + x = 11"
  5. template square(x): untyped = x * x
  6. assert dumpToString(square(x)) == "square(x): x * x = 100"
  7. assert not compiles dumpToString(1 + nonexistent)
  8. import std/strutils
  9. assert "failedAssertImpl" in dumpToString(assert true) # example with a statement

Source Edit

  1. macro dup[T](arg: T; calls: varargs[untyped]): T

Turns an in-place algorithm into one that works on a copy and returns this copy, without modifying its input.

This macro also allows for (otherwise in-place) function chaining.

Since: Version 1.2.

Example:

  1. import std/algorithm
  2. let a = @[1, 2, 3, 4, 5, 6, 7, 8, 9]
  3. assert a.dup(sort) == sorted(a)
  4. # Chaining:
  5. var aCopy = a
  6. aCopy.insert(10)
  7. assert a.dup(insert(10), sort) == sorted(aCopy)
  8. let s1 = "abc"
  9. let s2 = "xyz"
  10. assert s1 & s2 == s1.dup(&= s2)
  11. # An underscore (_) can be used to denote the place of the argument you're passing:
  12. assert "".dup(addQuoted(_, "foo")) == "\"foo\""
  13. # but `_` is optional here since the substitution is in 1st position:
  14. assert "".dup(addQuoted("foo")) == "\"foo\""
  15. proc makePalindrome(s: var string) =
  16. for i in countdown(s.len-2, 0):
  17. s.add(s[i])
  18. let c = "xyz"
  19. # chaining:
  20. let d = dup c:
  21. makePalindrome # xyzyx
  22. sort(_, SortOrder.Descending) # zyyxx
  23. makePalindrome # zyyxxxyyz
  24. assert d == "zyyxxxyyz"

Source Edit