Sugar tests (#16820)

This commit is contained in:
konsumlamm
2021-02-03 03:11:59 +01:00
committed by GitHub
parent e4ad0ae5c4
commit f4449a897d
2 changed files with 208 additions and 109 deletions

View File

@@ -53,8 +53,8 @@ proc createProcType(p, b: NimNode): NimNode {.compileTime.} =
result.add prag
macro `=>`*(p, b: untyped): untyped =
## Syntax sugar for anonymous procedures.
## It also supports pragmas.
## Syntax sugar for anonymous procedures. It also supports pragmas.
# TODO: xxx pending #13491: uncomment in runnableExamples
runnableExamples:
proc passTwoAndTwo(f: (int, int) -> int): int = f(2, 2)
@@ -62,13 +62,16 @@ macro `=>`*(p, b: untyped): untyped =
type
Bot = object
call: proc (name: string): string {.noSideEffect.}
call: (string {.noSideEffect.} -> string)
var myBot = Bot()
myBot.call = (name: string) {.noSideEffect.} => "Hello " & name & ", I'm a bot."
doAssert myBot.call("John") == "Hello John, I'm a bot."
# let f = () => (discard) # simplest proc that returns void
# f()
var
params = @[ident"auto"]
name = newEmptyNode()
@@ -140,15 +143,20 @@ macro `=>`*(p, b: untyped): untyped =
procType = kind)
macro `->`*(p, b: untyped): untyped =
## Syntax sugar for procedure types.
## Syntax sugar for procedure types. It also supports pragmas.
runnableExamples:
proc passTwoAndTwo(f: (int, int) -> int): int = f(2, 2)
# is the same as:
# proc passTwoAndTwo(f: proc (x, y: int): int): int = f(2, 2)
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)
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
## by their current iteration values.
runnableExamples:
import std/[strformat, sequtils]
import std/strformat
var myClosure: () -> string
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"
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")]
let locals = if locals.len == 1 and locals[0].kind == nnkBracket: locals[0]
else: locals

View File

@@ -1,120 +1,217 @@
import sugar
discard """
output: '''
x + y = 30
'''
"""
import std/[sugar, algorithm, random, sets, tables, strutils]
block dup_with_field:
type
Foo = object
col, pos: int
name: string
template main() =
block: # `=>`
block:
let f1 = () => 42
doAssert f1() == 42
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 f2 = (x: int) => x + 1
doAssert f2(42) == 43
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
let f3 = (x, y: int) => x + y
doAssert f3(1, 2) == 3
doAssert(b == Foo(col: 2, pos: 4, name: "foobar"))
var x = 0
let f4 = () => (x = 12)
f4()
doAssert x == 12
block:
let b = a.dup(inc_col, pos = 3, name = "bar"):
name_append("bar")
inc_pos
let f5 = () => (discard) # simplest proc that returns void
f5()
doAssert(b == Foo(col: 2, pos: 4, name: "barbar"))
block:
proc call1(f: () -> int): int = f()
doAssert call1(() => 12) == 12
import algorithm
proc call2(f: int -> int): int = f(42)
doAssert call2(x => x) == 42
doAssert call2((x) => x) == 42
doAssert call2((x: int) => x) == 42
var a = @[1, 2, 3, 4, 5, 6, 7, 8, 9]
doAssert dup(a, sort(_)) == sorted(a)
doAssert a.dup(sort) == sorted(a)
#Chaining:
var aCopy = a
aCopy.insert(10)
doAssert a.dup(insert(10)).dup(sort()) == sorted(aCopy)
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
import random
var a = 0
proc call4(f: int -> void) = f(42)
call4((x: int) => (a = x))
doAssert a == 42
const b = @[0, 1, 2]
let c = b.dup shuffle()
doAssert b[0] == 0
doAssert b[1] == 1
proc call5(f: (int {.noSideEffect.} -> int)): int = f(42)
doAssert call5(x {.noSideEffect.} => x + 1) == 43
#test collect
import sets, tables
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.}"
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 $(() -> 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.}"
let x = collect(newSeqOfCap(4)):
for (i, d) in data.pairs:
if i mod 2 == 0: d
doAssert x == @["bird"]
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.}"
# bug #12874
block: # capture
var closure1: () -> int
for i in 0 .. 10:
if i == 5:
capture i:
closure1 = () => i
doAssert closure1() == 5
let bug1 = collect(
newSeq,
for (i, d) in data.pairs:(
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:
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:
if i mod 2 == 0:
d
else:
d & d
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"))
block:
var a = @[1, 2, 3, 4, 5, 6, 7, 8, 9]
doAssert dup(a, sort(_)) == sorted(a)
doAssert a.dup(sort) == sorted(a)
# Chaining:
var aCopy = a
aCopy.insert(10)
doAssert a.dup(insert(10)).dup(sort()) == sorted(aCopy)
block:
when nimvm: discard
else:
const b = @[0, 1, 2]
discard b.dup shuffle()
doAssert b[0] == 0
doAssert b[1] == 1
block: # collect
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 collect(initHashSet(), for d in data.items: {d}) == data.toHashSet
block:
let x = collect(newSeqOfCap(4)):
for (i, d) in data.pairs:
if i mod 2 == 0: d
doAssert x == @["bird"]
block: # bug #12874
let bug = collect(
newSeq,
for (i, d) in data.pairs:(
block:
if i mod 2 == 0:
d
else:
d & d
)
)
)
doAssert bug1 == @["bird", "wordword"]
doAssert bug == @["bird", "wordword"]
import strutils
let y = collect(newSeq):
for (i, d) in data.pairs:
try: parseInt(d) except: 0
doAssert y == @[0, 0]
block:
let y = collect(newSeq):
for (i, d) in data.pairs:
try: parseInt(d) except: 0
doAssert y == @[0, 0]
let z = collect(newSeq):
for (i, d) in data.pairs:
case d
of "bird": "word"
else: d
doAssert z == @["word", "word"]
block:
let z = collect(newSeq):
for (i, d) in data.pairs:
case d
of "bird": "word"
else: d
doAssert z == @["word", "word"]
proc tforum =
let ans = collect(newSeq):
for y in 0..10:
if y mod 5 == 2:
for x in 0..y:
x
tforum()
block:
proc tforum(): seq[int] =
collect(newSeq):
for y in 0..10:
if y mod 5 == 2:
for x in 0..y:
x
doAssert tforum() == @[0, 1, 2, 0, 1, 2, 3, 4, 5, 6, 7]
block:
let x = collect:
for d in data.items:
when d is int: "word"
else: d
doAssert x == @["bird", "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 (i, d) in pairs(data): {i: d}) == {1: "word",
0: "bird"}.toTable
doAssert collect(for d in data.items: {d}) == data.toHashSet
block:
let x = collect:
for d in data.items:
when d is int: "word"
else: d
doAssert x == @["bird", "word"]
# bug #14332
template foo =
discard collect(newSeq, for i in 1..3: i)
foo()
block:
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 (i, d) in pairs(data): {i: d}) ==
{1: "word", 0: "bird"}.toTable
doAssert collect(for d in data.items: {d}) == data.toHashSet
block: # dumpToString
template square(x): untyped = x * x
let x = 10
doAssert dumpToString(square(x)) == "square(x): x * x = 100"
let s = dumpToString(doAssert 1+1 == 2)
doAssert "failedAssertImpl" in s
let s2 = dumpToString:
doAssertRaises(AssertionDefect): doAssert false
doAssert "except AssertionDefect" in s2
block: # bug #14332
template foo =
discard collect(newSeq, for i in 1..3: i)
foo()
proc mainProc() =
block: # dump
# symbols in templates are gensym'd
let
x = 10
y = 20
dump(x + y) # x + y = 30
block: # dumpToString
template square(x): untyped = x * x
let x = 10
doAssert dumpToString(square(x)) == "square(x): x * x = 100"
let s = dumpToString(doAssert 1+1 == 2)
doAssert "failedAssertImpl" in s
let s2 = dumpToString:
doAssertRaises(AssertionDefect): doAssert false
doAssert "except AssertionDefect" in s2
static:
main()
mainProc()
main()
mainProc()