new tester; all tests categorized
This commit is contained in:
parent
51ee524109
commit
20b5f31c03
481 changed files with 794 additions and 2506 deletions
47
tests/closure/tclosure.nim
Normal file
47
tests/closure/tclosure.nim
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
discard """
|
||||
file: "tclosure.nim"
|
||||
output: "2 4 6 8 10"
|
||||
disabled: true
|
||||
"""
|
||||
# Test the closure implementation
|
||||
|
||||
proc map(n: var openarray[int], fn: proc (x: int): int {.closure}) =
|
||||
for i in 0..n.len-1: n[i] = fn(n[i])
|
||||
|
||||
proc foldr(n: openarray[int], fn: proc (x, y: int): int {.closure}): int =
|
||||
for i in 0..n.len-1:
|
||||
result = fn(result, n[i])
|
||||
|
||||
proc each(n: openarray[int], fn: proc(x: int) {.closure.}) =
|
||||
for i in 0..n.len-1:
|
||||
fn(n[i])
|
||||
|
||||
var
|
||||
myData: array[0..4, int] = [0, 1, 2, 3, 4]
|
||||
|
||||
proc testA() =
|
||||
var p = 0
|
||||
map(myData, proc (x: int): int =
|
||||
result = x + 1 shl (proc (y: int): int =
|
||||
return y + p
|
||||
)(0)
|
||||
inc(p))
|
||||
|
||||
testA()
|
||||
|
||||
myData.each do (x: int):
|
||||
write(stout, x)
|
||||
|
||||
#OUT 2 4 6 8 10
|
||||
|
||||
type
|
||||
ITest = tuple[
|
||||
setter: proc(v: Int),
|
||||
getter: proc(): int]
|
||||
|
||||
proc getInterf(): ITest =
|
||||
var shared: int
|
||||
|
||||
return (setter: proc (x) = shared = x,
|
||||
getter: proc (): int = return shared)
|
||||
|
||||
101
tests/closure/tclosure2.nim
Normal file
101
tests/closure/tclosure2.nim
Normal file
|
|
@ -0,0 +1,101 @@
|
|||
discard """
|
||||
output: '''0
|
||||
11
|
||||
1
|
||||
11
|
||||
2
|
||||
11
|
||||
3
|
||||
11
|
||||
4
|
||||
11
|
||||
5
|
||||
11
|
||||
6
|
||||
11
|
||||
7
|
||||
11
|
||||
8
|
||||
11
|
||||
9
|
||||
11
|
||||
11
|
||||
py
|
||||
py
|
||||
py
|
||||
py
|
||||
px
|
||||
6'''
|
||||
"""
|
||||
|
||||
when true:
|
||||
proc ax =
|
||||
for xxxx in 0..9:
|
||||
var i = 0
|
||||
proc bx =
|
||||
if i > 10:
|
||||
echo xxxx
|
||||
return
|
||||
i += 1
|
||||
#for j in 0 .. 0: echo i
|
||||
bx()
|
||||
|
||||
bx()
|
||||
echo i
|
||||
|
||||
ax()
|
||||
|
||||
when true:
|
||||
proc accumulator(start: int): (proc(): int {.closure.}) =
|
||||
var x = start-1
|
||||
#let dummy = proc =
|
||||
# discard start
|
||||
|
||||
result = proc (): int =
|
||||
#var x = 9
|
||||
for i in 0 .. 0: x = x + 1
|
||||
|
||||
return x
|
||||
|
||||
var a = accumulator(3)
|
||||
let b = accumulator(4)
|
||||
echo a() + b() + a()
|
||||
|
||||
|
||||
proc outer =
|
||||
|
||||
proc py() =
|
||||
# no closure here:
|
||||
for i in 0..3: echo "py"
|
||||
|
||||
py()
|
||||
|
||||
outer()
|
||||
|
||||
|
||||
when true:
|
||||
proc outer2 =
|
||||
var errorValue = 3
|
||||
proc fac[T](n: T): T =
|
||||
if n < 0: result = errorValue
|
||||
elif n <= 1: result = 1
|
||||
else: result = n * fac(n-1)
|
||||
|
||||
proc px() {.closure.} =
|
||||
echo "px"
|
||||
|
||||
proc py() {.closure.} =
|
||||
echo "py"
|
||||
|
||||
const
|
||||
mapping = {
|
||||
"abc": px,
|
||||
"xyz": py
|
||||
}
|
||||
mapping[0][1]()
|
||||
|
||||
echo fac(3)
|
||||
|
||||
|
||||
outer2()
|
||||
|
||||
20
tests/closure/tclosure3.nim
Normal file
20
tests/closure/tclosure3.nim
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
discard """
|
||||
file: "tclosure3.nim"
|
||||
output: "success"
|
||||
"""
|
||||
|
||||
proc main =
|
||||
const n = 30
|
||||
for iterations in 0..50_000:
|
||||
var s: seq[proc(): string {.closure.}] = @[]
|
||||
for i in 0 .. n-1:
|
||||
let ii = i
|
||||
s.add(proc(): string = return $(ii*ii))
|
||||
for i in 0 .. n-1:
|
||||
let val = s[i]()
|
||||
if val != $(i*i): echo "bug ", val
|
||||
|
||||
if getOccupiedMem() > 3000_000: quit("still a leak!")
|
||||
echo "success"
|
||||
|
||||
main()
|
||||
13
tests/closure/tclosure4.nim
Normal file
13
tests/closure/tclosure4.nim
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
|
||||
import json, tables
|
||||
|
||||
proc run(json_params: TTable) =
|
||||
let json_elems = json_params["files"].elems
|
||||
# These fail compilation.
|
||||
var files = map(json_elems, proc (x: PJsonNode): string = x.str)
|
||||
#var files = json_elems.map do (x: PJsonNode) -> string: x.str
|
||||
echo "Hey!"
|
||||
|
||||
when isMainModule:
|
||||
let text = """{"files": ["a", "b", "c"]}"""
|
||||
run(toTable((text.parseJson).fields))
|
||||
194
tests/closure/tclosurebug2.nim
Normal file
194
tests/closure/tclosurebug2.nim
Normal file
|
|
@ -0,0 +1,194 @@
|
|||
import hashes, math
|
||||
|
||||
type
|
||||
TSlotEnum = enum seEmpty, seFilled, seDeleted
|
||||
TKeyValuePair[A, B] = tuple[slot: TSlotEnum, key: A, val: B]
|
||||
TKeyValuePairSeq[A, B] = seq[TKeyValuePair[A, B]]
|
||||
|
||||
TOrderedKeyValuePair[A, B] = tuple[
|
||||
slot: TSlotEnum, next: int, key: A, val: B]
|
||||
TOrderedKeyValuePairSeq[A, B] = seq[TOrderedKeyValuePair[A, B]]
|
||||
TOrderedTable*[A, B] = object ## table that remembers insertion order
|
||||
data: TOrderedKeyValuePairSeq[A, B]
|
||||
counter, first, last: int
|
||||
|
||||
const
|
||||
growthFactor = 2
|
||||
|
||||
proc mustRehash(length, counter: int): bool {.inline.} =
|
||||
assert(length > counter)
|
||||
result = (length * 2 < counter * 3) or (length - counter < 4)
|
||||
|
||||
proc nextTry(h, maxHash: THash): THash {.inline.} =
|
||||
result = ((5 * h) + 1) and maxHash
|
||||
|
||||
template rawGetImpl() {.dirty.} =
|
||||
var h: THash = hash(key) and high(t.data) # start with real hash value
|
||||
while t.data[h].slot != seEmpty:
|
||||
if t.data[h].key == key and t.data[h].slot == seFilled:
|
||||
return h
|
||||
h = nextTry(h, high(t.data))
|
||||
result = -1
|
||||
|
||||
template rawInsertImpl() {.dirty.} =
|
||||
var h: THash = hash(key) and high(data)
|
||||
while data[h].slot == seFilled:
|
||||
h = nextTry(h, high(data))
|
||||
data[h].key = key
|
||||
data[h].val = val
|
||||
data[h].slot = seFilled
|
||||
|
||||
template AddImpl() {.dirty.} =
|
||||
if mustRehash(len(t.data), t.counter): Enlarge(t)
|
||||
RawInsert(t, t.data, key, val)
|
||||
inc(t.counter)
|
||||
|
||||
template PutImpl() {.dirty.} =
|
||||
var index = RawGet(t, key)
|
||||
if index >= 0:
|
||||
t.data[index].val = val
|
||||
else:
|
||||
AddImpl()
|
||||
|
||||
proc len*[A, B](t: TOrderedTable[A, B]): int {.inline.} =
|
||||
## returns the number of keys in `t`.
|
||||
result = t.counter
|
||||
|
||||
template forAllOrderedPairs(yieldStmt: stmt) {.dirty, immediate.} =
|
||||
var h = t.first
|
||||
while h >= 0:
|
||||
var nxt = t.data[h].next
|
||||
if t.data[h].slot == seFilled: yieldStmt
|
||||
h = nxt
|
||||
|
||||
iterator pairs*[A, B](t: TOrderedTable[A, B]): tuple[key: A, val: B] =
|
||||
## iterates over any (key, value) pair in the table `t` in insertion
|
||||
## order.
|
||||
forAllOrderedPairs:
|
||||
yield (t.data[h].key, t.data[h].val)
|
||||
|
||||
iterator mpairs*[A, B](t: var TOrderedTable[A, B]): tuple[key: A, val: var B] =
|
||||
## iterates over any (key, value) pair in the table `t` in insertion
|
||||
## order. The values can be modified.
|
||||
forAllOrderedPairs:
|
||||
yield (t.data[h].key, t.data[h].val)
|
||||
|
||||
iterator keys*[A, B](t: TOrderedTable[A, B]): A =
|
||||
## iterates over any key in the table `t` in insertion order.
|
||||
forAllOrderedPairs:
|
||||
yield t.data[h].key
|
||||
|
||||
iterator values*[A, B](t: TOrderedTable[A, B]): B =
|
||||
## iterates over any value in the table `t` in insertion order.
|
||||
forAllOrderedPairs:
|
||||
yield t.data[h].val
|
||||
|
||||
iterator mvalues*[A, B](t: var TOrderedTable[A, B]): var B =
|
||||
## iterates over any value in the table `t` in insertion order. The values
|
||||
## can be modified.
|
||||
forAllOrderedPairs:
|
||||
yield t.data[h].val
|
||||
|
||||
proc RawGet[A, B](t: TOrderedTable[A, B], key: A): int =
|
||||
rawGetImpl()
|
||||
|
||||
proc `[]`*[A, B](t: TOrderedTable[A, B], key: A): B =
|
||||
## retrieves the value at ``t[key]``. If `key` is not in `t`,
|
||||
## default empty value for the type `B` is returned
|
||||
## and no exception is raised. One can check with ``hasKey`` whether the key
|
||||
## exists.
|
||||
var index = RawGet(t, key)
|
||||
if index >= 0: result = t.data[index].val
|
||||
|
||||
proc mget*[A, B](t: var TOrderedTable[A, B], key: A): var B =
|
||||
## retrieves the value at ``t[key]``. The value can be modified.
|
||||
## If `key` is not in `t`, the ``EInvalidKey`` exception is raised.
|
||||
var index = RawGet(t, key)
|
||||
if index >= 0: result = t.data[index].val
|
||||
else: raise newException(EInvalidKey, "key not found: " & $key)
|
||||
|
||||
proc hasKey*[A, B](t: TOrderedTable[A, B], key: A): bool =
|
||||
## returns true iff `key` is in the table `t`.
|
||||
result = rawGet(t, key) >= 0
|
||||
|
||||
proc RawInsert[A, B](t: var TOrderedTable[A, B],
|
||||
data: var TOrderedKeyValuePairSeq[A, B],
|
||||
key: A, val: B) =
|
||||
rawInsertImpl()
|
||||
data[h].next = -1
|
||||
if t.first < 0: t.first = h
|
||||
if t.last >= 0: data[t.last].next = h
|
||||
t.last = h
|
||||
|
||||
proc Enlarge[A, B](t: var TOrderedTable[A, B]) =
|
||||
var n: TOrderedKeyValuePairSeq[A, B]
|
||||
newSeq(n, len(t.data) * growthFactor)
|
||||
var h = t.first
|
||||
t.first = -1
|
||||
t.last = -1
|
||||
while h >= 0:
|
||||
var nxt = t.data[h].next
|
||||
if t.data[h].slot == seFilled:
|
||||
RawInsert(t, n, t.data[h].key, t.data[h].val)
|
||||
h = nxt
|
||||
swap(t.data, n)
|
||||
|
||||
proc `[]=`*[A, B](t: var TOrderedTable[A, B], key: A, val: B) =
|
||||
## puts a (key, value)-pair into `t`.
|
||||
putImpl()
|
||||
|
||||
proc add*[A, B](t: var TOrderedTable[A, B], key: A, val: B) =
|
||||
## puts a new (key, value)-pair into `t` even if ``t[key]`` already exists.
|
||||
AddImpl()
|
||||
|
||||
proc initOrderedTable*[A, B](initialSize=64): TOrderedTable[A, B] =
|
||||
## creates a new ordered hash table that is empty. `initialSize` needs to be
|
||||
## a power of two.
|
||||
assert isPowerOfTwo(initialSize)
|
||||
result.counter = 0
|
||||
result.first = -1
|
||||
result.last = -1
|
||||
newSeq(result.data, initialSize)
|
||||
|
||||
proc toOrderedTable*[A, B](pairs: openarray[tuple[key: A,
|
||||
val: B]]): TOrderedTable[A, B] =
|
||||
## creates a new ordered hash table that contains the given `pairs`.
|
||||
result = initOrderedTable[A, B](nextPowerOfTwo(pairs.len+10))
|
||||
for key, val in items(pairs): result[key] = val
|
||||
|
||||
proc sort*[A, B](t: var TOrderedTable[A,B],
|
||||
cmp: proc (x, y: tuple[key: A, val: B]): int {.closure.}) =
|
||||
## sorts the ordered table so that the entry with the highest counter comes
|
||||
## first. This is destructive (with the advantage of being efficient)!
|
||||
## You must not modify `t` afterwards!
|
||||
## You can use the iterators `pairs`, `keys`, and `values` to iterate over
|
||||
## `t` in the sorted order.
|
||||
|
||||
# we use shellsort here; fast enough and simple
|
||||
var h = 1
|
||||
while true:
|
||||
h = 3 * h + 1
|
||||
if h >= high(t.data): break
|
||||
while true:
|
||||
h = h div 3
|
||||
for i in countup(h, high(t.data)):
|
||||
var j = i
|
||||
#echo(t.data.len, " ", j, " - ", h)
|
||||
#echo(repr(t.data[j-h]))
|
||||
proc rawCmp(x, y: TOrderedKeyValuePair[A, B]): int =
|
||||
if x.slot in {seEmpty, seDeleted} and y.slot in {seEmpty, seDeleted}:
|
||||
return 0
|
||||
elif x.slot in {seEmpty, seDeleted}:
|
||||
return -1
|
||||
elif y.slot in {seEmpty, seDeleted}:
|
||||
return 1
|
||||
else:
|
||||
let item1 = (x.key, x.val)
|
||||
let item2 = (y.key, y.val)
|
||||
return cmp(item1, item2)
|
||||
|
||||
while rawCmp(t.data[j-h], t.data[j]) <= 0:
|
||||
swap(t.data[j], t.data[j-h])
|
||||
j = j-h
|
||||
if j < h: break
|
||||
if h == 1: break
|
||||
24
tests/closure/tinterf.nim
Normal file
24
tests/closure/tinterf.nim
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
discard """
|
||||
output: '''56 66'''
|
||||
"""
|
||||
|
||||
type
|
||||
ITest = tuple[
|
||||
setter: proc(v: int) {.closure.},
|
||||
getter1: proc(): int {.closure.},
|
||||
getter2: proc(): int {.closure.}]
|
||||
|
||||
proc getInterf(): ITest =
|
||||
var shared1, shared2: int
|
||||
|
||||
return (setter: proc (x: int) =
|
||||
shared1 = x
|
||||
shared2 = x + 10,
|
||||
getter1: proc (): int = result = shared1,
|
||||
getter2: proc (): int = return shared2)
|
||||
|
||||
var i = getInterf()
|
||||
i.setter(56)
|
||||
|
||||
echo i.getter1(), " ", i.getter2()
|
||||
|
||||
12
tests/closure/tinvalidclosure.nim
Normal file
12
tests/closure/tinvalidclosure.nim
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
discard """
|
||||
line: 12
|
||||
errormsg: "type mismatch: got (proc (int){.closure.})"
|
||||
"""
|
||||
|
||||
proc ugh[T](x: T) {.closure.} =
|
||||
echo "ugha"
|
||||
|
||||
|
||||
proc takeCdecl(p: proc (x: int) {.cdecl.}) = nil
|
||||
|
||||
takeCDecl(ugh[int])
|
||||
14
tests/closure/tinvalidclosure2.nim
Normal file
14
tests/closure/tinvalidclosure2.nim
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
discard """
|
||||
line: 10
|
||||
errormsg: "illegal capture 'A'"
|
||||
"""
|
||||
|
||||
proc outer() =
|
||||
var A: int
|
||||
|
||||
proc ugh[T](x: T) {.cdecl.} =
|
||||
echo "ugha", A, x
|
||||
|
||||
ugh[int](12)
|
||||
|
||||
outer()
|
||||
14
tests/closure/tnamedparamanonproc.nim
Normal file
14
tests/closure/tnamedparamanonproc.nim
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
|
||||
type
|
||||
PButton = ref object
|
||||
TButtonClicked = proc(button: PButton) {.nimcall.}
|
||||
|
||||
proc newButton*(onClick: TButtonClicked) =
|
||||
nil
|
||||
|
||||
proc main() =
|
||||
newButton(onClick = proc(b: PButton) =
|
||||
var requestomat = 12
|
||||
)
|
||||
|
||||
main()
|
||||
12
tests/closure/tnestedproc.nim
Normal file
12
tests/closure/tnestedproc.nim
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
discard """
|
||||
output: "11"
|
||||
"""
|
||||
|
||||
proc p(x, y: int): int =
|
||||
result = x + y
|
||||
|
||||
echo p((proc (): int =
|
||||
var x = 7
|
||||
return x)(),
|
||||
(proc (): int = return 4)())
|
||||
|
||||
12
tests/closure/uclosures.nim
Normal file
12
tests/closure/uclosures.nim
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
import unittest
|
||||
|
||||
test "loop variables are captured by copy":
|
||||
var funcs: seq[proc (): int {.closure.}] = @[]
|
||||
|
||||
for i in 0..10:
|
||||
let ii = i
|
||||
funcs.add do -> int: return ii * ii
|
||||
|
||||
check funcs[0]() == 0
|
||||
check funcs[3]() == 9
|
||||
|
||||
Loading…
Add table
Add a link
Reference in a new issue