Sugar tests (#16820)
This commit is contained in:
parent
e4ad0ae5c4
commit
f4449a897d
2 changed files with 208 additions and 109 deletions
|
|
@ -53,8 +53,8 @@ proc createProcType(p, b: NimNode): NimNode {.compileTime.} =
|
||||||
result.add prag
|
result.add prag
|
||||||
|
|
||||||
macro `=>`*(p, b: untyped): untyped =
|
macro `=>`*(p, b: untyped): untyped =
|
||||||
## Syntax sugar for anonymous procedures.
|
## Syntax sugar for anonymous procedures. It also supports pragmas.
|
||||||
## It also supports pragmas.
|
# TODO: xxx pending #13491: uncomment in runnableExamples
|
||||||
runnableExamples:
|
runnableExamples:
|
||||||
proc passTwoAndTwo(f: (int, int) -> int): int = f(2, 2)
|
proc passTwoAndTwo(f: (int, int) -> int): int = f(2, 2)
|
||||||
|
|
||||||
|
|
@ -62,13 +62,16 @@ macro `=>`*(p, b: untyped): untyped =
|
||||||
|
|
||||||
type
|
type
|
||||||
Bot = object
|
Bot = object
|
||||||
call: proc (name: string): string {.noSideEffect.}
|
call: (string {.noSideEffect.} -> string)
|
||||||
|
|
||||||
var myBot = Bot()
|
var myBot = Bot()
|
||||||
|
|
||||||
myBot.call = (name: string) {.noSideEffect.} => "Hello " & name & ", I'm a bot."
|
myBot.call = (name: string) {.noSideEffect.} => "Hello " & name & ", I'm a bot."
|
||||||
doAssert myBot.call("John") == "Hello John, I'm a bot."
|
doAssert myBot.call("John") == "Hello John, I'm a bot."
|
||||||
|
|
||||||
|
# let f = () => (discard) # simplest proc that returns void
|
||||||
|
# f()
|
||||||
|
|
||||||
var
|
var
|
||||||
params = @[ident"auto"]
|
params = @[ident"auto"]
|
||||||
name = newEmptyNode()
|
name = newEmptyNode()
|
||||||
|
|
@ -140,15 +143,20 @@ macro `=>`*(p, b: untyped): untyped =
|
||||||
procType = kind)
|
procType = kind)
|
||||||
|
|
||||||
macro `->`*(p, b: untyped): untyped =
|
macro `->`*(p, b: untyped): untyped =
|
||||||
## Syntax sugar for procedure types.
|
## Syntax sugar for procedure types. It also supports pragmas.
|
||||||
runnableExamples:
|
runnableExamples:
|
||||||
proc passTwoAndTwo(f: (int, int) -> int): int = f(2, 2)
|
proc passTwoAndTwo(f: (int, int) -> int): int = f(2, 2)
|
||||||
|
|
||||||
# is the same as:
|
# is the same as:
|
||||||
# proc passTwoAndTwo(f: proc (x, y: int): int): int = f(2, 2)
|
# proc passTwoAndTwo(f: proc (x, y: int): int): int = f(2, 2)
|
||||||
|
|
||||||
doAssert passTwoAndTwo((x, y) => x + y) == 4
|
doAssert passTwoAndTwo((x, y) => x + y) == 4
|
||||||
|
|
||||||
|
proc passOne(f: (int {.noSideEffect.} -> int)): int = f(1)
|
||||||
|
# is the same as:
|
||||||
|
# proc passOne(f: proc (x: int): int {.noSideEffect.}): int = f(1)
|
||||||
|
|
||||||
|
doAssert passOne(x {.noSideEffect.} => x + 1) == 2
|
||||||
|
|
||||||
result = createProcType(p, b)
|
result = createProcType(p, b)
|
||||||
|
|
||||||
macro dump*(x: untyped): untyped =
|
macro dump*(x: untyped): untyped =
|
||||||
|
|
@ -216,7 +224,7 @@ 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.
|
## by their current iteration values.
|
||||||
runnableExamples:
|
runnableExamples:
|
||||||
import std/[strformat, sequtils]
|
import std/strformat
|
||||||
|
|
||||||
var myClosure: () -> string
|
var myClosure: () -> string
|
||||||
for i in 5..7:
|
for i in 5..7:
|
||||||
|
|
@ -226,12 +234,6 @@ macro capture*(locals: varargs[typed], body: untyped): untyped {.since: (1, 1).}
|
||||||
myClosure = () => fmt"{i} * {j} = 42"
|
myClosure = () => fmt"{i} * {j} = 42"
|
||||||
doAssert myClosure() == "6 * 7 = 42"
|
doAssert myClosure() == "6 * 7 = 42"
|
||||||
|
|
||||||
let m = @[(s: string) => "to " & s,
|
|
||||||
(s: string) => "not to " & s]
|
|
||||||
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
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,85 @@
|
||||||
import sugar
|
discard """
|
||||||
|
output: '''
|
||||||
|
x + y = 30
|
||||||
|
'''
|
||||||
|
"""
|
||||||
|
import std/[sugar, algorithm, random, sets, tables, strutils]
|
||||||
|
|
||||||
|
template main() =
|
||||||
|
block: # `=>`
|
||||||
|
block:
|
||||||
|
let f1 = () => 42
|
||||||
|
doAssert f1() == 42
|
||||||
|
|
||||||
|
let f2 = (x: int) => x + 1
|
||||||
|
doAssert f2(42) == 43
|
||||||
|
|
||||||
|
let f3 = (x, y: int) => x + y
|
||||||
|
doAssert f3(1, 2) == 3
|
||||||
|
|
||||||
|
var x = 0
|
||||||
|
let f4 = () => (x = 12)
|
||||||
|
f4()
|
||||||
|
doAssert x == 12
|
||||||
|
|
||||||
|
let f5 = () => (discard) # simplest proc that returns void
|
||||||
|
f5()
|
||||||
|
|
||||||
|
block:
|
||||||
|
proc call1(f: () -> int): int = f()
|
||||||
|
doAssert call1(() => 12) == 12
|
||||||
|
|
||||||
|
proc call2(f: int -> int): int = f(42)
|
||||||
|
doAssert call2(x => x) == 42
|
||||||
|
doAssert call2((x) => x) == 42
|
||||||
|
doAssert call2((x: int) => x) == 42
|
||||||
|
|
||||||
|
proc call3(f: (int, int) -> int): int = f(1, 2)
|
||||||
|
doAssert call3((x, y) => x + y) == 3
|
||||||
|
doAssert call3((x, y: int) => x + y) == 3
|
||||||
|
doAssert call3((x: int, y: int) => x + y) == 3
|
||||||
|
|
||||||
|
var a = 0
|
||||||
|
proc call4(f: int -> void) = f(42)
|
||||||
|
call4((x: int) => (a = x))
|
||||||
|
doAssert a == 42
|
||||||
|
|
||||||
|
proc call5(f: (int {.noSideEffect.} -> int)): int = f(42)
|
||||||
|
doAssert call5(x {.noSideEffect.} => x + 1) == 43
|
||||||
|
|
||||||
|
block: # `->`
|
||||||
|
doAssert $(() -> int) == "proc (): int{.closure.}"
|
||||||
|
doAssert $(float -> int) == "proc (i0: float): int{.closure.}"
|
||||||
|
doAssert $((float) -> int) == "proc (i0: float): int{.closure.}"
|
||||||
|
doAssert $((float, bool) -> int) == "proc (i0: float, i1: bool): int{.closure.}"
|
||||||
|
|
||||||
|
doAssert $(() -> void) == "proc (){.closure.}"
|
||||||
|
doAssert $(float -> void) == "proc (i0: float){.closure.}"
|
||||||
|
doAssert $((float) -> void) == "proc (i0: float){.closure.}"
|
||||||
|
doAssert $((float, bool) -> void) == "proc (i0: float, i1: bool){.closure.}"
|
||||||
|
|
||||||
|
doAssert $(() {.inline.} -> int) == "proc (): int{.inline.}"
|
||||||
|
doAssert $(float {.inline.} -> int) == "proc (i0: float): int{.inline.}"
|
||||||
|
doAssert $((float) {.inline.} -> int) == "proc (i0: float): int{.inline.}"
|
||||||
|
doAssert $((float, bool) {.inline.} -> int) == "proc (i0: float, i1: bool): int{.inline.}"
|
||||||
|
|
||||||
|
block: # capture
|
||||||
|
var closure1: () -> int
|
||||||
|
for i in 0 .. 10:
|
||||||
|
if i == 5:
|
||||||
|
capture i:
|
||||||
|
closure1 = () => i
|
||||||
|
doAssert closure1() == 5
|
||||||
|
|
||||||
|
var closure2: () -> (int, int)
|
||||||
|
for i in 0 .. 10:
|
||||||
|
for j in 0 .. 10:
|
||||||
|
if i == 5 and j == 3:
|
||||||
|
capture i, j:
|
||||||
|
closure2 = () => (i, j)
|
||||||
|
doAssert closure2() == (5, 3)
|
||||||
|
|
||||||
|
block: # dup
|
||||||
block dup_with_field:
|
block dup_with_field:
|
||||||
type
|
type
|
||||||
Foo = object
|
Foo = object
|
||||||
|
|
@ -26,8 +106,7 @@ block dup_with_field:
|
||||||
|
|
||||||
doAssert(b == Foo(col: 2, pos: 4, name: "barbar"))
|
doAssert(b == Foo(col: 2, pos: 4, name: "barbar"))
|
||||||
|
|
||||||
import algorithm
|
block:
|
||||||
|
|
||||||
var a = @[1, 2, 3, 4, 5, 6, 7, 8, 9]
|
var a = @[1, 2, 3, 4, 5, 6, 7, 8, 9]
|
||||||
doAssert dup(a, sort(_)) == sorted(a)
|
doAssert dup(a, sort(_)) == sorted(a)
|
||||||
doAssert a.dup(sort) == sorted(a)
|
doAssert a.dup(sort) == sorted(a)
|
||||||
|
|
@ -36,30 +115,30 @@ var aCopy = a
|
||||||
aCopy.insert(10)
|
aCopy.insert(10)
|
||||||
doAssert a.dup(insert(10)).dup(sort()) == sorted(aCopy)
|
doAssert a.dup(insert(10)).dup(sort()) == sorted(aCopy)
|
||||||
|
|
||||||
import random
|
block:
|
||||||
|
when nimvm: discard
|
||||||
|
else:
|
||||||
const b = @[0, 1, 2]
|
const b = @[0, 1, 2]
|
||||||
let c = b.dup shuffle()
|
discard b.dup shuffle()
|
||||||
doAssert b[0] == 0
|
doAssert b[0] == 0
|
||||||
doAssert b[1] == 1
|
doAssert b[1] == 1
|
||||||
|
|
||||||
#test collect
|
block: # collect
|
||||||
import sets, tables
|
|
||||||
|
|
||||||
let data = @["bird", "word"] # if this gets stuck in your head, its not my fault
|
let data = @["bird", "word"] # if this gets stuck in your head, its not my fault
|
||||||
doAssert collect(newSeq, for (i, d) in data.pairs: (if i mod 2 == 0: d)) == @["bird"]
|
|
||||||
doAssert collect(initTable(2), for (i, d) in data.pairs: {i: d}) == {0: "bird",
|
|
||||||
1: "word"}.toTable
|
|
||||||
doAssert initHashSet.collect(for d in data.items: {d}) == data.toHashSet
|
|
||||||
|
|
||||||
|
doAssert collect(newSeq, for (i, d) in data.pairs: (if i mod 2 == 0: d)) == @["bird"]
|
||||||
|
doAssert collect(initTable(2), for (i, d) in data.pairs: {i: d}) ==
|
||||||
|
{0: "bird", 1: "word"}.toTable
|
||||||
|
doAssert collect(initHashSet(), for d in data.items: {d}) == data.toHashSet
|
||||||
|
|
||||||
|
block:
|
||||||
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"]
|
doAssert x == @["bird"]
|
||||||
|
|
||||||
# bug #12874
|
block: # bug #12874
|
||||||
|
let bug = collect(
|
||||||
let bug1 = collect(
|
|
||||||
newSeq,
|
newSeq,
|
||||||
for (i, d) in data.pairs:(
|
for (i, d) in data.pairs:(
|
||||||
block:
|
block:
|
||||||
|
|
@ -69,14 +148,15 @@ let bug1 = collect(
|
||||||
d & d
|
d & d
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
doAssert bug1 == @["bird", "wordword"]
|
doAssert bug == @["bird", "wordword"]
|
||||||
|
|
||||||
import strutils
|
block:
|
||||||
let y = collect(newSeq):
|
let y = collect(newSeq):
|
||||||
for (i, d) in data.pairs:
|
for (i, d) in data.pairs:
|
||||||
try: parseInt(d) except: 0
|
try: parseInt(d) except: 0
|
||||||
doAssert y == @[0, 0]
|
doAssert y == @[0, 0]
|
||||||
|
|
||||||
|
block:
|
||||||
let z = collect(newSeq):
|
let z = collect(newSeq):
|
||||||
for (i, d) in data.pairs:
|
for (i, d) in data.pairs:
|
||||||
case d
|
case d
|
||||||
|
|
@ -84,13 +164,14 @@ let z = collect(newSeq):
|
||||||
else: d
|
else: d
|
||||||
doAssert z == @["word", "word"]
|
doAssert z == @["word", "word"]
|
||||||
|
|
||||||
proc tforum =
|
block:
|
||||||
let ans = collect(newSeq):
|
proc tforum(): seq[int] =
|
||||||
|
collect(newSeq):
|
||||||
for y in 0..10:
|
for y in 0..10:
|
||||||
if y mod 5 == 2:
|
if y mod 5 == 2:
|
||||||
for x in 0..y:
|
for x in 0..y:
|
||||||
x
|
x
|
||||||
tforum()
|
doAssert tforum() == @[0, 1, 2, 0, 1, 2, 3, 4, 5, 6, 7]
|
||||||
|
|
||||||
block:
|
block:
|
||||||
let x = collect:
|
let x = collect:
|
||||||
|
|
@ -98,17 +179,27 @@ block:
|
||||||
when d is int: "word"
|
when d is int: "word"
|
||||||
else: d
|
else: d
|
||||||
doAssert x == @["bird", "word"]
|
doAssert x == @["bird", "word"]
|
||||||
|
|
||||||
|
block:
|
||||||
doAssert collect(for (i, d) in pairs(data): (i, d)) == @[(0, "bird"), (1, "word")]
|
doAssert collect(for (i, d) in pairs(data): (i, d)) == @[(0, "bird"), (1, "word")]
|
||||||
doAssert collect(for d in data.items: (try: parseInt(d) except: 0)) == @[0, 0]
|
doAssert collect(for d in data.items: (try: parseInt(d) except: 0)) == @[0, 0]
|
||||||
doAssert collect(for (i, d) in pairs(data): {i: d}) == {1: "word",
|
doAssert collect(for (i, d) in pairs(data): {i: d}) ==
|
||||||
0: "bird"}.toTable
|
{1: "word", 0: "bird"}.toTable
|
||||||
doAssert collect(for d in data.items: {d}) == data.toHashSet
|
doAssert collect(for d in data.items: {d}) == data.toHashSet
|
||||||
|
|
||||||
# bug #14332
|
block: # bug #14332
|
||||||
template foo =
|
template foo =
|
||||||
discard collect(newSeq, for i in 1..3: i)
|
discard collect(newSeq, for i in 1..3: i)
|
||||||
foo()
|
foo()
|
||||||
|
|
||||||
|
proc mainProc() =
|
||||||
|
block: # dump
|
||||||
|
# symbols in templates are gensym'd
|
||||||
|
let
|
||||||
|
x = 10
|
||||||
|
y = 20
|
||||||
|
dump(x + y) # x + y = 30
|
||||||
|
|
||||||
block: # dumpToString
|
block: # dumpToString
|
||||||
template square(x): untyped = x * x
|
template square(x): untyped = x * x
|
||||||
let x = 10
|
let x = 10
|
||||||
|
|
@ -118,3 +209,9 @@ block: # dumpToString
|
||||||
let s2 = dumpToString:
|
let s2 = dumpToString:
|
||||||
doAssertRaises(AssertionDefect): doAssert false
|
doAssertRaises(AssertionDefect): doAssert false
|
||||||
doAssert "except AssertionDefect" in s2
|
doAssert "except AssertionDefect" in s2
|
||||||
|
|
||||||
|
static:
|
||||||
|
main()
|
||||||
|
mainProc()
|
||||||
|
main()
|
||||||
|
mainProc()
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue