From 63f93853270d8b44ee42b34e5f52e3718b88d563 Mon Sep 17 00:00:00 2001 From: def Date: Tue, 31 Mar 2015 00:04:31 +0200 Subject: [PATCH 01/32] Rename mget to `[]` - In sets, tables, strtabs, critbits, xmltree - This uses the new var parameter overloading - mget variants still exist, but are deprecated in favor of `[]` - Includes tests and fixed tests and usages of mget - The non-var `[]` now throws an exception instead of returning binary 0 or an empty string --- lib/pure/collections/critbits.nim | 48 ++++++---- lib/pure/collections/sets.nim | 9 +- lib/pure/collections/tables.nim | 138 +++++++++++++++++----------- lib/pure/strtabs.nim | 31 ++++--- lib/pure/xmltree.nim | 9 +- lib/system/sets.nim | 2 +- tests/actiontable/tactiontable.nim | 15 ++- tests/collections/ttables.nim | 19 ++-- tests/collections/ttablesref.nim | 21 +++-- tests/misc/teventemitter.nim | 9 +- tests/stdlib/tmget.nim | 141 +++++++++++++++++++++++++++++ tests/stdlib/tmitems.nim | 2 +- 12 files changed, 322 insertions(+), 122 deletions(-) create mode 100644 tests/stdlib/tmget.nim diff --git a/lib/pure/collections/critbits.nim b/lib/pure/collections/critbits.nim index 3d10e39aa3..fb5fd7f36f 100644 --- a/lib/pure/collections/critbits.nim +++ b/lib/pure/collections/critbits.nim @@ -17,11 +17,11 @@ type otherbits: char case isLeaf: bool of false: child: array[0..1, ref NodeObj[T]] - of true: + of true: key: string when T isnot void: val: T - + Node[T] = ref NodeObj[T] CritBitTree*[T] = object ## The crit bit tree can either be used ## as a mapping from strings to @@ -66,7 +66,7 @@ proc rawInsert[T](c: var CritBitTree[T], key: string): Node[T] = let ch = if it.byte < key.len: key[it.byte] else: '\0' let dir = (1 + (ch.ord or it.otherBits.ord)) shr 8 it = it.child[dir] - + var newOtherBits = 0 var newByte = 0 block blockX: @@ -84,7 +84,7 @@ proc rawInsert[T](c: var CritBitTree[T], key: string): Node[T] = newOtherBits = newOtherBits xor 255 let ch = it.key[newByte] let dir = (1 + (ord(ch) or newOtherBits)) shr 8 - + var inner: Node[T] new inner new result @@ -93,7 +93,7 @@ proc rawInsert[T](c: var CritBitTree[T], key: string): Node[T] = inner.otherBits = chr(newOtherBits) inner.byte = newByte inner.child[1 - dir] = result - + var wherep = addr(c.root) while true: var p = wherep[] @@ -132,20 +132,31 @@ proc `[]=`*[T](c: var CritBitTree[T], key: string, val: T) = var n = rawInsert(c, key) n.val = val -proc `[]`*[T](c: CritBitTree[T], key: string): T {.inline.} = - ## retrieves the value at ``c[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. +template get[T](c: CritBitTree[T], key: string): T {.immediate.} = let n = rawGet(c, key) if n != nil: result = n.val + else: + when compiles($key): + raise newException(KeyError, "key not found: " & $key) + else: + raise newException(KeyError, "key not found") -proc mget*[T](c: var CritBitTree[T], key: string): var T {.inline.} = +proc `[]`*[T](c: CritBitTree[T], key: string): T {.inline.} = + ## retrieves the value at ``c[key]``. If `key` is not in `t`, the + ## ``KeyError`` exception is raised. One can check with ``hasKey`` whether + ## the key exists. + get(c, key) + +proc `[]`*[T](c: var CritBitTree[T], key: string): var T {.inline.} = ## retrieves the value at ``c[key]``. The value can be modified. ## If `key` is not in `t`, the ``KeyError`` exception is raised. - let n = rawGet(c, key) - if n != nil: result = n.val - else: raise newException(KeyError, "key not found: " & $key) + get(c, key) + +proc mget*[T](c: var CritBitTree[T], key: string): var T {.inline, deprecated.} = + ## retrieves the value at ``c[key]``. The value can be modified. + ## If `key` is not in `t`, the ``KeyError`` exception is raised. + ## Use ```[]``` instead. + get(c, key) proc excl*[T](c: var CritBitTree[T], key: string) = ## removes `key` (and its associated value) from the set `c`. @@ -176,7 +187,7 @@ iterator leaves[T](n: Node[T]): Node[T] = # XXX actually we could compute the necessary stack size in advance: # it's roughly log2(c.count). var stack = @[n] - while stack.len > 0: + while stack.len > 0: var it = stack.pop while not it.isLeaf: stack.add(it.child[1]) @@ -205,7 +216,7 @@ iterator items*[T](c: CritBitTree[T]): string = iterator pairs*[T](c: CritBitTree[T]): tuple[key: string, val: T] = ## yields all (key, value)-pairs of `c`. for x in leaves(c.root): yield (x.key, x.val) - + iterator mpairs*[T](c: var CritBitTree[T]): tuple[key: string, val: var T] = ## yields all (key, value)-pairs of `c`. The yielded values can be modified. for x in leaves(c.root): yield (x.key, x.val) @@ -251,7 +262,7 @@ iterator pairsWithPrefix*[T](c: CritBitTree[T], ## yields all (key, value)-pairs of `c` starting with `prefix`. let top = allprefixedAux(c, prefix) for x in leaves(top): yield (x.key, x.val) - + iterator mpairsWithPrefix*[T](c: var CritBitTree[T], prefix: string): tuple[key: string, val: var T] = ## yields all (key, value)-pairs of `c` starting with `prefix`. @@ -297,7 +308,6 @@ when isMainModule: for w in r.items: echo w - + for w in r.itemsWithPrefix("de"): echo w - diff --git a/lib/pure/collections/sets.nim b/lib/pure/collections/sets.nim index 4a20d00a46..49271e2c98 100644 --- a/lib/pure/collections/sets.nim +++ b/lib/pure/collections/sets.nim @@ -154,7 +154,7 @@ proc rawGetKnownHC[A](s: HashSet[A], key: A, hc: THash): int {.inline.} = proc rawGet[A](s: HashSet[A], key: A, hc: var THash): int {.inline.} = rawGetImpl() -proc mget*[A](s: var HashSet[A], key: A): var A = +proc `[]`*[A](s: var HashSet[A], key: A): var A = ## returns the element that is actually stored in 's' which has the same ## value as 'key' or raises the ``EInvalidKey`` exception. This is useful ## when one overloaded 'hash' and '==' but still needs reference semantics @@ -165,6 +165,13 @@ proc mget*[A](s: var HashSet[A], key: A): var A = if index >= 0: result = s.data[index].key else: raise newException(KeyError, "key not found: " & $key) +proc mget*[A](s: var HashSet[A], key: A): var A {.deprecated.} = + ## returns the element that is actually stored in 's' which has the same + ## value as 'key' or raises the ``EInvalidKey`` exception. This is useful + ## when one overloaded 'hash' and '==' but still needs reference semantics + ## for sharing. Use ```[]``` instead. + s[key] + proc contains*[A](s: HashSet[A], key: A): bool = ## Returns true iff `key` is in `s`. ## diff --git a/lib/pure/collections/tables.nim b/lib/pure/collections/tables.nim index f85acef226..adc9c6d8d6 100644 --- a/lib/pure/collections/tables.nim +++ b/lib/pure/collections/tables.nim @@ -181,18 +181,7 @@ proc rawGetDeep[A, B](t: Table[A, B], key: A, hc: var THash): int {.inline.} = proc rawGet[A, B](t: Table[A, B], key: A, hc: var THash): int {.inline.} = rawGetImpl() -proc `[]`*[A, B](t: Table[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 hc: THash - var index = rawGet(t, key, hc) - if index >= 0: result = t.data[index].val - -proc mget*[A, B](t: var Table[A, B], key: A): var B = - ## retrieves the value at ``t[key]``. The value can be modified. - ## If `key` is not in `t`, the ``KeyError`` exception is raised. +template get[A, B](t: Table[A, B], key: A): B {.immediate.} = var hc: THash var index = rawGet(t, key, hc) if index >= 0: result = t.data[index].val @@ -202,6 +191,23 @@ proc mget*[A, B](t: var Table[A, B], key: A): var B = else: raise newException(KeyError, "key not found") +proc `[]`*[A, B](t: Table[A, B], key: A): B = + ## retrieves the value at ``t[key]``. If `key` is not in `t`, the + ## ``KeyError`` exception is raised. One can check with ``hasKey`` whether + ## the key exists. + get(t, key) + +proc `[]`*[A, B](t: var Table[A, B], key: A): var B = + ## retrieves the value at ``t[key]``. The value can be modified. + ## If `key` is not in `t`, the ``KeyError`` exception is raised. + get(t, key) + +proc mget*[A, B](t: var Table[A, B], key: A): var B {.deprecated.} = + ## retrieves the value at ``t[key]``. The value can be modified. + ## If `key` is not in `t`, the ``KeyError`` exception is raised. Use ```[]``` + ## instead. + get(t, key) + iterator allValues*[A, B](t: Table[A, B]; key: A): B = ## iterates over any value in the table `t` that belongs to the given `key`. var h: THash = hash(key) and high(t.data) @@ -386,17 +392,17 @@ iterator mvalues*[A, B](t: TableRef[A, B]): var B = for h in 0..high(t.data): if isFilled(t.data[h].hcode): yield t.data[h].val -proc `[]`*[A, B](t: TableRef[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. +proc `[]`*[A, B](t: TableRef[A, B], key: A): var B = + ## retrieves the value at ``t[key]``. If `key` is not in `t`, the + ## ``KeyError`` exception is raised. One can check with ``hasKey`` whether + ## the key exists. result = t[][key] -proc mget*[A, B](t: TableRef[A, B], key: A): var B = +proc mget*[A, B](t: TableRef[A, B], key: A): var B {.deprecated.} = ## retrieves the value at ``t[key]``. The value can be modified. - ## If `key` is not in `t`, the ``EInvalidKey`` exception is raised. - t[].mget(key) + ## If `key` is not in `t`, the ``KeyError`` exception is raised. + ## Use ```[]``` instead. + t[][key] proc mgetOrPut*[A, B](t: TableRef[A, B], key: A, val: B): var B = ## retrieves value at ``t[key]`` or puts ``val`` if not present, either way @@ -510,22 +516,32 @@ proc rawGetDeep[A, B](t: OrderedTable[A, B], key: A, hc: var THash): int {.inlin proc rawGet[A, B](t: OrderedTable[A, B], key: A, hc: var THash): int = rawGetImpl() -proc `[]`*[A, B](t: OrderedTable[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. +template get[A, B](t: OrderedTable[A, B], key: A): B {.immediate.} = var hc: THash var index = rawGet(t, key, hc) if index >= 0: result = t.data[index].val + else: + when compiles($key): + raise newException(KeyError, "key not found: " & $key) + else: + raise newException(KeyError, "key not found") -proc mget*[A, B](t: var OrderedTable[A, B], key: A): var B = +proc `[]`*[A, B](t: OrderedTable[A, B], key: A): B = + ## retrieves the value at ``t[key]``. If `key` is not in `t`, the + ## ``KeyError`` exception is raised. One can check with ``hasKey`` whether + ## the key exists. + get(t, key) + +proc `[]`*[A, B](t: var OrderedTable[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 hc: THash - var index = rawGet(t, key, hc) - if index >= 0: result = t.data[index].val - else: raise newException(KeyError, "key not found: " & $key) + ## If `key` is not in `t`, the ``KeyError`` exception is raised. + get(t, key) + +proc mget*[A, B](t: var OrderedTable[A, B], key: A): var B {.deprecated.} = + ## retrieves the value at ``t[key]``. The value can be modified. + ## If `key` is not in `t`, the ``KeyError`` exception is raised. + ## Use ```[]``` instead. + get(t, key) proc hasKey*[A, B](t: OrderedTable[A, B], key: A): bool = ## returns true iff `key` is in the table `t`. @@ -679,17 +695,17 @@ iterator mvalues*[A, B](t: OrderedTableRef[A, B]): var B = forAllOrderedPairs: yield t.data[h].val -proc `[]`*[A, B](t: OrderedTableRef[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. +proc `[]`*[A, B](t: OrderedTableRef[A, B], key: A): var B = + ## retrieves the value at ``t[key]``. If `key` is not in `t`, the + ## ``KeyError`` exception is raised. One can check with ``hasKey`` whether + ## the key exists. result = t[][key] -proc mget*[A, B](t: OrderedTableRef[A, B], key: A): var B = +proc mget*[A, B](t: OrderedTableRef[A, B], key: A): var B {.deprecated.} = ## retrieves the value at ``t[key]``. The value can be modified. - ## If `key` is not in `t`, the ``EInvalidKey`` exception is raised. - result = t[].mget(key) + ## If `key` is not in `t`, the ``KeyError`` exception is raised. + ## Use ```[]``` instead. + result = t[][key] proc mgetOrPut*[A, B](t: OrderedTableRef[A, B], key: A, val: B): var B = ## retrieves value at ``t[key]`` or puts ``val`` if not present, either way @@ -786,19 +802,31 @@ proc rawGet[A](t: CountTable[A], key: A): int = h = nextTry(h, high(t.data)) result = -1 - h # < 0 => MISSING; insert idx = -1 - result +template get[A](t: CountTable[A], key: A): int {.immediate.} = + var index = rawGet(t, key) + if index >= 0: result = t.data[index].val + else: + when compiles($key): + raise newException(KeyError, "key not found: " & $key) + else: + raise newException(KeyError, "key not found") + proc `[]`*[A](t: CountTable[A], key: A): int = ## retrieves the value at ``t[key]``. If `key` is not in `t`, - ## 0 is returned. One can check with ``hasKey`` whether the key - ## exists. - var index = rawGet(t, key) - if index >= 0: result = t.data[index].val + ## the ``KeyError`` exception is raised. One can check with ``hasKey`` + ## whether the key exists. + get(t, key) -proc mget*[A](t: var CountTable[A], key: A): var int = +proc `[]`*[A](t: var CountTable[A], key: A): var int = ## 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(KeyError, "key not found: " & $key) + ## If `key` is not in `t`, the ``KeyError`` exception is raised. + get(t, key) + +proc mget*[A](t: var CountTable[A], key: A): var int {.deprecated.} = + ## retrieves the value at ``t[key]``. The value can be modified. + ## If `key` is not in `t`, the ``KeyError`` exception is raised. + ## Use ```[]``` instead. + get(t, key) proc hasKey*[A](t: CountTable[A], key: A): bool = ## returns true iff `key` is in the table `t`. @@ -927,16 +955,16 @@ iterator mvalues*[A](t: CountTableRef[A]): var int = for h in 0..high(t.data): if t.data[h].val != 0: yield t.data[h].val -proc `[]`*[A](t: CountTableRef[A], key: A): int = - ## retrieves the value at ``t[key]``. If `key` is not in `t`, - ## 0 is returned. One can check with ``hasKey`` whether the key - ## exists. +proc `[]`*[A](t: CountTableRef[A], key: A): var int = + ## retrieves the value at ``t[key]``. The value can be modified. + ## If `key` is not in `t`, the ``KeyError`` exception is raised. result = t[][key] -proc mget*[A](t: CountTableRef[A], key: A): var int = +proc mget*[A](t: CountTableRef[A], key: A): var int {.deprecated.} = ## retrieves the value at ``t[key]``. The value can be modified. - ## If `key` is not in `t`, the ``EInvalidKey`` exception is raised. - result = t[].mget(key) + ## If `key` is not in `t`, the ``KeyError`` exception is raised. + ## Use ```[]``` instead. + result = t[][key] proc hasKey*[A](t: CountTableRef[A], key: A): bool = ## returns true iff `key` is in the table `t`. diff --git a/lib/pure/strtabs.nim b/lib/pure/strtabs.nim index 727d5a386d..6ed1bb9d8f 100644 --- a/lib/pure/strtabs.nim +++ b/lib/pure/strtabs.nim @@ -101,21 +101,26 @@ proc rawGet(t: StringTableRef, key: string): int = h = nextTry(h, high(t.data)) result = - 1 -proc `[]`*(t: StringTableRef, key: string): string {.rtl, extern: "nstGet".} = - ## retrieves the value at ``t[key]``. If `key` is not in `t`, "" is returned - ## and no exception is raised. One can check with ``hasKey`` whether the key - ## exists. +template get(t: StringTableRef, key: string): stmt {.immediate.} = var index = rawGet(t, key) if index >= 0: result = t.data[index].val - else: result = "" + else: + when compiles($key): + raise newException(KeyError, "key not found: " & $key) + else: + raise newException(KeyError, "key not found") -proc mget*(t: StringTableRef, key: string): var string {. - rtl, extern: "nstTake".} = +proc `[]`*(t: StringTableRef, key: string): var string {. + rtl, extern: "nstTake".} = ## retrieves the location at ``t[key]``. If `key` is not in `t`, the - ## ``KeyError`` exception is raised. - var index = rawGet(t, key) - if index >= 0: result = t.data[index].val - else: raise newException(KeyError, "key does not exist: " & key) + ## ``KeyError`` exception is raised. One can check with ``hasKey`` whether + ## the key exists. + get(t, key) + +proc mget*(t: StringTableRef, key: string): var string {.deprecated.} = + ## retrieves the location at ``t[key]``. If `key` is not in `t`, the + ## ``KeyError`` exception is raised. Use ```[]``` instead. + get(t, key) proc hasKey*(t: StringTableRef, key: string): bool {.rtl, extern: "nst$1".} = ## returns true iff `key` is in the table `t`. @@ -227,7 +232,7 @@ proc `$`*(t: StringTableRef): string {.rtl, extern: "nstDollar".} = result = "{:}" else: result = "{" - for key, val in pairs(t): + for key, val in pairs(t): if result.len > 1: result.add(", ") result.add(key) result.add(": ") @@ -239,6 +244,6 @@ when isMainModule: assert x["k"] == "v" assert x["11"] == "22" assert x["565"] == "67" - x.mget("11") = "23" + x["11"] = "23" assert x["11"] == "23" diff --git a/lib/pure/xmltree.nim b/lib/pure/xmltree.nim index 0bf5b52a46..832cedf474 100644 --- a/lib/pure/xmltree.nim +++ b/lib/pure/xmltree.nim @@ -115,11 +115,16 @@ proc `[]`* (n: XmlNode, i: int): XmlNode {.inline.} = assert n.k == xnElement result = n.s[i] -proc mget* (n: var XmlNode, i: int): var XmlNode {.inline.} = +proc `[]`* (n: var XmlNode, i: int): var XmlNode {.inline.} = ## returns the `i`'th child of `n` so that it can be modified assert n.k == xnElement result = n.s[i] +proc mget* (n: var XmlNode, i: int): var XmlNode {.inline, deprecated.} = + ## returns the `i`'th child of `n` so that it can be modified. Use ```[]``` + ## instead. + n[i] + iterator items*(n: XmlNode): XmlNode {.inline.} = ## iterates over any child of `n`. assert n.k == xnElement @@ -128,7 +133,7 @@ iterator items*(n: XmlNode): XmlNode {.inline.} = iterator mitems*(n: var XmlNode): var XmlNode {.inline.} = ## iterates over any child of `n`. assert n.k == xnElement - for i in 0 .. n.len-1: yield mget(n, i) + for i in 0 .. n.len-1: yield n[i] proc attrs*(n: XmlNode): XmlAttributes {.inline.} = ## gets the attributes belonging to `n`. diff --git a/lib/system/sets.nim b/lib/system/sets.nim index 626d43c33d..7826fd4b7a 100644 --- a/lib/system/sets.nim +++ b/lib/system/sets.nim @@ -18,7 +18,7 @@ proc countBits32(n: int32): int {.compilerproc.} = v = (v and 0x33333333'i32) +% ((v shr 2'i32) and 0x33333333'i32) result = ((v +% (v shr 4'i32) and 0xF0F0F0F'i32) *% 0x1010101'i32) shr 24'i32 -proc countBits64(n: int64): int {.compilerproc.} = +proc countBits64(n: int64): int {.compilerproc.} = result = countBits32(toU32(n and 0xffff'i64)) + countBits32(toU32(n shr 16'i64)) diff --git a/tests/actiontable/tactiontable.nim b/tests/actiontable/tactiontable.nim index e2f19a099e..4560d0f7f6 100644 --- a/tests/actiontable/tactiontable.nim +++ b/tests/actiontable/tactiontable.nim @@ -4,24 +4,23 @@ discard """ import tables -proc action1(arg: string) = +proc action1(arg: string) = echo "action 1 ", arg -proc action2(arg: string) = +proc action2(arg: string) = echo "action 2 ", arg -proc action3(arg: string) = +proc action3(arg: string) = echo "action 3 ", arg -proc action4(arg: string) = +proc action4(arg: string) = echo "action 4 ", arg var actionTable = { - "A": action1, - "B": action2, - "C": action3, + "A": action1, + "B": action2, + "C": action3, "D": action4}.toTable actionTable["C"]("arg") - diff --git a/tests/collections/ttables.nim b/tests/collections/ttables.nim index 3a923610ec..e4cff7c7e2 100644 --- a/tests/collections/ttables.nim +++ b/tests/collections/ttables.nim @@ -22,15 +22,15 @@ const "---00": 346677844, "0": 34404, "1": 344004, - "10": 34484, + "10": 34484, "11": 34474, "12": 789, "19": 34464, - "2": 344774, "20": 34454, + "2": 344774, "20": 34454, "3": 342244, "30": 34141244, "34": 123456, "4": 3412344, "40": 344114, - "5": 341232144, "50": 344490, + "5": 341232144, "50": 344490, "6": 34214544, "60": 344491, "7": 3434544, "70": 344492, "8": 344544, "80": 344497, @@ -46,7 +46,7 @@ block tableTest1: for x in 0..1: for y in 0..1: assert t[(x,y)] == $x & $y - assert($t == + assert($t == "{(x: 0, y: 1): 01, (x: 0, y: 0): 00, (x: 1, y: 0): 10, (x: 1, y: 1): 11}") block tableTest2: @@ -55,14 +55,17 @@ block tableTest2: t["111"] = 1.000043 t["123"] = 1.23 t.del("111") - + t["012"] = 67.9 t["123"] = 1.5 # test overwriting - + assert t["123"] == 1.5 - assert t["111"] == 0.0 # deleted + try: + echo t["111"] # deleted + except KeyError: + discard assert(not hasKey(t, "111")) - + for key, val in items(data): t[key] = val.toFloat for key, val in items(data): assert t[key] == val.toFloat diff --git a/tests/collections/ttablesref.nim b/tests/collections/ttablesref.nim index 16b0d831e9..92bc65da3b 100644 --- a/tests/collections/ttablesref.nim +++ b/tests/collections/ttablesref.nim @@ -22,15 +22,15 @@ const "---00": 346677844, "0": 34404, "1": 344004, - "10": 34484, + "10": 34484, "11": 34474, "12": 789, "19": 34464, - "2": 344774, "20": 34454, + "2": 344774, "20": 34454, "3": 342244, "30": 34141244, "34": 123456, "4": 3412344, "40": 344114, - "5": 341232144, "50": 344490, + "5": 341232144, "50": 344490, "6": 34214544, "60": 344491, "7": 3434544, "70": 344492, "8": 344544, "80": 344497, @@ -46,7 +46,7 @@ block tableTest1: for x in 0..1: for y in 0..1: assert t[(x,y)] == $x & $y - assert($t == + assert($t == "{(x: 0, y: 1): 01, (x: 0, y: 0): 00, (x: 1, y: 0): 10, (x: 1, y: 1): 11}") block tableTest2: @@ -55,17 +55,20 @@ block tableTest2: t["111"] = 1.000043 t["123"] = 1.23 t.del("111") - + t["012"] = 67.9 t["123"] = 1.5 # test overwriting - + assert t["123"] == 1.5 - assert t["111"] == 0.0 # deleted + try: + echo t["111"] # deleted + except KeyError: + discard assert(not hasKey(t, "111")) - + for key, val in items(data): t[key] = val.toFloat for key, val in items(data): assert t[key] == val.toFloat - + block orderedTableTest1: var t = newOrderedTable[string, int](2) diff --git a/tests/misc/teventemitter.nim b/tests/misc/teventemitter.nim index c1cc3d3a9c..7da1a2522d 100644 --- a/tests/misc/teventemitter.nim +++ b/tests/misc/teventemitter.nim @@ -13,21 +13,20 @@ proc emit*(emitter: EventEmitter, event: string, args: EventArgs) = for fn in nodes(emitter.events[event]): fn.value(args) #call function with args. -proc on*(emitter: var EventEmitter, event: string, +proc on*(emitter: var EventEmitter, event: string, fn: proc(e: EventArgs) {.nimcall.}) = if not hasKey(emitter.events, event): var list: DoublyLinkedList[proc(e: EventArgs) {.nimcall.}] add(emitter.events, event, list) #if not, add it. - append(emitter.events.mget(event), fn) + append(emitter.events[event], fn) proc initEmitter(emitter: var EventEmitter) = - emitter.events = initTable[string, + emitter.events = initTable[string, DoublyLinkedList[proc(e: EventArgs) {.nimcall.}]]() -var +var ee: EventEmitter args: EventArgs initEmitter(ee) ee.on("print", proc(e: EventArgs) = echo("pie")) ee.emit("print", args) - diff --git a/tests/stdlib/tmget.nim b/tests/stdlib/tmget.nim new file mode 100644 index 0000000000..5792b62827 --- /dev/null +++ b/tests/stdlib/tmget.nim @@ -0,0 +1,141 @@ +discard """ + output: '''Can't access 6 +10 +11 +Can't access 6 +10 +11 +Can't access 6 +10 +11 +Can't access 6 +10 +11 +Can't access 6 +10 +11 +Can't access 6 +10 +11 +Can't access 6 +5 +Can't access 6 +10 +11 +Can't access 6 +10 +11''' +""" + +import tables + +block: + var x = initTable[int, int]() + x[5] = 10 + try: + echo x[6] + except KeyError: + echo "Can't access 6" + echo x[5] + x[5] += 1 + var c = x[5] + echo c + +block: + var x = newTable[int, int]() + x[5] = 10 + try: + echo x[6] + except KeyError: + echo "Can't access 6" + echo x[5] + x[5] += 1 + var c = x[5] + echo c + +block: + var x = initOrderedTable[int, int]() + x[5] = 10 + try: + echo x[6] + except KeyError: + echo "Can't access 6" + echo x[5] + x[5] += 1 + var c = x[5] + echo c + +block: + var x = newOrderedTable[int, int]() + x[5] = 10 + try: + echo x[6] + except KeyError: + echo "Can't access 6" + echo x[5] + x[5] += 1 + var c = x[5] + echo c + +block: + var x = initCountTable[int]() + x[5] = 10 + try: + echo x[6] + except KeyError: + echo "Can't access 6" + echo x[5] + x[5] += 1 + var c = x[5] + echo c + +block: + var x = newCountTable[int]() + x[5] = 10 + try: + echo x[6] + except KeyError: + echo "Can't access 6" + echo x[5] + x[5] += 1 + var c = x[5] + echo c + +import sets + +block: + var x = initSet[int]() + x.incl 5 + try: + echo x[6] + except KeyError: + echo "Can't access 6" + echo x[5] + +import critbits + +block: + var x: CritBitTree[int] + x["5"] = 10 + try: + echo x["6"] + except KeyError: + echo "Can't access 6" + echo x["5"] + x["5"] += 1 + var c = x["5"] + echo c + +import strtabs + +block: + var x = newStringTable() + x["5"] = "10" + try: + echo x["6"] + except KeyError: + echo "Can't access 6" + echo x["5"] + x["5"][1] = '1' + var c = x["5"] + echo c diff --git a/tests/stdlib/tmitems.nim b/tests/stdlib/tmitems.nim index 2c0a0392a5..f2307aeb37 100644 --- a/tests/stdlib/tmitems.nim +++ b/tests/stdlib/tmitems.nim @@ -132,5 +132,5 @@ block: """) for x in d.mitems: x = <>Student(Name=x.attrs["Name"] & "foo") - d.mget(1).attrs["Name"] = "bar" + d[1].attrs["Name"] = "bar" echo d From 4a471d82310659bcb9683b9e81ba9e4af5e23062 Mon Sep 17 00:00:00 2001 From: def Date: Tue, 31 Mar 2015 00:33:53 +0200 Subject: [PATCH 02/32] Don't use deprecated intsets.empty --- compiler/importer.nim | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/importer.nim b/compiler/importer.nim index d619725db0..657f41eabe 100644 --- a/compiler/importer.nim +++ b/compiler/importer.nim @@ -121,7 +121,7 @@ proc importAllSymbolsExcept(c: PContext, fromMod: PSym, exceptSet: IntSet) = if s.kind != skEnumField: if s.kind notin ExportableSymKinds: internalError(s.info, "importAllSymbols: " & $s.kind) - if exceptSet.empty or s.name.id notin exceptSet: + if s.name.id notin exceptSet: rawImportSymbol(c, s) s = nextIter(i, fromMod.tab) @@ -138,7 +138,7 @@ proc importForwarded(c: PContext, n: PNode, exceptSet: IntSet) = let s = a.sym if s.kind == skModule: importAllSymbolsExcept(c, s, exceptSet) - elif exceptSet.empty or s.name.id notin exceptSet: + elif s.name.id notin exceptSet: rawImportSymbol(c, s) of nkExportExceptStmt: localError(n.info, errGenerated, "'export except' not implemented") From 4baaea5ad52f5a80b2ca5592d2950ed28f7c49dc Mon Sep 17 00:00:00 2001 From: Reimer Behrends Date: Sun, 6 Sep 2015 01:48:31 +0200 Subject: [PATCH 03/32] Properly initialize the Boehm GC on all platforms. --- lib/system/mmdisp.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/system/mmdisp.nim b/lib/system/mmdisp.nim index 8a946716d6..bf006f68a7 100644 --- a/lib/system/mmdisp.nim +++ b/lib/system/mmdisp.nim @@ -157,7 +157,7 @@ when defined(boehmgc): proc setStackBottom(theStackBottom: pointer) = discard proc initGC() = - when defined(macosx): boehmGCinit() + boehmGCinit() proc newObj(typ: PNimType, size: int): pointer {.compilerproc.} = if ntfNoRefs in typ.flags: result = allocAtomic(size) From 639b5e006992779e8f984eb4a2b1509e4ad2b03a Mon Sep 17 00:00:00 2001 From: Reimer Behrends Date: Tue, 8 Sep 2015 19:01:06 +0200 Subject: [PATCH 04/32] Properly register threads with the Boehm GC. In order to be able to scan thread stacks, the Boehm GC needs to know about newly created threads. We establish the end of the stack by using GC_call_with_stack_base (this works properly also with the dual-stack Itanium architecture) and then GC_register_my_thread() to register a thrad and GC_unregister_my_thread() to unregister it again. This patch also includes a modification for the refc and markandsweep collectors to set the stack bottom for thread stacks correctly even if an optimizer aggressively inlines and optimizes procedures (this is already being done for the stack of the main thread). Finally, we use the {.noconv.} pragma for the Boehm GC, as the Boehm API uses no specific calling convention. --- lib/system.nim | 9 +++++++ lib/system/mmdisp.nim | 41 +++++++++++++--------------- lib/system/threads.nim | 61 +++++++++++++++++++++++++++++++----------- 3 files changed, 73 insertions(+), 38 deletions(-) diff --git a/lib/system.nim b/lib/system.nim index 3d7d4bd284..e0bfbe8eaa 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -1200,6 +1200,15 @@ const hasSharedHeap = defined(boehmgc) or defined(gogc) # don't share heaps; every thread has its own taintMode = compileOption("taintmode") +when defined(boehmgc): + when defined(windows): + const boehmLib = "boehmgc.dll" + elif defined(macosx): + const boehmLib = "libgc.dylib" + else: + const boehmLib = "libgc.so.1" + {.pragma: boehmGC, noconv, dynlib: boehmLib.} + when taintMode: type TaintedString* = distinct string ## a distinct string type that ## is `tainted`:idx:. It is an alias for diff --git a/lib/system/mmdisp.nim b/lib/system/mmdisp.nim index bf006f68a7..ecf25ceeeb 100644 --- a/lib/system/mmdisp.nim +++ b/lib/system/mmdisp.nim @@ -66,41 +66,34 @@ proc raiseOutOfMem() {.noinline.} = quit(1) when defined(boehmgc): - when defined(windows): - const boehmLib = "boehmgc.dll" - elif defined(macosx): - const boehmLib = "libgc.dylib" - else: - const boehmLib = "libgc.so.1" - - proc boehmGCinit {.importc: "GC_init", dynlib: boehmLib.} - proc boehmGC_disable {.importc: "GC_disable", dynlib: boehmLib.} - proc boehmGC_enable {.importc: "GC_enable", dynlib: boehmLib.} + proc boehmGCinit {.importc: "GC_init", boehmGC.} + proc boehmGC_disable {.importc: "GC_disable", boehmGC.} + proc boehmGC_enable {.importc: "GC_enable", boehmGC.} proc boehmGCincremental {. - importc: "GC_enable_incremental", dynlib: boehmLib.} - proc boehmGCfullCollect {.importc: "GC_gcollect", dynlib: boehmLib.} - proc boehmAlloc(size: int): pointer {. - importc: "GC_malloc", dynlib: boehmLib.} + importc: "GC_enable_incremental", boehmGC.} + proc boehmGCfullCollect {.importc: "GC_gcollect", boehmGC.} + proc boehmAlloc(size: int): pointer {.importc: "GC_malloc", boehmGC.} proc boehmAllocAtomic(size: int): pointer {. - importc: "GC_malloc_atomic", dynlib: boehmLib.} + importc: "GC_malloc_atomic", boehmGC.} proc boehmRealloc(p: pointer, size: int): pointer {. - importc: "GC_realloc", dynlib: boehmLib.} - proc boehmDealloc(p: pointer) {.importc: "GC_free", dynlib: boehmLib.} + importc: "GC_realloc", boehmGC.} + proc boehmDealloc(p: pointer) {.importc: "GC_free", boehmGC.} + when hasThreadSupport: + proc boehmGC_allow_register_threads {. + importc: "GC_allow_register_threads", boehmGC.} - proc boehmGetHeapSize: int {.importc: "GC_get_heap_size", dynlib: boehmLib.} + proc boehmGetHeapSize: int {.importc: "GC_get_heap_size", boehmGC.} ## Return the number of bytes in the heap. Excludes collector private ## data structures. Includes empty blocks and fragmentation loss. ## Includes some pages that were allocated but never written. - proc boehmGetFreeBytes: int {.importc: "GC_get_free_bytes", dynlib: boehmLib.} + proc boehmGetFreeBytes: int {.importc: "GC_get_free_bytes", boehmGC.} ## Return a lower bound on the number of free bytes in the heap. - proc boehmGetBytesSinceGC: int {.importc: "GC_get_bytes_since_gc", - dynlib: boehmLib.} + proc boehmGetBytesSinceGC: int {.importc: "GC_get_bytes_since_gc", boehmGC.} ## Return the number of bytes allocated since the last collection. - proc boehmGetTotalBytes: int {.importc: "GC_get_total_bytes", - dynlib: boehmLib.} + proc boehmGetTotalBytes: int {.importc: "GC_get_total_bytes", boehmGC.} ## Return the total number of bytes allocated in this process. ## Never decreases. @@ -158,6 +151,8 @@ when defined(boehmgc): proc initGC() = boehmGCinit() + when hasThreadSupport: + boehmGC_allow_register_threads() proc newObj(typ: PNimType, size: int): pointer {.compilerproc.} = if ntfNoRefs in typ.flags: result = allocAtomic(size) diff --git a/lib/system/threads.nim b/lib/system/threads.nim index c7cb8d9df8..c5de841f88 100644 --- a/lib/system/threads.nim +++ b/lib/system/threads.nim @@ -304,22 +304,53 @@ type when not defined(boehmgc) and not hasSharedHeap and not defined(gogc): proc deallocOsPages() +when defined(boehmgc): + type GCStackBaseProc = proc(sb: pointer, t: pointer) {.noconv.} + proc boehmGC_call_with_stack_base(sbp: GCStackBaseProc, p: pointer) + {.importc: "GC_call_with_stack_base", boehmGC.} + proc boehmGC_register_my_thread(sb: pointer) + {.importc: "GC_register_my_thread", boehmGC.} + proc boehmGC_unregister_my_thread() + {.importc: "GC_unregister_my_thread", boehmGC.} + + proc threadProcWrapDispatch[TArg](sb: pointer, thrd: pointer) {.noconv.} = + boehmGC_register_my_thread(sb) + let thrd = cast[ptr Thread[TArg]](thrd) + when TArg is void: + thrd.dataFn() + else: + thrd.dataFn(thrd.data) + boehmGC_unregister_my_thread() +else: + proc threadProcWrapDispatch[TArg](thrd: ptr Thread[TArg]) = + when TArg is void: + thrd.dataFn() + else: + thrd.dataFn(thrd.data) + +proc threadProcWrapStackFrame[TArg](thrd: ptr Thread[TArg]) = + when defined(boehmgc): + boehmGC_call_with_stack_base(threadProcWrapDispatch[TArg], thrd) + elif not defined(nogc) and not defined(gogc): + var p {.volatile.}: proc(a: ptr Thread[TArg]) {.nimcall.} = + threadProcWrapDispatch[TArg] + when not hasSharedHeap: + # init the GC for refc/markandsweep + setStackBottom(addr(p)) + initGC() + when declared(registerThread): + thrd.stackBottom = addr(thrd) + registerThread(thrd) + p(thrd) + when declared(registerThread): unregisterThread(thrd) + when declared(deallocOsPages): deallocOsPages() + else: + threadProcWrapDispatch(thrd) + template threadProcWrapperBody(closure: expr) {.immediate.} = when declared(globalsSlot): threadVarSetValue(globalsSlot, closure) - var t = cast[ptr Thread[TArg]](closure) - when useStackMaskHack: - var tls: ThreadLocalStorage - when not defined(boehmgc) and not defined(gogc) and not defined(nogc) and not hasSharedHeap: - # init the GC for this thread: - setStackBottom(addr(t)) - initGC() - when declared(registerThread): - t.stackBottom = addr(t) - registerThread(t) - when TArg is void: t.dataFn() - else: t.dataFn(t.data) - when declared(registerThread): unregisterThread(t) - when declared(deallocOsPages): deallocOsPages() + var thrd = cast[ptr Thread[TArg]](closure) + threadProcWrapStackFrame(thrd) # Since an unhandled exception terminates the whole process (!), there is # no need for a ``try finally`` here, nor would it be correct: The current # exception is tried to be re-raised by the code-gen after the ``finally``! @@ -327,7 +358,7 @@ template threadProcWrapperBody(closure: expr) {.immediate.} = # page! # mark as not running anymore: - t.dataFn = nil + thrd.dataFn = nil {.push stack_trace:off.} when defined(windows): From 9deab06c1ba4e7badec41031ac1af585c353c6f2 Mon Sep 17 00:00:00 2001 From: Reimer Behrends Date: Tue, 8 Sep 2015 19:29:29 +0200 Subject: [PATCH 05/32] Include Boehm GC in garbage collection tests. --- tests/testament/categories.nim | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/tests/testament/categories.nim b/tests/testament/categories.nim index 4de1edeee1..10e39b20a5 100644 --- a/tests/testament/categories.nim +++ b/tests/testament/categories.nim @@ -114,12 +114,18 @@ proc gcTests(r: var TResults, cat: Category, options: string) = testSpec r, makeTest("tests/gc" / filename, options & " -d:release -d:useRealtimeGC", cat, actionRun) - template test(filename: expr): stmt = + template testWithoutBoehm(filename: expr): stmt = testWithoutMs filename testSpec r, makeTest("tests/gc" / filename, options & " --gc:markAndSweep", cat, actionRun) testSpec r, makeTest("tests/gc" / filename, options & " -d:release --gc:markAndSweep", cat, actionRun) + template test(filename: expr): stmt = + testWithoutBoehm filename + testSpec r, makeTest("tests/gc" / filename, options & + " --gc:boehm", cat, actionRun) + testSpec r, makeTest("tests/gc" / filename, options & + " -d:release --gc:boehm", cat, actionRun) test "growobjcrash" test "gcbench" @@ -130,9 +136,9 @@ proc gcTests(r: var TResults, cat: Category, options: string) = test "gcleak4" # Disabled because it works and takes too long to run: #test "gcleak5" - test "weakrefs" + testWithoutBoehm "weakrefs" test "cycleleak" - test "closureleak" + testWithoutBoehm "closureleak" testWithoutMs "refarrayleak" test "stackrefleak" From 250375bdd22530d3a0f3b2b87cbbf0987c65fcaa Mon Sep 17 00:00:00 2001 From: Reimer Behrends Date: Tue, 8 Sep 2015 19:12:01 +0200 Subject: [PATCH 06/32] Remove spurious unsigned operations from system/threads.nim. These operations were included before the unsigned module was incorporated directly into system.nim and subsequently caused compilation errors with --gc:go due to duplicate definitions. --- lib/system/mmdisp.nim | 3 --- 1 file changed, 3 deletions(-) diff --git a/lib/system/mmdisp.nim b/lib/system/mmdisp.nim index ecf25ceeeb..1c13f3ff8a 100644 --- a/lib/system/mmdisp.nim +++ b/lib/system/mmdisp.nim @@ -199,9 +199,6 @@ elif defined(gogc): else: const goLib = "libgo.so" - proc `div`[T: SomeUnsignedInt](x, y: T): T {.magic: "DivU", noSideEffect.} - proc `-`[T: SomeUnsignedInt](x, y: T): T {.magic: "SubU", noSideEffect.} - proc roundup(x, v: int): int {.inline.} = result = (x + (v-1)) and not (v-1) From e02e8968c4ae11fc9f8230c449526aa7c87f9231 Mon Sep 17 00:00:00 2001 From: Rostyslav Dzinko Date: Thu, 17 Sep 2015 12:50:51 +0300 Subject: [PATCH 07/32] Moved teardown call to try block for namespace access reasons --- lib/pure/unittest.nim | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/pure/unittest.nim b/lib/pure/unittest.nim index a0f7b955e9..aca9d51e22 100755 --- a/lib/pure/unittest.nim +++ b/lib/pure/unittest.nim @@ -150,6 +150,8 @@ template test*(name: expr, body: stmt): stmt {.immediate, dirty.} = try: when declared(testSetupIMPLFlag): testSetupIMPL() body + when declared(testTeardownIMPLFlag): + defer: testTeardownIMPL() except: when not defined(js): @@ -158,7 +160,6 @@ template test*(name: expr, body: stmt): stmt {.immediate, dirty.} = fail() finally: - when declared(testTeardownIMPLFlag): testTeardownIMPL() testDone name, testStatusIMPL proc checkpoint*(msg: string) = From 75097e2981e470197fa5649557875a9f60385973 Mon Sep 17 00:00:00 2001 From: Peter Mora Date: Mon, 5 Oct 2015 22:41:54 +0200 Subject: [PATCH 08/32] sequtils related changes --- examples/maximum.nim | 2 +- lib/pure/collections/sequtils.nim | 205 +++++++++++++++++++---- lib/system.nim | 47 ------ tests/closure/tclosure4.nim | 2 +- tests/collections/tapply.nim | 7 + tests/collections/tmapit.nim | 28 ++++ tests/generics/tinferredgenericprocs.nim | 1 + tests/generics/tmap_auto.nim | 2 +- tests/overload/toverprc.nim | 2 +- tests/parser/tcommand_as_expr.nim | 1 + tests/template/twrongmapit.nim | 2 +- 11 files changed, 211 insertions(+), 88 deletions(-) create mode 100644 tests/collections/tapply.nim create mode 100644 tests/collections/tmapit.nim diff --git a/examples/maximum.nim b/examples/maximum.nim index aa3fe375ab..6552a8144d 100644 --- a/examples/maximum.nim +++ b/examples/maximum.nim @@ -1,6 +1,6 @@ # Test high level features -import strutils +import strutils, sequtils echo "Give a list of numbers (separated by spaces): " stdin.readLine.split.map(parseInt).max.`$`.echo(" is the maximum!") diff --git a/lib/pure/collections/sequtils.nim b/lib/pure/collections/sequtils.nim index e6ea19a6b6..6e51b453e9 100644 --- a/lib/pure/collections/sequtils.nim +++ b/lib/pure/collections/sequtils.nim @@ -47,7 +47,7 @@ proc concat*[T](seqs: varargs[seq[T]]): seq[T] = result[i] = itm inc(i) -proc repeat*[T](s: seq[T], n: Natural): seq[T] = +proc cycle*[T](s: seq[T], n: Natural): seq[T] = ## Returns a new sequence with the items of `s` repeated `n` times. ## ## Example: @@ -56,15 +56,29 @@ proc repeat*[T](s: seq[T], n: Natural): seq[T] = ## ## let ## s = @[1, 2, 3] - ## total = s.repeat(3) + ## total = s.cycle(3) ## assert total == @[1, 2, 3, 1, 2, 3, 1, 2, 3] result = newSeq[T](n * s.len) var o = 0 - for x in 1..n: + for x in 0.. ["1", "2", "3", "4"] + ## map(a, proc(x: var string) = x &= "42") + ## echo repr(a) + ## # --> ["142", "242", "342", "442"] + ## **Deprecated since version 0.12.0:** Use the ``apply`` proc instead. + for i in 0..data.len-1: op(data[i]) + +proc apply*[T](data: var seq[T], op: proc (x: var T) {.closure.}) + {.inline.} = + ## Applies `op` to every item in `data` modifying it directly. + ## + ## Note that this requires your input and output types to + ## be the same, since they are modified in-place. + ## The parameter function takes a ``var T`` type parameter. + ## Example: + ## + ## .. code-block:: nim + ## var a = @["1", "2", "3", "4"] + ## echo repr(a) + ## # --> ["1", "2", "3", "4"] + ## map(a, proc(x: var string) = x &= "42") + ## echo repr(a) + ## # --> ["142", "242", "342", "442"] + ## + for i in 0..data.len-1: op(data[i]) + +proc apply*[T](data: var seq[T], op: proc (x: T): T {.closure.}) + {.inline.} = + ## Applies `op` to every item in `data` modifying it directly. + ## + ## Note that this requires your input and output types to + ## be the same, since they are modified in-place. + ## The parameter function takes and returns a ``T`` type variable. + ## Example: + ## + ## .. code-block:: nim + ## var a = @["1", "2", "3", "4"] + ## echo repr(a) + ## # --> ["1", "2", "3", "4"] + ## map(a, proc(x: string): string = x & "42") + ## echo repr(a) + ## # --> ["142", "242", "342", "442"] + ## + for i in 0..data.len-1: data[i] = op(data[i]) + iterator filter*[T](seq1: seq[T], pred: proc(item: T): bool {.closure.}): T = ## Iterates through a sequence and yields every item that fulfills the @@ -181,11 +266,12 @@ iterator filter*[T](seq1: seq[T], pred: proc(item: T): bool {.closure.}): T = ## for n in filter(numbers, proc (x: int): bool = x mod 2 == 0): ## echo($n) ## # echoes 4, 8, 4 in separate lines - for i in countup(0, len(seq1)-1): - var item = seq1[i] - if pred(item): yield seq1[i] + for i in 0.. bool : x.len > 5 ## assert f1 == @["red", "black"] ## assert f2 == @["yellow"] - accumulateResult(filter(seq1, pred)) + result = newSeq[T]() + for i in 0.. 50 or it < -10) ## assert acceptable == @[-2.0, 24.5, 44.31] ## assert notAcceptable == @[-272.15, 99.9, -113.44] - var result {.gensym.}: type(seq1) = @[] + var result {.gensym.} = newSeq[type(seq1[0])]() for it {.inject.} in items(seq1): if pred: result.add(it) result -template keepItIf*(varSeq, pred: expr) = +template keepItIf*(varSeq: seq, pred: expr) = ## Convenience template around the ``keepIf`` proc to reduce typing. ## ## Unlike the `proc` version, the predicate needs to be an expression using @@ -303,12 +393,12 @@ template keepItIf*(varSeq, pred: expr) = let it {.inject.} = varSeq[i] if pred: if pos != i: - varSeq[pos] = varSeq[i] + shallowCopy(varSeq[pos], varSeq[i]) inc(pos) setLen(varSeq, pos) -template toSeq*(iter: expr): expr {.immediate.} = +template toSeq*(iter: expr): expr = ## Transforms any iterator into a sequence. ## ## Example: @@ -320,14 +410,19 @@ template toSeq*(iter: expr): expr {.immediate.} = ## if x mod 2 == 1: ## result = true) ## assert odd_numbers == @[1, 3, 5, 7, 9] - ## - ## **Note**: Since this is an immediate macro, you cannot always invoke this - ## as ``x.toSeq``, depending on the ``x``. - ## See `this `_ - ## for an explanation. - var result {.gensym.}: seq[type(iter)] = @[] - for x in iter: add(result, x) - result + + when compiles(iter.len): + var i = 0 + var result = newSeq[type(iter)](iter.len) + for x in iter: + result[i] = x + inc i + result + else: + var result: seq[type(iter)] = @[] + for x in iter: + result.add(x) + result template foldl*(sequence, operation: expr): expr = ## Template to fold a sequence from left to right, returning the accumulation. @@ -358,7 +453,7 @@ template foldl*(sequence, operation: expr): expr = assert sequence.len > 0, "Can't fold empty sequences" var result {.gensym.}: type(sequence[0]) result = sequence[0] - for i in countup(1, sequence.len - 1): + for i in 1.. ["1", "2", "3", "4"] - ## map(a, proc(x: var string) = x &= "42") - ## echo repr(a) - ## # --> ["142", "242", "342", "442"] - for i in 0..data.len-1: op(data[i]) - iterator fields*[T: tuple|object](x: T): RootObj {. magic: "Fields", noSideEffect.} ## iterates over every field of `x`. Warning: This really transforms diff --git a/tests/closure/tclosure4.nim b/tests/closure/tclosure4.nim index 8e08376b60..10c7cac54a 100644 --- a/tests/closure/tclosure4.nim +++ b/tests/closure/tclosure4.nim @@ -1,5 +1,5 @@ -import json, tables +import json, tables, sequtils proc run(json_params: TTable) = let json_elems = json_params["files"].elems diff --git a/tests/collections/tapply.nim b/tests/collections/tapply.nim new file mode 100644 index 0000000000..403321ce13 --- /dev/null +++ b/tests/collections/tapply.nim @@ -0,0 +1,7 @@ +import sequtils + +var x = @[1, 2, 3] +x.apply(proc(x: var int) = x = x+10) +x.apply(proc(x: int): int = x+100) +x.applyIt(it+5000) +doAssert x == @[5111, 5112, 5113] diff --git a/tests/collections/tmapit.nim b/tests/collections/tmapit.nim new file mode 100644 index 0000000000..0675618829 --- /dev/null +++ b/tests/collections/tmapit.nim @@ -0,0 +1,28 @@ +import sequtils + +var x = @[1, 2, 3] +# This mapIt call will run with preallocation because ``len`` is available. +var y = x.mapIt($(it+10)) +doAssert y == @["11", "12", "13"] + +type structureWithoutLen = object + a: array[5, int] + +iterator items(s: structureWithoutLen): int {.inline.} = + yield s.a[0] + yield s.a[1] + yield s.a[2] + yield s.a[3] + yield s.a[4] + +var st: structureWithoutLen +st.a[0] = 0 +st.a[1] = 1 +st.a[2] = 2 +st.a[3] = 3 +st.a[4] = 4 + +# this will run without preallocating the result +# since ``len`` is not available +var r = st.mapIt($(it+10)) +doAssert r == @["10", "11", "12", "13", "14"] diff --git a/tests/generics/tinferredgenericprocs.nim b/tests/generics/tinferredgenericprocs.nim index 5cbeabb94c..359c71ba84 100644 --- a/tests/generics/tinferredgenericprocs.nim +++ b/tests/generics/tinferredgenericprocs.nim @@ -5,6 +5,7 @@ discard """ 3''' """ +import sequtils # https://github.com/Araq/Nim/issues/797 proc foo[T](s:T):string = $s diff --git a/tests/generics/tmap_auto.nim b/tests/generics/tmap_auto.nim index dea9b571fb..572556722c 100644 --- a/tests/generics/tmap_auto.nim +++ b/tests/generics/tmap_auto.nim @@ -1,4 +1,4 @@ -import future +import future, sequtils let x = map(@[1, 2, 3], x => x+10) assert x == @[11, 12, 13] diff --git a/tests/overload/toverprc.nim b/tests/overload/toverprc.nim index 78831f7445..112eae0969 100644 --- a/tests/overload/toverprc.nim +++ b/tests/overload/toverprc.nim @@ -5,7 +5,7 @@ yay''' # Test overloading of procs when used as function pointers -import strutils +import strutils, sequtils proc parseInt(x: float): int {.noSideEffect.} = discard proc parseInt(x: bool): int {.noSideEffect.} = discard diff --git a/tests/parser/tcommand_as_expr.nim b/tests/parser/tcommand_as_expr.nim index 730e9cbb7d..a244c87678 100644 --- a/tests/parser/tcommand_as_expr.nim +++ b/tests/parser/tcommand_as_expr.nim @@ -5,6 +5,7 @@ discard """ 77''' """ #import math +import sequtils proc optarg(x:int, y:int = 0):int = x + 3 * y proc singlearg(x:int):int = 20*x diff --git a/tests/template/twrongmapit.nim b/tests/template/twrongmapit.nim index 0a6d694f67..df695fcd62 100644 --- a/tests/template/twrongmapit.nim +++ b/tests/template/twrongmapit.nim @@ -27,6 +27,6 @@ when ATTEMPT == 0: # bug #1543 import sequtils -(var i = @[""];i).mapIt(it) +(var i = @[""];i).applyIt(it) # now works: echo "##", i[0], "##" From 6318f77821959f1fbd0c6bd3d04550b6ac926dcc Mon Sep 17 00:00:00 2001 From: Peter Mora Date: Tue, 6 Oct 2015 08:15:00 +0200 Subject: [PATCH 09/32] restore {.immediate.} to toSeq --- lib/pure/collections/sequtils.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pure/collections/sequtils.nim b/lib/pure/collections/sequtils.nim index 6e51b453e9..fd012e811d 100644 --- a/lib/pure/collections/sequtils.nim +++ b/lib/pure/collections/sequtils.nim @@ -398,7 +398,7 @@ template keepItIf*(varSeq: seq, pred: expr) = setLen(varSeq, pos) -template toSeq*(iter: expr): expr = +template toSeq*(iter: expr): expr {.immediate.} = ## Transforms any iterator into a sequence. ## ## Example: From b284ace099aa2dadfd67c4006ded2f64225e4c09 Mon Sep 17 00:00:00 2001 From: Peter Mora Date: Tue, 6 Oct 2015 08:24:43 +0200 Subject: [PATCH 10/32] fixing unittest --- tests/stdlib/tunittest.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/stdlib/tunittest.nim b/tests/stdlib/tunittest.nim index 4d2a2a340e..4b210c23b6 100644 --- a/tests/stdlib/tunittest.nim +++ b/tests/stdlib/tunittest.nim @@ -1,4 +1,4 @@ -import unittest +import unittest, sequtils proc doThings(spuds: var int): int = From e2468fee55a3477a5707ac2d74b329fcb73f4f2b Mon Sep 17 00:00:00 2001 From: Peter Mora Date: Tue, 6 Oct 2015 22:03:43 +0200 Subject: [PATCH 11/32] updated news.txt with backward compatibility breaks of sequtils --- web/news.txt | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/web/news.txt b/web/news.txt index 2b60796206..45bbe8c441 100644 --- a/web/news.txt +++ b/web/news.txt @@ -87,7 +87,13 @@ News echo f(0, "abc") - The ``ftpclient`` module is now deprecated in favour of the ``asyncdispatch`` module. - + - In sequtils.nim renamed ``repeat`` function to ``cycle`` (concatenating + a sequence by itself the given times), and also introduced ``repeat``, + which repeats an element the given times. + - The function ``map`` is moved to sequtils.nim. The inplace ``map`` version + is renamed to ``apply``. + - The template ``mapIt`` now doesn't require the result's type parameter. + Also the inplace ``mapIt`` is renamed to ``apply``. Library Additions ----------------- From 07eaafca698def254fff1f3ed843526441dc91b7 Mon Sep 17 00:00:00 2001 From: JamesP Date: Wed, 7 Oct 2015 13:03:31 +1000 Subject: [PATCH 12/32] added hash procs for handling portions of strings/arrays/seqs. added tests at bottom of file changed some doco layout Makes hashing iteratively through buffers faster when you don't have to pass copied portions of the buffer to the hash function --- lib/pure/hashes.nim | 74 ++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 70 insertions(+), 4 deletions(-) diff --git a/lib/pure/hashes.nim b/lib/pure/hashes.nim index 61c16129bc..11af811493 100644 --- a/lib/pure/hashes.nim +++ b/lib/pure/hashes.nim @@ -8,9 +8,10 @@ # ## This module implements efficient computations of hash values for diverse -## Nim types. All the procs are based on these two building blocks: the `!& -## proc <#!&>`_ used to start or mix a hash value, and the `!$ proc <#!$>`_ -## used to *finish* the hash value. If you want to implement hash procs for +## Nim types. All the procs are based on these two building blocks: +## - `!& proc <#!&>`_ used to start or mix a hash value, and +## - `!$ proc <#!$>`_ used to *finish* the hash value. +## If you want to implement hash procs for ## your custom types you will end up writing the following kind of skeleton of ## code: ## @@ -108,7 +109,7 @@ proc hash*(x: int): Hash {.inline.} = result = x proc hash*(x: int64): Hash {.inline.} = - ## efficient hashing of integers + ## efficient hashing of int64 integers result = toU32(x) proc hash*(x: char): Hash {.inline.} = @@ -126,6 +127,16 @@ proc hash*(x: string): Hash = h = h !& ord(x[i]) result = !$h +proc hash*(sBuf: string, sPos, ePos: int): Hash = + ## efficient hashing of a string buffer, from starting + ## position `sPos` to ending position `ePos` + ## + ## ``hash(myStr, 0, myStr.high)`` is equivalent to ``hash(myStr)`` + var h: Hash = 0 + for i in sPos..ePos: + h = h !& ord(sBuf[i]) + result = !$h + proc hashIgnoreStyle*(x: string): Hash = ## efficient hashing of strings; style is ignored var h: Hash = 0 @@ -145,6 +156,27 @@ proc hashIgnoreStyle*(x: string): Hash = result = !$h +proc hashIgnoreStyle*(sBuf: string, sPos, ePos: int): Hash = + ## efficient hashing of a string buffer, from starting + ## position `sPos` to ending position `ePos`; style is ignored + ## + ## ``hashIgnoreStyle(myBuf, 0, myBuf.high)`` is equivalent + ## to ``hashIgnoreStyle(myBuf)`` + var h: Hash = 0 + var i = sPos + while i <= ePos: + var c = sBuf[i] + if c == '_': + inc(i) + elif isMagicIdentSeparatorRune(cstring(sBuf), i): + inc(i, magicIdentSeparatorRuneByteWidth) + else: + if c in {'A'..'Z'}: + c = chr(ord(c) + (ord('a') - ord('A'))) # toLower() + h = h !& ord(c) + inc(i) + result = !$h + proc hashIgnoreCase*(x: string): Hash = ## efficient hashing of strings; case is ignored var h: Hash = 0 @@ -155,7 +187,22 @@ proc hashIgnoreCase*(x: string): Hash = h = h !& ord(c) result = !$h +proc hashIgnoreCase*(sBuf: string, sPos, ePos: int): Hash = + ## efficient hashing of a string buffer, from starting + ## position `sPos` to ending position `ePos`; case is ignored + ## + ## ``hashIgnoreCase(myBuf, 0, myBuf.high)`` is equivalent + ## to ``hashIgnoreCase(myBuf)`` + var h: Hash = 0 + for i in sPos..ePos: + var c = sBuf[i] + if c in {'A'..'Z'}: + c = chr(ord(c) + (ord('a') - ord('A'))) # toLower() + h = h !& ord(c) + result = !$h + proc hash*(x: float): Hash {.inline.} = + ## efficient hashing of floats. var y = x + 1.0 result = cast[ptr Hash](addr(y))[] @@ -173,10 +220,29 @@ proc hash*[T: tuple](x: T): Hash = result = !$result proc hash*[A](x: openArray[A]): Hash = + ## efficient hashing of arrays and sequences. for it in items(x): result = result !& hash(it) result = !$result +proc hash*[A](aBuf: openArray[A], sPos, ePos: int): Hash = + ## efficient hashing of portions of arrays and sequences. + ## + ## ``hash(myBuf, 0, myBuf.high)`` is equivalent to ``hash(myBuf)`` + for i in sPos..ePos: + result = result !& hash(aBuf[i]) + result = !$result + proc hash*[A](x: set[A]): Hash = + ## efficient hashing of sets. for it in items(x): result = result !& hash(it) result = !$result +when isMainModule: + doAssert( hash("aa bb aaaa1234") == hash("aa bb aaaa1234", 0, 13) ) + doAssert( hashIgnoreCase("aa bb aaaa1234") == hash("aa bb aaaa1234") ) + doAssert( hashIgnoreStyle("aa bb aaaa1234") == hashIgnoreCase("aa bb aaaa1234") ) + let xx = @['H','e','l','l','o'] + let ss = "Hello" + doAssert( hash(xx) == hash(ss) ) + doAssert( hash(xx) == hash(xx, 0, xx.high) ) + doAssert( hash(ss) == hash(ss, 0, ss.high) ) From 6823a60b235b5a4559ba4648d73221c339b2ce7d Mon Sep 17 00:00:00 2001 From: Federico Ceratto Date: Fri, 9 Oct 2015 18:34:58 +0100 Subject: [PATCH 13/32] Export substituteLog Allow Nim users to create their own loggers --- lib/pure/logging.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pure/logging.nim b/lib/pure/logging.nim index 7a900daae2..4e7f83a9b7 100644 --- a/lib/pure/logging.nim +++ b/lib/pure/logging.nim @@ -92,7 +92,7 @@ type {.deprecated: [TLevel: Level, PLogger: Logger, PConsoleLogger: ConsoleLogger, PFileLogger: FileLogger, PRollingFileLogger: RollingFileLogger].} -proc substituteLog(frmt: string, level: Level, args: varargs[string, `$`]): string = +proc substituteLog*(frmt: string, level: Level, args: varargs[string, `$`]): string = var msgLen = 0 for arg in args: msgLen += arg.len From 08ec0ce071fc604f56f29b4fbfb226457345505b Mon Sep 17 00:00:00 2001 From: Federico Ceratto Date: Fri, 9 Oct 2015 23:26:22 +0100 Subject: [PATCH 14/32] Add substituteLog docs --- lib/pure/logging.nim | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/pure/logging.nim b/lib/pure/logging.nim index 4e7f83a9b7..c6c7945359 100644 --- a/lib/pure/logging.nim +++ b/lib/pure/logging.nim @@ -93,6 +93,8 @@ type PFileLogger: FileLogger, PRollingFileLogger: RollingFileLogger].} proc substituteLog*(frmt: string, level: Level, args: varargs[string, `$`]): string = + ## Format a log message using the ``frmt`` format string, ``level`` and varargs. + ## See the module documentation for the format string syntax. var msgLen = 0 for arg in args: msgLen += arg.len From bb570de994cd263b23e01111336a121671e06a3f Mon Sep 17 00:00:00 2001 From: Joey Payne Date: Fri, 9 Oct 2015 22:09:21 -0600 Subject: [PATCH 15/32] Added useful procs to strutils for string testing. Added procs: isAlpha isAlphaNumeric isDigit isSpace isUpper isLower --- lib/pure/strutils.nim | 126 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 126 insertions(+) diff --git a/lib/pure/strutils.nim b/lib/pure/strutils.nim index eacea72e4f..005715a30a 100644 --- a/lib/pure/strutils.nim +++ b/lib/pure/strutils.nim @@ -60,6 +60,132 @@ const ## doAssert "01234".find(invalid) == -1 ## doAssert "01A34".find(invalid) == 2 +proc isAlpha*(c: char): bool {.noSideEffect, procvar, + rtl, extern: "nsuIsAlphaChar".}= + ## Checks whether or not `c` is alphabetical. + ## + ## This checks a-z, A-Z ASCII characters only. + return c in Letters + +proc isAlphaNumeric*(c: char): bool {.noSideEffect, procvar, + rtl, extern: "nsuIsAlphaNumericChar".}= + ## Checks whether or not `c` is alphanumeric. + ## + ## This checks a-z, A-Z, 0-9 ASCII characters only. + return c in Letters and c in Digits + +proc isDigit*(c: char): bool {.noSideEffect, procvar, + rtl, extern: "nsuIsDigitChar".}= + ## Checks whether or not `c` is a number. + ## + ## This checks 0-9 ASCII characters only. + return c in Digits + +proc isSpace*(c: char): bool {.noSideEffect, procvar, + rtl, extern: "nsuIsSpaceChar".}= + ## Checks whether or not `c` is a whitespace character. + return c in Whitespace + +proc isLower*(c: char): bool {.noSideEffect, procvar, + rtl, extern: "nsuIsLowerChar".}= + ## Checks whether or not `c` is a lower case character. + ## + ## This checks ASCII characters only. + return c in {'a'..'z'} + +proc isUpper*(c: char): bool {.noSideEffect, procvar, + rtl, extern: "nsuIsUpperChar".}= + ## Checks whether or not `c` is an upper case character. + ## + ## This checks ASCII characters only. + return c in {'A'..'Z'} + +proc isAlpha*(s: string): bool {.noSideEffect, procvar, + rtl, extern: "nsuIsAlphaStr".}= + ## Checks whether or not `s` is alphabetical. + ## + ## This checks a-z, A-Z ASCII characters only. + ## Returns true if all characters in `s` are + ## alphabetic and there is at least one character + ## in `s`. + if s.len() == 0: + return false + + result = true + for c in s: + result = c.isAlpha() and result + +proc isAlphaNumeric*(s: string): bool {.noSideEffect, procvar, + rtl, extern: "nsuIsAlphaNumericStr".}= + ## Checks whether or not `s` is alphanumeric. + ## + ## This checks a-z, A-Z, 0-9 ASCII characters only. + ## Returns true if all characters in `s` are + ## alpanumeric and there is at least one character + ## in `s`. + if s.len() == 0: + return false + + result = true + for c in s: + result = c.isAlphaNumeric() and result + +proc isDigit*(s: string): bool {.noSideEffect, procvar, + rtl, extern: "nsuIsDigitStr".}= + ## Checks whether or not `s` is a numeric value. + ## + ## This checks 0-9 ASCII characters only. + ## Returns true if all characters in `s` are + ## numeric and there is at least one character + ## in `s`. + if s.len() == 0: + return false + + result = true + for c in s: + result = c.isDigit() and result + +proc isSpace*(s: string): bool {.noSideEffect, procvar, + rtl, extern: "nsuIsSpaceStr".}= + ## Checks whether or not `s` is completely whitespace. + ## + ## Returns true if all characters in `s` are whitespace + ## characters and there is at least one character in `s`. + if s.len() == 0: + return false + + result = true + for c in s: + result = c.isSpace() and result + +proc isLower*(s: string): bool {.noSideEffect, procvar, + rtl, extern: "nsuIsLowerStr".}= + ## Checks whether or not `s` contains all lower case characters. + ## + ## This checks ASCII characters only. + ## Returns true if all characters in `s` are lower case + ## and there is at least one character in `s`. + if s.len() == 0: + return false + + result = true + for c in s: + result = c.isLower() and result + +proc isUpper*(s: string): bool {.noSideEffect, procvar, + rtl, extern: "nsuIsUpperStr".}= + ## Checks whether or not `s` contains all upper case characters. + ## + ## This checks ASCII characters only. + ## Returns true if all characters in `s` are upper case + ## and there is at least one character in `s`. + if s.len() == 0: + return false + + result = true + for c in s: + result = c.isUpper() and result + proc toLower*(c: char): char {.noSideEffect, procvar, rtl, extern: "nsuToLowerChar".} = ## Converts `c` into lower case. From 2e7cc9e1592d37cf4481077e95f982ae4b80af6c Mon Sep 17 00:00:00 2001 From: Varriount Date: Sat, 10 Oct 2015 06:42:38 -0400 Subject: [PATCH 16/32] Update readme.md --- readme.md | 1 - 1 file changed, 1 deletion(-) diff --git a/readme.md b/readme.md index 80723cabc9..cd40000c88 100644 --- a/readme.md +++ b/readme.md @@ -94,7 +94,6 @@ All rights reserved. [windows-x86-img]: http://buildbot.nim-lang.org/buildstatusimage?builder=windows-x32-builder [windows-x86_64-img]: http://buildbot.nim-lang.org/buildstatusimage?builder=windows-x64-builder -[mac-x86-img]: http://buildbot.nim-lang.org/buildstatusimage?builder=mac-x32-builder [mac-x86_64-img]: http://buildbot.nim-lang.org/buildstatusimage?builder=mac-x64-builder [waterfall]: http://buildbot.nim-lang.org/waterfall From dc854f3480f993da7ab27f6b1182c8d2fd418416 Mon Sep 17 00:00:00 2001 From: Varriount Date: Sat, 10 Oct 2015 06:52:13 -0400 Subject: [PATCH 17/32] Update readme.md --- readme.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/readme.md b/readme.md index cd40000c88..57fc223d3f 100644 --- a/readme.md +++ b/readme.md @@ -79,11 +79,11 @@ All rights reserved. # Build Status [**Build Waterfall**][waterfall] -| | Linux | Windows | Mac | -| ------ | ----- | ------- | --- | -| x86 | ![linux-x86][linux-x86-img] | ![windows-x86][windows-x86-img] | ![mac-x86][mac-x86-img] | -| x86_64 | ![linux-x86_64][linux-x86_64-img] | ![windows-x86_64][windows-x86_64-img] | ![mac-x86_64][mac-x86_64-img] | -| arm | ![linux-armv5][linux-arm5-img]
![linux-armv6][linux-arm6-img]
![linux-armv7][linux-arm7-img] | | | +| | Linux | Windows | Mac | +| ------ | ----- | ------- | --- | +| x86 | ![linux-x86][linux-x86-img] | ![windows-x86][windows-x86-img] | +| x86_64 | ![linux-x86_64][linux-x86_64-img] | ![windows-x86_64][windows-x86_64-img] | ![mac-x86_64][mac-x86_64-img] | +| arm | ![linux-armv5][linux-arm5-img]
![linux-armv6][linux-arm6-img]
![linux-armv7][linux-arm7-img] [linux-x86-img]: http://buildbot.nim-lang.org/buildstatusimage?builder=linux-x32-builder [linux-x86_64-img]: http://buildbot.nim-lang.org/buildstatusimage?builder=linux-x64-builder From e3bc27ac15ae59630c76f9652db249f05faf8cfb Mon Sep 17 00:00:00 2001 From: Joey Payne Date: Sat, 10 Oct 2015 08:40:31 -0600 Subject: [PATCH 18/32] Changed alphanumeric check to "or" instead of "and". --- lib/pure/strutils.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pure/strutils.nim b/lib/pure/strutils.nim index 005715a30a..05862ca87f 100644 --- a/lib/pure/strutils.nim +++ b/lib/pure/strutils.nim @@ -72,7 +72,7 @@ proc isAlphaNumeric*(c: char): bool {.noSideEffect, procvar, ## Checks whether or not `c` is alphanumeric. ## ## This checks a-z, A-Z, 0-9 ASCII characters only. - return c in Letters and c in Digits + return c in Letters or c in Digits proc isDigit*(c: char): bool {.noSideEffect, procvar, rtl, extern: "nsuIsDigitChar".}= From ea9a1e26bee4aad6660d3a3cf027ddefe3312196 Mon Sep 17 00:00:00 2001 From: Joey Payne Date: Sat, 10 Oct 2015 08:55:19 -0600 Subject: [PATCH 19/32] Added tests for string test procs. --- lib/pure/strutils.nim | 52 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/lib/pure/strutils.nim b/lib/pure/strutils.nim index 05862ca87f..f1f5b8dc81 100644 --- a/lib/pure/strutils.nim +++ b/lib/pure/strutils.nim @@ -1652,3 +1652,55 @@ when isMainModule: doAssert strip("sfoofoofoos", trailing = false, chars = {'s'}) == "foofoofoos" doAssert " foo\n bar".indent(4, "Q") == "QQQQ foo\nQQQQ bar" + + doAssert isAlpha('r') == true + doAssert isAlpha('A') == true + doAssert isAlpha('$') == false + + doAssert isAlpha("Rasp") == true + doAssert isAlpha("Args") == true + doAssert isAlpha("$Tomato") == false + + doAssert isAlphaNumeric('3') == true + doAssert isAlphaNumeric('R') == true + doAssert isAlphaNumeric('!') == false + + doAssert isAlphaNumeric("34ABc") == true + doAssert isAlphaNumeric("Rad") == true + doAssert isAlphaNumeric("1234") == true + doAssert isAlphaNumeric("@nose") == false + + doAssert isDigit('3') == true + doAssert isDigit('a') == false + doAssert isDigit('%') == false + + doAssert isDigit("12533") == true + doAssert isDigit("12.33") == false + doAssert isDigit("A45b") == false + + doAssert isSpace('\t') == true + doAssert isSpace('\l') == true + doAssert isSpace('A') == false + + doAssert isSpace("\t\l \v\r\f") == true + doAssert isSpace(" ") == true + doAssert isSpace("ABc \td") == false + + doAssert isLower('a') == true + doAssert isLower('z') == true + doAssert isLower('A') == false + doAssert isLower('5') == false + doAssert isLower('&') == false + + doAssert isLower("abcd") == true + doAssert isLower("abCD") == false + doAssert isLower("33aa") == false + + doAssert isUpper('A') == true + doAssert isUpper('b') == false + doAssert isUpper('5') == false + doAssert isUpper('%') == false + + doAssert isUpper("ABC") == true + doAssert isUpper("AAcc") == false + doAssert isUpper("A#$") == false From 2d256a4489a214ee10407890783d329d5f27e374 Mon Sep 17 00:00:00 2001 From: Joey Payne Date: Sat, 10 Oct 2015 09:13:00 -0600 Subject: [PATCH 20/32] Made strutils string test procs less redundant. --- lib/pure/strutils.nim | 80 +++++++++++++++++++++---------------------- 1 file changed, 40 insertions(+), 40 deletions(-) diff --git a/lib/pure/strutils.nim b/lib/pure/strutils.nim index f1f5b8dc81..a78fed4b91 100644 --- a/lib/pure/strutils.nim +++ b/lib/pure/strutils.nim @@ -1653,54 +1653,54 @@ when isMainModule: doAssert " foo\n bar".indent(4, "Q") == "QQQQ foo\nQQQQ bar" - doAssert isAlpha('r') == true - doAssert isAlpha('A') == true - doAssert isAlpha('$') == false + doAssert isAlpha('r') + doAssert isAlpha('A') + doAssert(not isAlpha('$')) - doAssert isAlpha("Rasp") == true - doAssert isAlpha("Args") == true - doAssert isAlpha("$Tomato") == false + doAssert isAlpha("Rasp") + doAssert isAlpha("Args") + doAssert(not isAlpha("$Tomato")) - doAssert isAlphaNumeric('3') == true - doAssert isAlphaNumeric('R') == true - doAssert isAlphaNumeric('!') == false + doAssert isAlphaNumeric('3') + doAssert isAlphaNumeric('R') + doAssert(not isAlphaNumeric('!')) - doAssert isAlphaNumeric("34ABc") == true - doAssert isAlphaNumeric("Rad") == true - doAssert isAlphaNumeric("1234") == true - doAssert isAlphaNumeric("@nose") == false + doAssert isAlphaNumeric("34ABc") + doAssert isAlphaNumeric("Rad") + doAssert isAlphaNumeric("1234") + doAssert(not isAlphaNumeric("@nose")) - doAssert isDigit('3') == true - doAssert isDigit('a') == false - doAssert isDigit('%') == false + doAssert isDigit('3') + doAssert(not isDigit('a')) + doAssert(not isDigit('%')) - doAssert isDigit("12533") == true - doAssert isDigit("12.33") == false - doAssert isDigit("A45b") == false + doAssert isDigit("12533") + doAssert(not isDigit("12.33")) + doAssert(not isDigit("A45b")) - doAssert isSpace('\t') == true - doAssert isSpace('\l') == true - doAssert isSpace('A') == false + doAssert isSpace('\t') + doAssert isSpace('\l') + doAssert(not isSpace('A')) - doAssert isSpace("\t\l \v\r\f") == true - doAssert isSpace(" ") == true - doAssert isSpace("ABc \td") == false + doAssert isSpace("\t\l \v\r\f") + doAssert isSpace(" ") + doAssert(not isSpace("ABc \td")) - doAssert isLower('a') == true - doAssert isLower('z') == true - doAssert isLower('A') == false - doAssert isLower('5') == false - doAssert isLower('&') == false + doAssert isLower('a') + doAssert isLower('z') + doAssert(not isLower('A')) + doAssert(not isLower('5')) + doAssert(not isLower('&')) - doAssert isLower("abcd") == true - doAssert isLower("abCD") == false - doAssert isLower("33aa") == false + doAssert isLower("abcd") + doAssert(not isLower("abCD")) + doAssert(not isLower("33aa")) - doAssert isUpper('A') == true - doAssert isUpper('b') == false - doAssert isUpper('5') == false - doAssert isUpper('%') == false + doAssert isUpper('A') + doAssert(not isUpper('b')) + doAssert(not isUpper('5')) + doAssert(not isUpper('%')) - doAssert isUpper("ABC") == true - doAssert isUpper("AAcc") == false - doAssert isUpper("A#$") == false + doAssert isUpper("ABC") + doAssert(not isUpper("AAcc")) + doAssert(not isUpper("A#$")) From 3e897a7c71997b039a55da04450b051d3d870003 Mon Sep 17 00:00:00 2001 From: Araq Date: Mon, 12 Oct 2015 16:50:23 +0200 Subject: [PATCH 21/32] added setResult that simply takes a node --- compiler/vmhooks.nim | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/compiler/vmhooks.nim b/compiler/vmhooks.nim index 5dd27feda1..576b0565fe 100644 --- a/compiler/vmhooks.nim +++ b/compiler/vmhooks.nim @@ -30,6 +30,14 @@ proc setResult*(a: VmArgs; v: string) = s[a.ra].node = newNode(nkStrLit) s[a.ra].node.strVal = v +proc setResult*(a: VmArgs; n: PNode) = + var s: seq[TFullReg] + move(s, cast[seq[TFullReg]](a.slots)) + if s[a.ra].kind != rkNode: + myreset(s[a.ra]) + s[a.ra].kind = rkNode + s[a.ra].node = n + proc setResult*(a: VmArgs; v: seq[string]) = var s: seq[TFullReg] move(s, cast[seq[TFullReg]](a.slots)) From 4705cf2308a6772fadff670fe15313458ce434da Mon Sep 17 00:00:00 2001 From: Araq Date: Mon, 12 Oct 2015 16:50:59 +0200 Subject: [PATCH 22/32] cleaned up ospaths module --- lib/pure/ospaths.nim | 46 +++++++++++++++++++++++---------------- tests/newconfig/tfoo.nims | 3 +++ 2 files changed, 30 insertions(+), 19 deletions(-) diff --git a/lib/pure/ospaths.nim b/lib/pure/ospaths.nim index 667ca82d73..e9f5bee0ae 100644 --- a/lib/pure/ospaths.nim +++ b/lib/pure/ospaths.nim @@ -26,8 +26,10 @@ when not declared(getEnv) or defined(nimscript): ## to an environment variable ReadDirEffect* = object of ReadIOEffect ## effect that denotes a write - ## operation to the directory structure - WriteDirEffect* = object of WriteIOEffect ## effect that denotes a write operation to + ## operation to the directory + ## structure + WriteDirEffect* = object of WriteIOEffect ## effect that denotes a write + ## operation to ## the directory structure OSErrorCode* = distinct int32 ## Specifies an OS Error Code. @@ -63,13 +65,13 @@ when not declared(getEnv) or defined(nimscript): AltSep* = '/' ## An alternative character used by the operating system to separate ## pathname components, or the same as `DirSep` if only one separator - ## character exists. This is set to '/' on Windows systems where `DirSep` - ## is a backslash. + ## character exists. This is set to '/' on Windows systems + ## where `DirSep` is a backslash. PathSep* = ':' ## The character conventionally used by the operating system to separate - ## search patch components (as in PATH), such as ':' for POSIX or ';' for - ## Windows. + ## search patch components (as in PATH), such as ':' for POSIX + ## or ';' for Windows. FileSystemCaseSensitive* = true ## true if the file system is case sensitive, false otherwise. Used by @@ -104,7 +106,8 @@ when not declared(getEnv) or defined(nimscript): # MacOS directory separator is a colon ":" which is the only character not # allowed in filenames. # - # A path containing no colon or which begins with a colon is a partial path. + # A path containing no colon or which begins with a colon is a partial + # path. # E.g. ":kalle:petter" ":kalle" "kalle" # # All other paths are full (absolute) paths. E.g. "HD:kalle:" "HD:" @@ -206,9 +209,9 @@ when not declared(getEnv) or defined(nimscript): proc joinPath*(parts: varargs[string]): string {.noSideEffect, rtl, extern: "nos$1OpenArray".} = - ## The same as `joinPath(head, tail)`, but works with any number of directory - ## parts. You need to pass at least one element or the proc will assert in - ## debug builds and crash on release builds. + ## The same as `joinPath(head, tail)`, but works with any number of + ## directory parts. You need to pass at least one element or the proc + ## will assert in debug builds and crash on release builds. result = parts[0] for i in 1..high(parts): result = joinPath(result, parts[i]) @@ -316,8 +319,8 @@ when not declared(getEnv) or defined(nimscript): if inclusive: yield path proc `/../` * (head, tail: string): string {.noSideEffect.} = - ## The same as ``parentDir(head) / tail`` unless there is no parent directory. - ## Then ``head / tail`` is performed instead. + ## The same as ``parentDir(head) / tail`` unless there is no parent + ## directory. Then ``head / tail`` is performed instead. let sepPos = parentDirPos(head) if sepPos >= 0: result = substr(head, 0, sepPos-1) / tail @@ -500,7 +503,8 @@ when defined(nimdoc) and not declared(os): proc existsFile(x: string): bool = discard when declared(getEnv) or defined(nimscript): - proc getHomeDir*(): string {.rtl, extern: "nos$1", tags: [ReadEnvEffect, ReadIOEffect].} = + proc getHomeDir*(): string {.rtl, extern: "nos$1", + tags: [ReadEnvEffect, ReadIOEffect].} = ## Returns the home directory of the current user. ## ## This proc is wrapped by the expandTilde proc for the convenience of @@ -508,18 +512,21 @@ when declared(getEnv) or defined(nimscript): when defined(windows): return string(getEnv("USERPROFILE")) & "\\" else: return string(getEnv("HOME")) & "/" - proc getConfigDir*(): string {.rtl, extern: "nos$1", tags: [ReadEnvEffect, ReadIOEffect].} = + proc getConfigDir*(): string {.rtl, extern: "nos$1", + tags: [ReadEnvEffect, ReadIOEffect].} = ## Returns the config directory of the current user for applications. when defined(windows): return string(getEnv("APPDATA")) & "\\" else: return string(getEnv("HOME")) & "/.config/" - proc getTempDir*(): string {.rtl, extern: "nos$1", tags: [ReadEnvEffect].} = + proc getTempDir*(): string {.rtl, extern: "nos$1", + tags: [ReadEnvEffect, ReadIOEffect].} = ## Returns the temporary directory of the current user for applications to ## save temporary files in. when defined(windows): return string(getEnv("TEMP")) & "\\" else: return "/tmp/" - proc expandTilde*(path: string): string {.tags: [ReadEnvEffect, ReadIOEffect].} = + proc expandTilde*(path: string): string {. + tags: [ReadEnvEffect, ReadIOEffect].} = ## Expands a path starting with ``~/`` to a full path. ## ## If `path` starts with the tilde character and is followed by `/` or `\\` @@ -527,8 +534,8 @@ when declared(getEnv) or defined(nimscript): ## the getHomeDir() proc, otherwise the input path will be returned without ## modification. ## - ## The behaviour of this proc is the same on the Windows platform despite not - ## having this convention. Example: + ## The behaviour of this proc is the same on the Windows platform despite + ## not having this convention. Example: ## ## .. code-block:: nim ## let configFile = expandTilde("~" / "appname.cfg") @@ -549,7 +556,8 @@ when declared(getEnv) or defined(nimscript): yield substr(s, first, last-1) inc(last) - proc findExe*(exe: string): string {.tags: [ReadDirEffect, ReadEnvEffect, ReadIOEffect].} = + proc findExe*(exe: string): string {. + tags: [ReadDirEffect, ReadEnvEffect, ReadIOEffect].} = ## Searches for `exe` in the current working directory and then ## in directories listed in the ``PATH`` environment variable. ## Returns "" if the `exe` cannot be found. On DOS-like platforms, `exe` diff --git a/tests/newconfig/tfoo.nims b/tests/newconfig/tfoo.nims index a2166576d0..519a868d5d 100644 --- a/tests/newconfig/tfoo.nims +++ b/tests/newconfig/tfoo.nims @@ -3,6 +3,9 @@ mode = ScriptMode.Whatif exec "gcc -v" +# test that ospaths actually compiles: +import ospaths + --forceBuild task listDirs, "lists every subdirectory": From ca75985fc185b4fa47583534f1c53c33eaad3f6c Mon Sep 17 00:00:00 2001 From: Araq Date: Mon, 12 Oct 2015 16:55:10 +0200 Subject: [PATCH 23/32] nimsuggest: added 'dus' command that combines 'def' and 'use' --- compiler/options.nim | 4 +++- compiler/suggest.nim | 6 +++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/compiler/options.nim b/compiler/options.nim index adb340fea0..23c76acc59 100644 --- a/compiler/options.nim +++ b/compiler/options.nim @@ -86,7 +86,7 @@ type # please make sure we have under 32 options gcNone, gcBoehm, gcGo, gcMarkAndSweep, gcRefc, gcV2, gcGenerational IdeCmd* = enum - ideNone, ideSug, ideCon, ideDef, ideUse + ideNone, ideSug, ideCon, ideDef, ideUse, ideDus var gIdeCmd*: IdeCmd @@ -421,6 +421,7 @@ proc parseIdeCmd*(s: string): IdeCmd = of "con": ideCon of "def": ideDef of "use": ideUse + of "dus": ideDus else: ideNone proc `$`*(c: IdeCmd): string = @@ -429,4 +430,5 @@ proc `$`*(c: IdeCmd): string = of ideCon: "con" of ideDef: "def" of ideUse: "use" + of ideDus: "dus" of ideNone: "none" diff --git a/compiler/suggest.nim b/compiler/suggest.nim index ed21aa4eae..18d7233152 100644 --- a/compiler/suggest.nim +++ b/compiler/suggest.nim @@ -309,6 +309,10 @@ proc suggestSym*(info: TLineInfo; s: PSym) {.inline.} = findUsages(info, s) elif gIdeCmd == ideDef: findDefinition(info, s) + elif gIdeCmd == ideDus and s != nil: + if isTracked(info, s.name.s.len): + suggestResult(symToSuggest(s, isLocal=false, $ideDef)) + findUsages(info, s) proc markUsed(info: TLineInfo; s: PSym) = incl(s.flags, sfUsed) @@ -366,7 +370,7 @@ proc suggestExpr*(c: PContext, node: PNode) = suggestCall(c, a, n, outputs) dec(c.compilesContextId) - if outputs > 0 and gIdeCmd != ideUse: suggestQuit() + if outputs > 0 and gIdeCmd notin {ideUse, ideDus}: suggestQuit() proc suggestStmt*(c: PContext, n: PNode) = suggestExpr(c, n) From 645cf70112495a0326371d8f81e2095da87f15bf Mon Sep 17 00:00:00 2001 From: Araq Date: Mon, 12 Oct 2015 19:58:43 +0200 Subject: [PATCH 24/32] disable new BoehmGC tests on Windows --- tests/testament/categories.nim | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/tests/testament/categories.nim b/tests/testament/categories.nim index 33ce086d35..3166942ecb 100644 --- a/tests/testament/categories.nim +++ b/tests/testament/categories.nim @@ -125,10 +125,13 @@ proc gcTests(r: var TResults, cat: Category, options: string) = " -d:release --gc:markAndSweep", cat, actionRun) template test(filename: expr): stmt = testWithoutBoehm filename - testSpec r, makeTest("tests/gc" / filename, options & - " --gc:boehm", cat, actionRun) - testSpec r, makeTest("tests/gc" / filename, options & - " -d:release --gc:boehm", cat, actionRun) + when not defined(windows): + # AR: cannot find any boehm.dll on the net, right now, so disabled + # for windows: + testSpec r, makeTest("tests/gc" / filename, options & + " --gc:boehm", cat, actionRun) + testSpec r, makeTest("tests/gc" / filename, options & + " -d:release --gc:boehm", cat, actionRun) test "gcemscripten" test "growobjcrash" From e0f896785d81ce22d6ff54b00c5e7e84c126e286 Mon Sep 17 00:00:00 2001 From: Araq Date: Mon, 12 Oct 2015 20:54:43 +0200 Subject: [PATCH 25/32] docs now build again --- lib/pure/md5.nim | 2 -- lib/{deprecated => }/pure/parseopt.nim | 0 web/website.ini | 11 ++++++----- 3 files changed, 6 insertions(+), 7 deletions(-) rename lib/{deprecated => }/pure/parseopt.nim (100%) diff --git a/lib/pure/md5.nim b/lib/pure/md5.nim index 5ee301b15c..44b9ed0d4e 100644 --- a/lib/pure/md5.nim +++ b/lib/pure/md5.nim @@ -9,8 +9,6 @@ ## Module for computing MD5 checksums. -import unsigned - type MD5State = array[0..3, uint32] MD5Block = array[0..15, uint32] diff --git a/lib/deprecated/pure/parseopt.nim b/lib/pure/parseopt.nim similarity index 100% rename from lib/deprecated/pure/parseopt.nim rename to lib/pure/parseopt.nim diff --git a/web/website.ini b/web/website.ini index dcfea8bf4c..0a2117564d 100644 --- a/web/website.ini +++ b/web/website.ini @@ -34,8 +34,8 @@ doc: "tools;niminst;nimgrep;gc;estp;idetools;docgen;koch;backends.txt" doc: "nimfix.txt;nimsuggest.txt;nep1.txt;nims.txt" pdf: "manual.txt;lib;tut1;tut2;nimc;niminst;gc" srcdoc2: "system.nim;system/nimscript;pure/ospaths" -srcdoc2: "core/macros;pure/marshal;core/typeinfo;core/unsigned" -srcdoc2: "impure/re;pure/sockets;pure/typetraits" +srcdoc2: "core/macros;pure/marshal;core/typeinfo" +srcdoc2: "impure/re;pure/typetraits" srcdoc2: "pure/concurrency/threadpool.nim;pure/concurrency/cpuinfo.nim" srcdoc: "system/threads.nim;system/channels.nim;js/dom" srcdoc2: "pure/os;pure/strutils;pure/math;pure/matchers;pure/algorithm" @@ -52,12 +52,13 @@ srcdoc2: "pure/json;pure/base64;pure/scgi" srcdoc2: "pure/collections/tables;pure/collections/sets;pure/collections/lists" srcdoc2: "pure/collections/intsets;pure/collections/queues;pure/encodings" srcdoc2: "pure/events;pure/collections/sequtils;pure/cookies" -srcdoc2: "pure/ftpclient;pure/memfiles;pure/subexes;pure/collections/critbits" -srcdoc2: "pure/asyncio;pure/actors;core/locks;pure/oids;pure/endians;pure/uri" +srcdoc2: "pure/memfiles;pure/subexes;pure/collections/critbits" +srcdoc2: "deprecated/pure/asyncio;deprecated/pure/actors;core/locks;pure/oids;pure/endians;pure/uri" srcdoc2: "pure/nimprof;pure/unittest;packages/docutils/highlite" srcdoc2: "packages/docutils/rst;packages/docutils/rstast" srcdoc2: "packages/docutils/rstgen;pure/logging;pure/asyncdispatch;pure/asyncnet" -srcdoc2: "pure/rawsockets;pure/asynchttpserver;pure/net;pure/selectors;pure/future" +srcdoc2: "deprecated/pure/rawsockets;pure/asynchttpserver;pure/net;pure/selectors;pure/future" +srcdoc2: "deprecated/pure/ftpclient" srcdoc2: "pure/asyncfile" srcdoc2: "pure/md5;pure/rationals" srcdoc2: "posix/posix" From c7a30791239f2a99656eae1087b9742ee7e0e8ba Mon Sep 17 00:00:00 2001 From: Araq Date: Mon, 12 Oct 2015 21:08:44 +0200 Subject: [PATCH 26/32] logging.nim: expose underlying 'file' object; errors and fatals flush the buffer; refs #3270 --- lib/pure/logging.nim | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/lib/pure/logging.nim b/lib/pure/logging.nim index c6c7945359..aa55b5ade7 100644 --- a/lib/pure/logging.nim +++ b/lib/pure/logging.nim @@ -77,7 +77,7 @@ type ## console FileLogger* = ref object of Logger ## logger that writes the messages to a file - f: File + file*: File ## the wrapped file. RollingFileLogger* = ref object of FileLogger ## logger that writes the ## messages to a file and @@ -126,7 +126,7 @@ proc substituteLog*(frmt: string, level: Level, args: varargs[string, `$`]): str method log*(logger: Logger, level: Level, args: varargs[string, `$`]) {. raises: [Exception], - tags: [TimeEffect, WriteIOEffect, ReadIOEffect].} = + tags: [TimeEffect, WriteIOEffect, ReadIOEffect], base.} = ## Override this method in custom loggers. Default implementation does ## nothing. discard @@ -135,15 +135,17 @@ method log*(logger: ConsoleLogger, level: Level, args: varargs[string, `$`]) = ## Logs to the console using ``logger`` only. if level >= logger.levelThreshold: writeLine(stdout, substituteLog(logger.fmtStr, level, args)) + if level in {lvlError, lvlFatal}: flushFile(stdout) method log*(logger: FileLogger, level: Level, args: varargs[string, `$`]) = ## Logs to a file using ``logger`` only. if level >= logger.levelThreshold: - writeLine(logger.f, substituteLog(logger.fmtStr, level, args)) + writeLine(logger.file, substituteLog(logger.fmtStr, level, args)) + if level in {lvlError, lvlFatal}: flushFile(logger.file) proc defaultFilename*(): string = ## Returns the default filename for a logger. - var (path, name, ext) = splitFile(getAppFilename()) + var (path, name, _) = splitFile(getAppFilename()) result = changeFileExt(path / name, "log") proc newConsoleLogger*(levelThreshold = lvlAll, fmtStr = defaultFmtStr): ConsoleLogger = @@ -162,14 +164,14 @@ proc newFileLogger*(filename = defaultFilename(), ## (-1: use system defaults, 0: unbuffered, >0: fixed buffer size). new(result) result.levelThreshold = levelThreshold - result.f = open(filename, mode, bufSize = bufSize) + result.file = open(filename, mode, bufSize = bufSize) result.fmtStr = fmtStr # ------ proc countLogLines(logger: RollingFileLogger): int = result = 0 - for line in logger.f.lines(): + for line in logger.file.lines(): result.inc() proc countFiles(filename: string): int = @@ -202,7 +204,7 @@ proc newRollingFileLogger*(filename = defaultFilename(), result.fmtStr = fmtStr result.maxLines = maxLines result.bufSize = bufSize - result.f = open(filename, mode, bufSize=result.bufSize) + result.file = open(filename, mode, bufSize=result.bufSize) result.curLine = 0 result.baseName = filename result.baseMode = mode @@ -224,13 +226,14 @@ method log*(logger: RollingFileLogger, level: Level, args: varargs[string, `$`]) ## Logs to a file using rolling ``logger`` only. if level >= logger.levelThreshold: if logger.curLine >= logger.maxLines: - logger.f.close() + logger.file.close() rotate(logger) logger.logFiles.inc logger.curLine = 0 - logger.f = open(logger.baseName, logger.baseMode, bufSize = logger.bufSize) + logger.file = open(logger.baseName, logger.baseMode, bufSize = logger.bufSize) - writeLine(logger.f, substituteLog(logger.fmtStr, level, args)) + writeLine(logger.file, substituteLog(logger.fmtStr, level, args)) + if level in {lvlError, lvlFatal}: flushFile(logger.file) logger.curLine.inc # -------- From 2c33ebed7be1313fc66a80437a66e9d4155308a9 Mon Sep 17 00:00:00 2001 From: Araq Date: Mon, 12 Oct 2015 21:12:00 +0200 Subject: [PATCH 27/32] improves new tests --- tests/collections/tapply.nim | 6 +++++- tests/collections/tmapit.nim | 9 +++++++-- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/tests/collections/tapply.nim b/tests/collections/tapply.nim index 403321ce13..2b7464216a 100644 --- a/tests/collections/tapply.nim +++ b/tests/collections/tapply.nim @@ -1,7 +1,11 @@ +discard """ + output: '''true''' +""" + import sequtils var x = @[1, 2, 3] x.apply(proc(x: var int) = x = x+10) x.apply(proc(x: int): int = x+100) x.applyIt(it+5000) -doAssert x == @[5111, 5112, 5113] +echo x == @[5111, 5112, 5113] diff --git a/tests/collections/tmapit.nim b/tests/collections/tmapit.nim index 0675618829..b2afa94295 100644 --- a/tests/collections/tmapit.nim +++ b/tests/collections/tmapit.nim @@ -1,9 +1,14 @@ +discard """ + output: '''true +true''' +""" + import sequtils var x = @[1, 2, 3] # This mapIt call will run with preallocation because ``len`` is available. var y = x.mapIt($(it+10)) -doAssert y == @["11", "12", "13"] +echo y == @["11", "12", "13"] type structureWithoutLen = object a: array[5, int] @@ -25,4 +30,4 @@ st.a[4] = 4 # this will run without preallocating the result # since ``len`` is not available var r = st.mapIt($(it+10)) -doAssert r == @["10", "11", "12", "13", "14"] +echo r == @["10", "11", "12", "13", "14"] From c6d653f30d7d53eefdda637a1084be7defa3d141 Mon Sep 17 00:00:00 2001 From: Adam Strzelecki Date: Tue, 13 Oct 2015 00:11:21 +0200 Subject: [PATCH 28/32] readme.md: Open builder page from its status icon Previously clicking on that icon was opening just the icon image in new browser window, which is default behavior - not very useful in our case. --- readme.md | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/readme.md b/readme.md index 57fc223d3f..4c996ebae4 100644 --- a/readme.md +++ b/readme.md @@ -81,19 +81,27 @@ All rights reserved. | | Linux | Windows | Mac | | ------ | ----- | ------- | --- | -| x86 | ![linux-x86][linux-x86-img] | ![windows-x86][windows-x86-img] | -| x86_64 | ![linux-x86_64][linux-x86_64-img] | ![windows-x86_64][windows-x86_64-img] | ![mac-x86_64][mac-x86_64-img] | -| arm | ![linux-armv5][linux-arm5-img]
![linux-armv6][linux-arm6-img]
![linux-armv7][linux-arm7-img] +| x86 | [![linux-x86][linux-x86-img]][linux-x86] | [![windows-x86][windows-x86-img]][windows-x86] | +| x86_64 | [![linux-x86_64][linux-x86_64-img]][linux-x86_64] | [![windows-x86_64][windows-x86_64-img]][windows-x86_64] | [![mac-x86_64][mac-x86_64-img]][mac-x86_64] | +| arm | [![linux-armv5][linux-arm5-img]][linux-arm5]
[![linux-armv6][linux-arm6-img]][linux-arm6]
[![linux-armv7][linux-arm7-img]][linux-arm7] +[linux-x86]: http://buildbot.nim-lang.org/builders/linux-x32-builder [linux-x86-img]: http://buildbot.nim-lang.org/buildstatusimage?builder=linux-x32-builder +[linux-x86_64]: http://buildbot.nim-lang.org/builders/linux-x64-builder [linux-x86_64-img]: http://buildbot.nim-lang.org/buildstatusimage?builder=linux-x64-builder +[linux-arm5]: http://buildbot.nim-lang.org/builders/linux-arm5-builder [linux-arm5-img]: http://buildbot.nim-lang.org/buildstatusimage?builder=linux-arm5-builder +[linux-arm6]: http://buildbot.nim-lang.org/builders/linux-arm6-builder [linux-arm6-img]: http://buildbot.nim-lang.org/buildstatusimage?builder=linux-arm6-builder +[linux-arm7]: http://buildbot.nim-lang.org/builders/linux-arm7-builder [linux-arm7-img]: http://buildbot.nim-lang.org/buildstatusimage?builder=linux-arm7-builder +[windows-x86]: http://buildbot.nim-lang.org/builders/windows-x32-builder [windows-x86-img]: http://buildbot.nim-lang.org/buildstatusimage?builder=windows-x32-builder +[windows-x86_64]: http://buildbot.nim-lang.org/builders/windows-x64-builder [windows-x86_64-img]: http://buildbot.nim-lang.org/buildstatusimage?builder=windows-x64-builder +[mac-x86_64]: http://buildbot.nim-lang.org/builders/mac-x64-builder [mac-x86_64-img]: http://buildbot.nim-lang.org/buildstatusimage?builder=mac-x64-builder [waterfall]: http://buildbot.nim-lang.org/waterfall From 2fda95a4d630aa8b293f16e4f21471f7ee8e743a Mon Sep 17 00:00:00 2001 From: Araq Date: Tue, 13 Oct 2015 03:03:05 +0200 Subject: [PATCH 29/32] added getOrDefault; bootstrapping works again --- compiler/importer.nim | 4 +- compiler/main.nim | 2 +- compiler/nimblecmd.nim | 2 +- compiler/options.nim | 2 +- compiler/vmmarshal.nim | 2 +- lib/pure/collections/intsets.nim | 2 + lib/pure/collections/tables.nim | 71 +++++++++++++++++--------------- lib/pure/strtabs.nim | 5 +++ lib/pure/xmltree.nim | 2 +- 9 files changed, 52 insertions(+), 40 deletions(-) diff --git a/compiler/importer.nim b/compiler/importer.nim index 657f41eabe..c121059fdd 100644 --- a/compiler/importer.nim +++ b/compiler/importer.nim @@ -121,7 +121,7 @@ proc importAllSymbolsExcept(c: PContext, fromMod: PSym, exceptSet: IntSet) = if s.kind != skEnumField: if s.kind notin ExportableSymKinds: internalError(s.info, "importAllSymbols: " & $s.kind) - if s.name.id notin exceptSet: + if exceptSet.isNil or s.name.id notin exceptSet: rawImportSymbol(c, s) s = nextIter(i, fromMod.tab) @@ -138,7 +138,7 @@ proc importForwarded(c: PContext, n: PNode, exceptSet: IntSet) = let s = a.sym if s.kind == skModule: importAllSymbolsExcept(c, s, exceptSet) - elif s.name.id notin exceptSet: + elif exceptSet.isNil or s.name.id notin exceptSet: rawImportSymbol(c, s) of nkExportExceptStmt: localError(n.info, errGenerated, "'export except' not implemented") diff --git a/compiler/main.nim b/compiler/main.nim index 3bb6fc343e..2ee07a443e 100644 --- a/compiler/main.nim +++ b/compiler/main.nim @@ -15,7 +15,7 @@ import wordrecg, sem, semdata, idents, passes, docgen, extccomp, cgen, jsgen, json, nversion, platform, nimconf, importer, passaux, depends, vm, vmdef, types, idgen, - tables, docgen2, service, parser, modules, ccgutils, sigmatch, ropes, lists + docgen2, service, parser, modules, ccgutils, sigmatch, ropes, lists from magicsys import systemModule, resetSysTypes diff --git a/compiler/nimblecmd.nim b/compiler/nimblecmd.nim index 9b647e67d7..c6c2ab0587 100644 --- a/compiler/nimblecmd.nim +++ b/compiler/nimblecmd.nim @@ -48,7 +48,7 @@ proc addPackage(packages: StringTableRef, p: string) = let name = p.substr(0, x-1) if x < p.len: let version = p.substr(x+1) - if packages[name] <. version: + if packages.getOrDefault(name) <. version: packages[name] = version else: packages[name] = latest diff --git a/compiler/options.nim b/compiler/options.nim index 23c76acc59..98224a11df 100644 --- a/compiler/options.nim +++ b/compiler/options.nim @@ -173,7 +173,7 @@ proc existsConfigVar*(key: string): bool = result = hasKey(gConfigVars, key) proc getConfigVar*(key: string): string = - result = gConfigVars[key] + result = gConfigVars.getOrDefault key proc setConfigVar*(key, val: string) = gConfigVars[key] = val diff --git a/compiler/vmmarshal.nim b/compiler/vmmarshal.nim index 1670dd4c43..c08c5d2493 100644 --- a/compiler/vmmarshal.nim +++ b/compiler/vmmarshal.nim @@ -239,7 +239,7 @@ proc loadAny(p: var JsonParser, t: PType, result = newNode(nkNilLit) next(p) of jsonInt: - result = tab[p.getInt] + result = tab.getOrDefault(p.getInt) if result.isNil: raiseParseErr(p, "cannot load object with address " & $p.getInt) next(p) diff --git a/lib/pure/collections/intsets.nim b/lib/pure/collections/intsets.nim index 38bc9d4629..603a4b5958 100644 --- a/lib/pure/collections/intsets.nim +++ b/lib/pure/collections/intsets.nim @@ -138,6 +138,8 @@ proc initIntSet*: IntSet = result.counter = 0 result.head = nil +proc isNil*(x: IntSet): bool {.inline.} = x.head.isNil + proc assign*(dest: var IntSet, src: IntSet) = ## copies `src` to `dest`. `dest` does not need to be initialized by ## `initIntSet`. diff --git a/lib/pure/collections/tables.nim b/lib/pure/collections/tables.nim index bb64406527..37d52b6de7 100644 --- a/lib/pure/collections/tables.nim +++ b/lib/pure/collections/tables.nim @@ -96,18 +96,10 @@ proc len*[A, B](t: Table[A, B]): int = ## returns the number of keys in `t`. result = t.counter -proc `[]`*[A, B](t: Table[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 hc: Hash - var index = rawGet(t, key, hc) - if index >= 0: result = t.data[index].val - -proc mget*[A, B](t: var Table[A, B], key: A): var B = +template get(t, key): untyped {.immediate.} = ## retrieves the value at ``t[key]``. The value can be modified. ## If `key` is not in `t`, the ``KeyError`` exception is raised. + mixin rawGet var hc: Hash var index = rawGet(t, key, hc) if index >= 0: result = t.data[index].val @@ -117,6 +109,12 @@ proc mget*[A, B](t: var Table[A, B], key: A): var B = else: raise newException(KeyError, "key not found") +template getOrDefaultImpl(t, key): untyped {.immediate.} = + mixin rawGet + var hc: Hash + var index = rawGet(t, key, hc) + if index >= 0: result = t.data[index].val + proc `[]`*[A, B](t: Table[A, B], key: A): B = ## retrieves the value at ``t[key]``. If `key` is not in `t`, the ## ``KeyError`` exception is raised. One can check with ``hasKey`` whether @@ -134,6 +132,8 @@ proc mget*[A, B](t: var Table[A, B], key: A): var B {.deprecated.} = ## instead. get(t, key) +proc getOrDefault*[A, B](t: Table[A, B], key: A): B = getOrDefaultImpl(t, key) + iterator allValues*[A, B](t: Table[A, B]; key: A): B = ## iterates over any value in the table `t` that belongs to the given `key`. var h: Hash = hash(key) and high(t.data) @@ -305,6 +305,8 @@ proc mget*[A, B](t: TableRef[A, B], key: A): var B {.deprecated.} = ## Use ```[]``` instead. t[][key] +proc getOrDefault*[A, B](t: TableRef[A, B], key: A): B = getOrDefault(t[], key) + proc mgetOrPut*[A, B](t: TableRef[A, B], key: A, val: B): var B = ## retrieves value at ``t[key]`` or puts ``val`` if not present, either way ## returning a value which can be modified. @@ -416,20 +418,6 @@ proc rawGetDeep[A, B](t: OrderedTable[A, B], key: A, hc: var Hash): int {.inline proc rawGet[A, B](t: OrderedTable[A, B], key: A, hc: var Hash): int = rawGetImpl() -proc `[]`*[A, B](t: OrderedTable[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 hc: Hash - var index = rawGet(t, key, hc) - if index >= 0: result = t.data[index].val - else: - when compiles($key): - raise newException(KeyError, "key not found: " & $key) - else: - raise newException(KeyError, "key not found") - proc `[]`*[A, B](t: OrderedTable[A, B], key: A): B = ## retrieves the value at ``t[key]``. If `key` is not in `t`, the ## ``KeyError`` exception is raised. One can check with ``hasKey`` whether @@ -438,11 +426,18 @@ proc `[]`*[A, B](t: OrderedTable[A, B], key: A): B = proc `[]`*[A, B](t: var OrderedTable[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 hc: Hash - var index = rawGet(t, key, hc) - if index >= 0: result = t.data[index].val - else: raise newException(KeyError, "key not found: " & $key) + ## If `key` is not in `t`, the ``KeyError`` exception is raised. + get(t, key) + +proc mget*[A, B](t: var OrderedTable[A, B], key: A): var B {.deprecated.} = + ## retrieves the value at ``t[key]``. The value can be modified. + ## If `key` is not in `t`, the ``KeyError`` exception is raised. + ## Use ```[]``` instead. + get(t, key) + +proc getOrDefault*[A, B](t: OrderedTable[A, B], key: A): B = + getOrDefaultImpl(t, key) + proc hasKey*[A, B](t: OrderedTable[A, B], key: A): bool = ## returns true iff `key` is in the table `t`. @@ -612,6 +607,9 @@ proc mget*[A, B](t: OrderedTableRef[A, B], key: A): var B {.deprecated.} = ## Use ```[]``` instead. result = t[][key] +proc getOrDefault*[A, B](t: OrderedTableRef[A, B], key: A): B = + getOrDefault(t[], key) + proc mgetOrPut*[A, B](t: OrderedTableRef[A, B], key: A, val: B): var B = ## retrieves value at ``t[key]`` or puts ``val`` if not present, either way ## returning a value which can be modified. @@ -711,7 +709,7 @@ proc rawGet[A](t: CountTable[A], key: A): int = h = nextTry(h, high(t.data)) result = -1 - h # < 0 => MISSING; insert idx = -1 - result -template get[A](t: CountTable[A], key: A): int {.immediate.} = +template ctget(t, key: untyped): untyped {.immediate.} = var index = rawGet(t, key) if index >= 0: result = t.data[index].val else: @@ -724,18 +722,22 @@ proc `[]`*[A](t: CountTable[A], key: A): int = ## retrieves the value at ``t[key]``. If `key` is not in `t`, ## the ``KeyError`` exception is raised. One can check with ``hasKey`` ## whether the key exists. - get(t, key) + ctget(t, key) proc `[]`*[A](t: var CountTable[A], key: A): var int = ## retrieves the value at ``t[key]``. The value can be modified. ## If `key` is not in `t`, the ``KeyError`` exception is raised. - get(t, key) + ctget(t, key) proc mget*[A](t: var CountTable[A], key: A): var int {.deprecated.} = ## retrieves the value at ``t[key]``. The value can be modified. ## If `key` is not in `t`, the ``KeyError`` exception is raised. ## Use ```[]``` instead. - get(t, key) + ctget(t, key) + +proc getOrDefault*[A](t: CountTable[A], key: A): int = + var index = rawGet(t, key) + if index >= 0: result = t.data[index].val proc hasKey*[A](t: CountTable[A], key: A): bool = ## returns true iff `key` is in the table `t`. @@ -882,6 +884,9 @@ proc mget*[A](t: CountTableRef[A], key: A): var int {.deprecated.} = ## Use ```[]``` instead. result = t[][key] +proc getOrDefault*[A](t: CountTableRef[A], key: A): int = + getOrDefaultImpl(t, key) + proc hasKey*[A](t: CountTableRef[A], key: A): bool = ## returns true iff `key` is in the table `t`. result = t[].hasKey(key) diff --git a/lib/pure/strtabs.nim b/lib/pure/strtabs.nim index 2127c7f10c..e477c6f071 100644 --- a/lib/pure/strtabs.nim +++ b/lib/pure/strtabs.nim @@ -122,6 +122,11 @@ proc mget*(t: StringTableRef, key: string): var string {.deprecated.} = ## ``KeyError`` exception is raised. Use ```[]``` instead. get(t, key) +proc getOrDefault*(t: StringTableRef; key: string): string = + var index = rawGet(t, key) + if index >= 0: result = t.data[index].val + else: result = "" + proc hasKey*(t: StringTableRef, key: string): bool {.rtl, extern: "nst$1".} = ## returns true iff `key` is in the table `t`. result = rawGet(t, key) >= 0 diff --git a/lib/pure/xmltree.nim b/lib/pure/xmltree.nim index c60da0239c..4a506546bb 100644 --- a/lib/pure/xmltree.nim +++ b/lib/pure/xmltree.nim @@ -144,7 +144,7 @@ proc `[]`* (n: var XmlNode, i: int): var XmlNode {.inline.} = assert n.k == xnElement result = n.s[i] -proc mget* (n: var XmlNode, i: int): var XmlNode {.inline, deprecated.} = +proc mget*(n: var XmlNode, i: int): var XmlNode {.inline, deprecated.} = ## returns the `i`'th child of `n` so that it can be modified. Use ```[]``` ## instead. n[i] From 4548c1aa9b574ccecf0285f695bf2c26bfe58868 Mon Sep 17 00:00:00 2001 From: rbmz Date: Tue, 13 Oct 2015 01:10:25 -0300 Subject: [PATCH 30/32] added all/any/allIt/anyIt with tests and inline documentation Signed-off-by: rbmz --- lib/pure/collections/sequtils.nim | 93 +++++++++++++++++++++++++++++++ 1 file changed, 93 insertions(+) diff --git a/lib/pure/collections/sequtils.nim b/lib/pure/collections/sequtils.nim index fd012e811d..71babe93b8 100644 --- a/lib/pure/collections/sequtils.nim +++ b/lib/pure/collections/sequtils.nim @@ -397,6 +397,67 @@ template keepItIf*(varSeq: seq, pred: expr) = inc(pos) setLen(varSeq, pos) +proc all*[T](seq1: seq[T], pred: proc(item: T): bool {.closure.}): bool = + ## Iterates through a sequence and checks if every item fulfills the + ## predicate. + ## + ## Example: + ## + ## .. code-block:: + ## let numbers = @[1, 4, 5, 8, 9, 7, 4] + ## assert all(numbers, proc (x: int): bool = return x < 10) == true + ## assert all(numbers, proc (x: int): bool = return x < 9) == false + for i in seq1: + if not pred(i): + return false + return true + +template allIt*(seq1, pred: expr): bool {.immediate.} = + ## Checks if every item fulfills the predicate. + ## + ## Example: + ## + ## .. code-block:: + ## let numbers = @[1, 4, 5, 8, 9, 7, 4] + ## assert allIt(numbers, it < 10) == true + ## assert allIt(numbers, it < 9) == false + var result {.gensym.} = true + for it {.inject.} in items(seq1): + if not pred: + result = false + break + result + +proc any*[T](seq1: seq[T], pred: proc(item: T): bool {.closure.}): bool = + ## Iterates through a sequence and checks if some item fulfills the + ## predicate. + ## + ## Example: + ## + ## .. code-block:: + ## let numbers = @[1, 4, 5, 8, 9, 7, 4] + ## assert any(numbers, proc (x: int): bool = return x > 8) == true + ## assert any(numbers, proc (x: int): bool = return x > 9) == false + for i in seq1: + if pred(i): + return true + return false + +template anyIt*(seq1, pred: expr): bool {.immediate.} = + ## Checks if some item fulfills the predicate. + ## + ## Example: + ## + ## .. code-block:: + ## let numbers = @[1, 4, 5, 8, 9, 7, 4] + ## assert anyIt(numbers, it > 8) == true + ## assert anyIt(numbers, it > 9) == false + var result {.gensym.} = false + for it {.inject.} in items(seq1): + if pred: + result = true + break + result template toSeq*(iter: expr): expr {.immediate.} = ## Transforms any iterator into a sequence. @@ -642,6 +703,38 @@ when isMainModule: keepItIf(candidates, it.len == 3 and it[0] == 'b') assert candidates == @["bar", "baz"] + block: # any + let + numbers = @[1, 4, 5, 8, 9, 7, 4] + len0seq : seq[int] = @[] + assert any(numbers, proc (x: int): bool = return x > 8) == true + assert any(numbers, proc (x: int): bool = return x > 9) == false + assert any(len0seq, proc (x: int): bool = return true) == false + + block: # anyIt + let + numbers = @[1, 4, 5, 8, 9, 7, 4] + len0seq : seq[int] = @[] + assert anyIt(numbers, it > 8) == true + assert anyIt(numbers, it > 9) == false + assert anyIt(len0seq, true) == false + + block: # all + let + numbers = @[1, 4, 5, 8, 9, 7, 4] + len0seq : seq[int] = @[] + assert all(numbers, proc (x: int): bool = return x < 10) == true + assert all(numbers, proc (x: int): bool = return x < 9) == false + assert all(len0seq, proc (x: int): bool = return false) == true + + block: # allIt + let + numbers = @[1, 4, 5, 8, 9, 7, 4] + len0seq : seq[int] = @[] + assert allIt(numbers, it < 10) == true + assert allIt(numbers, it < 9) == false + assert allIt(len0seq, false) == true + block: # toSeq test let numeric = @[1, 2, 3, 4, 5, 6, 7, 8, 9] From 8be9e4640320ddc4c11cf433fb6e232a743a9700 Mon Sep 17 00:00:00 2001 From: Araq Date: Tue, 13 Oct 2015 14:10:33 +0200 Subject: [PATCH 31/32] udpated the compiler and tester to use getOrDefault --- compiler/docgen.nim | 2 +- compiler/rodread.nim | 6 +++--- lib/impure/re.nim | 4 +++- lib/packages/docutils/rstgen.nim | 23 +++++++++++++---------- lib/pure/asynchttpserver.nim | 15 +++++++++------ lib/pure/cgi.nim | 2 +- lib/pure/collections/critbits.nim | 7 +++++-- lib/pure/collections/sets.nim | 4 ++-- lib/pure/collections/tables.nim | 18 ++++++++++-------- lib/pure/marshal.nim | 2 +- lib/pure/mimetypes.nim | 2 +- lib/pure/scgi.nim | 11 ++++++----- lib/pure/strtabs.nim | 4 ++-- lib/pure/xmltree.nim | 2 +- lib/system/inclrtl.nim | 5 +++++ tests/testament/backend.nim | 6 +++--- tests/testament/htmlgen.nim | 2 +- tests/testament/tester.nim | 10 +++++----- web/news.txt | 16 ++++++++++------ 19 files changed, 82 insertions(+), 59 deletions(-) diff --git a/compiler/docgen.nim b/compiler/docgen.nim index 4b52b1c92c..8ae32492aa 100644 --- a/compiler/docgen.nim +++ b/compiler/docgen.nim @@ -75,7 +75,7 @@ proc newDocumentor*(filename: string, config: StringTableRef): PDoc = ga('send', 'pageview'); - """ % [config["doc.googleAnalytics"]] + """ % [config.getOrDefault"doc.googleAnalytics"] else: result.analytics = "" diff --git a/compiler/rodread.nim b/compiler/rodread.nim index e4530c2cc9..2a85c89759 100644 --- a/compiler/rodread.nim +++ b/compiler/rodread.nim @@ -372,7 +372,7 @@ proc decodeSym(r: PRodReader, info: TLineInfo): PSym = else: internalError(info, "decodeSym: no ident") #echo "decoding: {", ident.s - result = r.syms[id] + result = r.syms.getOrDefault(id) if result == nil: new(result) result.id = id @@ -491,7 +491,7 @@ proc processCompilerProcs(r: PRodReader, module: PSym) = inc(r.pos) var key = decodeVInt(r.s, r.pos) inc(r.pos) # #10 - var s = r.syms[key] + var s = r.syms.getOrDefault(key) if s == nil: s = newStub(r, w, key) s.owner = module @@ -737,7 +737,7 @@ proc getReader(moduleId: int): PRodReader = return nil proc rrGetSym(r: PRodReader, id: int, info: TLineInfo): PSym = - result = r.syms[id] + result = r.syms.getOrDefault(id) if result == nil: # load the symbol: var d = iiTableGet(r.index.tab, id) diff --git a/lib/impure/re.nim b/lib/impure/re.nim index 30081bb192..60bb6c77f1 100644 --- a/lib/impure/re.nim +++ b/lib/impure/re.nim @@ -28,6 +28,8 @@ import pcre, strutils, rtarrays +{.deprecated.} + const MaxSubpatterns* = 20 ## defines the maximum number of subpatterns that can be captured. @@ -46,7 +48,7 @@ type h: ptr Pcre e: ptr ExtraData - Regex* {.deprecated.} = ref RegexDesc ## a compiled regular expression + Regex* = ref RegexDesc ## a compiled regular expression RegexError* = object of ValueError ## is raised if the pattern is no valid regular expression. diff --git a/lib/packages/docutils/rstgen.nim b/lib/packages/docutils/rstgen.nim index 83e1b8b9f5..4a0304a7cc 100644 --- a/lib/packages/docutils/rstgen.nim +++ b/lib/packages/docutils/rstgen.nim @@ -139,7 +139,7 @@ proc initRstGenerator*(g: var RstGenerator, target: OutputTarget, g.seenIndexTerms = initTable[string, int]() g.msgHandler = msgHandler - let s = config["split.item.toc"] + let s = config.getOrDefault"split.item.toc" if s != "": g.splitAfter = parseInt(s) for i in low(g.meta)..high(g.meta): g.meta[i] = "" @@ -341,10 +341,10 @@ proc renderIndexTerm*(d: PDoc, n: PRstNode, result: var string) = ## previously appeared to give a different identifier value for each. let refname = n.rstnodeToRefname if d.seenIndexTerms.hasKey(refname): - d.seenIndexTerms[refname] = d.seenIndexTerms[refname] + 1 + d.seenIndexTerms[refname] = d.seenIndexTerms.getOrDefault(refname) + 1 else: d.seenIndexTerms[refname] = 1 - let id = refname & '_' & $d.seenIndexTerms[refname] + let id = refname & '_' & $d.seenIndexTerms.getOrDefault(refname) var term = "" renderAux(d, n, term) @@ -518,7 +518,7 @@ proc generateDocumentationIndex(docs: IndexedDocs): string = sort(titles, cmp) for title in titles: - let tocList = generateDocumentationTOC(docs[title]) + let tocList = generateDocumentationTOC(docs.getOrDefault(title)) result.add("\n") @@ -786,7 +786,8 @@ proc renderSmiley(d: PDoc, n: PRstNode, result: var string) = dispA(d.target, result, """""", - "\\includegraphics{$1}", [d.config["doc.smiley_format"] % n.text]) + "\\includegraphics{$1}", + [d.config.getOrDefault"doc.smiley_format" % n.text]) proc parseCodeBlockField(d: PDoc, n: PRstNode, params: var CodeBlockParams) = ## Parses useful fields which can appear before a code block. @@ -844,8 +845,8 @@ proc buildLinesHTMLTable(d: PDoc; params: CodeBlockParams, code: string): inc d.listingCounter let id = $d.listingCounter if not params.numberLines: - result = (d.config["doc.listing_start"] % id, - d.config["doc.listing_end"] % id) + result = (d.config.getOrDefault"doc.listing_start" % id, + d.config.getOrDefault"doc.listing_end" % id) return var codeLines = 1 + code.strip.countLines @@ -856,9 +857,11 @@ proc buildLinesHTMLTable(d: PDoc; params: CodeBlockParams, code: string): result.beginTable.add($line & "\n") line.inc codeLines.dec - result.beginTable.add("" & (d.config["doc.listing_start"] % id)) - result.endTable = (d.config["doc.listing_end"] % id) & - "" & (d.config["doc.listing_button"] % id) + result.beginTable.add("" & ( + d.config.getOrDefault"doc.listing_start" % id)) + result.endTable = (d.config.getOrDefault"doc.listing_end" % id) & + "" & ( + d.config.getOrDefault"doc.listing_button" % id) proc renderCodeBlock(d: PDoc, n: PRstNode, result: var string) = ## Renders a code block, appending it to `result`. diff --git a/lib/pure/asynchttpserver.nim b/lib/pure/asynchttpserver.nim index 5d74896bf5..590b52c1a2 100644 --- a/lib/pure/asynchttpserver.nim +++ b/lib/pure/asynchttpserver.nim @@ -212,7 +212,7 @@ proc processClient(client: AsyncSocket, address: string, if request.reqMethod == "post": # Check for Expect header if request.headers.hasKey("Expect"): - if request.headers["Expect"].toLower == "100-continue": + if request.headers.getOrDefault("Expect").toLower == "100-continue": await client.sendStatus("100 Continue") else: await client.sendStatus("417 Expectation Failed") @@ -221,7 +221,8 @@ proc processClient(client: AsyncSocket, address: string, # - Check for Content-length header if request.headers.hasKey("Content-Length"): var contentLength = 0 - if parseInt(request.headers["Content-Length"], contentLength) == 0: + if parseInt(request.headers.getOrDefault("Content-Length"), + contentLength) == 0: await request.respond(Http400, "Bad Request. Invalid Content-Length.") continue else: @@ -232,16 +233,18 @@ proc processClient(client: AsyncSocket, address: string, continue case request.reqMethod - of "get", "post", "head", "put", "delete", "trace", "options", "connect", "patch": + of "get", "post", "head", "put", "delete", "trace", "options", + "connect", "patch": await callback(request) else: - await request.respond(Http400, "Invalid request method. Got: " & request.reqMethod) + await request.respond(Http400, "Invalid request method. Got: " & + request.reqMethod) # Persistent connections if (request.protocol == HttpVer11 and - request.headers["connection"].normalize != "close") or + request.headers.getOrDefault("connection").normalize != "close") or (request.protocol == HttpVer10 and - request.headers["connection"].normalize == "keep-alive"): + request.headers.getOrDefault("connection").normalize == "keep-alive"): # In HTTP 1.1 we assume that connection is persistent. Unless connection # header states otherwise. # In HTTP 1.0 we assume that the connection should not be persistent. diff --git a/lib/pure/cgi.nim b/lib/pure/cgi.nim index cfd768f91a..200a4adf18 100644 --- a/lib/pure/cgi.nim +++ b/lib/pure/cgi.nim @@ -387,7 +387,7 @@ var proc getCookie*(name: string): TaintedString = ## Gets a cookie. If no cookie of `name` exists, "" is returned. if gcookies == nil: gcookies = parseCookies(getHttpCookie()) - result = TaintedString(gcookies[name]) + result = TaintedString(gcookies.getOrDefault(name)) proc existsCookie*(name: string): bool = ## Checks if a cookie of `name` exists. diff --git a/lib/pure/collections/critbits.nim b/lib/pure/collections/critbits.nim index bd7e083bec..8c507d4fbf 100644 --- a/lib/pure/collections/critbits.nim +++ b/lib/pure/collections/critbits.nim @@ -11,6 +11,8 @@ ## container for a set or a mapping of strings. Based on the excellent paper ## by Adam Langley. +include "system/inclrtl" + type NodeObj[T] = object {.acyclic.} byte: int ## byte index of the difference @@ -149,13 +151,14 @@ template get[T](c: CritBitTree[T], key: string): T {.immediate.} = else: raise newException(KeyError, "key not found") -proc `[]`*[T](c: CritBitTree[T], key: string): T {.inline.} = +proc `[]`*[T](c: CritBitTree[T], key: string): T {.inline, deprecatedGet.} = ## retrieves the value at ``c[key]``. If `key` is not in `t`, the ## ``KeyError`` exception is raised. One can check with ``hasKey`` whether ## the key exists. get(c, key) -proc `[]`*[T](c: var CritBitTree[T], key: string): var T {.inline.} = +proc `[]`*[T](c: var CritBitTree[T], key: string): var T {.inline, + deprecatedGet.} = ## retrieves the value at ``c[key]``. The value can be modified. ## If `key` is not in `t`, the ``KeyError`` exception is raised. get(c, key) diff --git a/lib/pure/collections/sets.nim b/lib/pure/collections/sets.nim index 2195a2442c..abe9cf85ef 100644 --- a/lib/pure/collections/sets.nim +++ b/lib/pure/collections/sets.nim @@ -156,7 +156,7 @@ proc rawGet[A](s: HashSet[A], key: A, hc: var Hash): int {.inline.} = proc `[]`*[A](s: var HashSet[A], key: A): var A = ## returns the element that is actually stored in 's' which has the same - ## value as 'key' or raises the ``EInvalidKey`` exception. This is useful + ## value as 'key' or raises the ``KeyError`` exception. This is useful ## when one overloaded 'hash' and '==' but still needs reference semantics ## for sharing. assert s.isValid, "The set needs to be initialized." @@ -167,7 +167,7 @@ proc `[]`*[A](s: var HashSet[A], key: A): var A = proc mget*[A](s: var HashSet[A], key: A): var A {.deprecated.} = ## returns the element that is actually stored in 's' which has the same - ## value as 'key' or raises the ``EInvalidKey`` exception. This is useful + ## value as 'key' or raises the ``KeyError`` exception. This is useful ## when one overloaded 'hash' and '==' but still needs reference semantics ## for sharing. Use ```[]``` instead. s[key] diff --git a/lib/pure/collections/tables.nim b/lib/pure/collections/tables.nim index 37d52b6de7..329b2a1cb5 100644 --- a/lib/pure/collections/tables.nim +++ b/lib/pure/collections/tables.nim @@ -68,6 +68,8 @@ import hashes, math +include "system/inclrtl" + type KeyValuePair[A, B] = tuple[hcode: Hash, key: A, val: B] KeyValuePairSeq[A, B] = seq[KeyValuePair[A, B]] @@ -115,13 +117,13 @@ template getOrDefaultImpl(t, key): untyped {.immediate.} = var index = rawGet(t, key, hc) if index >= 0: result = t.data[index].val -proc `[]`*[A, B](t: Table[A, B], key: A): B = +proc `[]`*[A, B](t: Table[A, B], key: A): B {.deprecatedGet.} = ## retrieves the value at ``t[key]``. If `key` is not in `t`, the ## ``KeyError`` exception is raised. One can check with ``hasKey`` whether ## the key exists. get(t, key) -proc `[]`*[A, B](t: var Table[A, B], key: A): var B = +proc `[]`*[A, B](t: var Table[A, B], key: A): var B {.deprecatedGet.} = ## retrieves the value at ``t[key]``. The value can be modified. ## If `key` is not in `t`, the ``KeyError`` exception is raised. get(t, key) @@ -293,7 +295,7 @@ iterator mvalues*[A, B](t: TableRef[A, B]): var B = for h in 0..high(t.data): if isFilled(t.data[h].hcode): yield t.data[h].val -proc `[]`*[A, B](t: TableRef[A, B], key: A): var B = +proc `[]`*[A, B](t: TableRef[A, B], key: A): var B {.deprecatedGet.} = ## retrieves the value at ``t[key]``. If `key` is not in `t`, the ## ``KeyError`` exception is raised. One can check with ``hasKey`` whether ## the key exists. @@ -418,13 +420,13 @@ proc rawGetDeep[A, B](t: OrderedTable[A, B], key: A, hc: var Hash): int {.inline proc rawGet[A, B](t: OrderedTable[A, B], key: A, hc: var Hash): int = rawGetImpl() -proc `[]`*[A, B](t: OrderedTable[A, B], key: A): B = +proc `[]`*[A, B](t: OrderedTable[A, B], key: A): B {.deprecatedGet.} = ## retrieves the value at ``t[key]``. If `key` is not in `t`, the ## ``KeyError`` exception is raised. One can check with ``hasKey`` whether ## the key exists. get(t, key) -proc `[]`*[A, B](t: var OrderedTable[A, B], key: A): var B = +proc `[]`*[A, B](t: var OrderedTable[A, B], key: A): var B{.deprecatedGet.} = ## retrieves the value at ``t[key]``. The value can be modified. ## If `key` is not in `t`, the ``KeyError`` exception is raised. get(t, key) @@ -718,13 +720,13 @@ template ctget(t, key: untyped): untyped {.immediate.} = else: raise newException(KeyError, "key not found") -proc `[]`*[A](t: CountTable[A], key: A): int = +proc `[]`*[A](t: CountTable[A], key: A): int {.deprecatedGet.} = ## retrieves the value at ``t[key]``. If `key` is not in `t`, ## the ``KeyError`` exception is raised. One can check with ``hasKey`` ## whether the key exists. ctget(t, key) -proc `[]`*[A](t: var CountTable[A], key: A): var int = +proc `[]`*[A](t: var CountTable[A], key: A): var int {.deprecatedGet.} = ## retrieves the value at ``t[key]``. The value can be modified. ## If `key` is not in `t`, the ``KeyError`` exception is raised. ctget(t, key) @@ -873,7 +875,7 @@ iterator mvalues*[A](t: CountTableRef[A]): var int = for h in 0..high(t.data): if t.data[h].val != 0: yield t.data[h].val -proc `[]`*[A](t: CountTableRef[A], key: A): var int = +proc `[]`*[A](t: CountTableRef[A], key: A): var int {.deprecatedGet.} = ## retrieves the value at ``t[key]``. The value can be modified. ## If `key` is not in `t`, the ``KeyError`` exception is raised. result = t[][key] diff --git a/lib/pure/marshal.nim b/lib/pure/marshal.nim index 173cd1e811..134581a066 100644 --- a/lib/pure/marshal.nim +++ b/lib/pure/marshal.nim @@ -176,7 +176,7 @@ proc loadAny(p: var JsonParser, a: Any, t: var Table[BiggestInt, pointer]) = setPointer(a, nil) next(p) of jsonInt: - setPointer(a, t[p.getInt]) + setPointer(a, t.getOrDefault(p.getInt)) next(p) of jsonArrayStart: next(p) diff --git a/lib/pure/mimetypes.nim b/lib/pure/mimetypes.nim index 642419e644..1e315afb4a 100644 --- a/lib/pure/mimetypes.nim +++ b/lib/pure/mimetypes.nim @@ -499,7 +499,7 @@ proc newMimetypes*(): MimeDB = proc getMimetype*(mimedb: MimeDB, ext: string, default = "text/plain"): string = ## Gets mimetype which corresponds to ``ext``. Returns ``default`` if ``ext`` ## could not be found. - result = mimedb.mimes[ext] + result = mimedb.mimes.getOrDefault(ext) if result == "": return default diff --git a/lib/pure/scgi.nim b/lib/pure/scgi.nim index 1d54b45917..711e4a8975 100644 --- a/lib/pure/scgi.nim +++ b/lib/pure/scgi.nim @@ -145,8 +145,8 @@ proc next*(s: var ScgiState, timeout: int = -1): bool = L = L * 10 + ord(d) - ord('0') recvBuffer(s, L+1) s.headers = parseHeaders(s.input, L) - if s.headers["SCGI"] != "1": raiseScgiError("SCGI Version 1 expected") - L = parseInt(s.headers["CONTENT_LENGTH"]) + if s.headers.getOrDefault("SCGI") != "1": raiseScgiError("SCGI Version 1 expected") + L = parseInt(s.headers.getOrDefault("CONTENT_LENGTH")) recvBuffer(s, L) return true @@ -221,10 +221,10 @@ proc handleClientRead(client: AsyncClient, s: AsyncScgiState) = case ret of ReadFullLine: client.headers = parseHeaders(client.input, client.input.len-1) - if client.headers["SCGI"] != "1": raiseScgiError("SCGI Version 1 expected") + if client.headers.getOrDefault("SCGI") != "1": raiseScgiError("SCGI Version 1 expected") client.input = "" # For next part - let contentLen = parseInt(client.headers["CONTENT_LENGTH"]) + let contentLen = parseInt(client.headers.getOrDefault("CONTENT_LENGTH")) if contentLen > 0: client.mode = ClientReadContent else: @@ -232,7 +232,8 @@ proc handleClientRead(client: AsyncClient, s: AsyncScgiState) = checkCloseSocket(client) of ReadPartialLine, ReadDisconnected, ReadNone: return of ClientReadContent: - let L = parseInt(client.headers["CONTENT_LENGTH"])-client.input.len + let L = parseInt(client.headers.getOrDefault("CONTENT_LENGTH")) - + client.input.len if L > 0: let ret = recvBufferAsync(client, L) case ret diff --git a/lib/pure/strtabs.nim b/lib/pure/strtabs.nim index e477c6f071..1c761cd923 100644 --- a/lib/pure/strtabs.nim +++ b/lib/pure/strtabs.nim @@ -111,7 +111,7 @@ template get(t: StringTableRef, key: string): stmt {.immediate.} = raise newException(KeyError, "key not found") proc `[]`*(t: StringTableRef, key: string): var string {. - rtl, extern: "nstTake".} = + rtl, extern: "nstTake", deprecatedGet.} = ## retrieves the location at ``t[key]``. If `key` is not in `t`, the ## ``KeyError`` exception is raised. One can check with ``hasKey`` whether ## the key exists. @@ -162,7 +162,7 @@ proc raiseFormatException(s: string) = raise e proc getValue(t: StringTableRef, flags: set[FormatFlag], key: string): string = - if hasKey(t, key): return t[key] + if hasKey(t, key): return t.getOrDefault(key) # hm difficult: assume safety in taint mode here. XXX This is dangerous! if useEnvironment in flags: result = os.getEnv(key).string else: result = "" diff --git a/lib/pure/xmltree.nim b/lib/pure/xmltree.nim index 4a506546bb..a9fc8998a8 100644 --- a/lib/pure/xmltree.nim +++ b/lib/pure/xmltree.nim @@ -342,7 +342,7 @@ proc attr*(n: XmlNode, name: string): string = ## Returns "" on failure. assert n.kind == xnElement if n.attrs == nil: return "" - return n.attrs[name] + return n.attrs.getOrDefault(name) proc findAll*(n: XmlNode, tag: string, result: var seq[XmlNode]) = ## Iterates over all the children of `n` returning those matching `tag`. diff --git a/lib/system/inclrtl.nim b/lib/system/inclrtl.nim index 201a99ca75..3caeefcbcd 100644 --- a/lib/system/inclrtl.nim +++ b/lib/system/inclrtl.nim @@ -51,3 +51,8 @@ when defined(nimlocks): {.pragma: benign, gcsafe, locks: 0.} else: {.pragma: benign, gcsafe.} + +when defined(nimTableGet): + {.pragma: deprecatedGet, deprecated.} +else: + {.pragma: deprecatedGet.} diff --git a/tests/testament/backend.nim b/tests/testament/backend.nim index e2e2e2dd5c..9ec0c09739 100644 --- a/tests/testament/backend.nim +++ b/tests/testament/backend.nim @@ -8,7 +8,7 @@ import strutils, db_sqlite, os, osproc -var db: TDbConn +var db: DbConn proc createDb() = db.exec(sql""" @@ -61,7 +61,7 @@ var proc `()`(cmd: string{lit}): string = cmd.execProcess.string.strip -proc getMachine*(db: TDbConn): MachineId = +proc getMachine*(db: DbConn): MachineId = var name = "hostname"() if name.len == 0: name = when defined(posix): getenv"HOSTNAME".string @@ -76,7 +76,7 @@ proc getMachine*(db: TDbConn): MachineId = result = db.insertId(sql"insert into Machine(name, os, cpu) values (?,?,?)", name, system.hostOS, system.hostCPU).MachineId -proc getCommit(db: TDbConn): CommitId = +proc getCommit(db: DbConn): CommitId = const commLen = "commit ".len let hash = "git log -n 1"()[commLen..commLen+10] let branch = "git symbolic-ref --short HEAD"() diff --git a/tests/testament/htmlgen.nim b/tests/testament/htmlgen.nim index 98ccf11703..15960f09a3 100644 --- a/tests/testament/htmlgen.nim +++ b/tests/testament/htmlgen.nim @@ -109,7 +109,7 @@ div.tabContent.hide { display: none; } proc td(s: string): string = result = "" & s.substr(0, 200).xmlEncode & "" -proc getCommit(db: TDbConn, c: int): string = +proc getCommit(db: DbConn, c: int): string = var commit = c for thisCommit in db.rows(sql"select id from [Commit] order by id desc"): if commit == 0: result = thisCommit[0] diff --git a/tests/testament/tester.nim b/tests/testament/tester.nim index 636093a7f5..ae8735ebef 100644 --- a/tests/testament/tester.nim +++ b/tests/testament/tester.nim @@ -64,7 +64,7 @@ proc callCompiler(cmdTemplate, filename, options: string, let c = parseCmdLine(cmdTemplate % ["target", targetToCmd[target], "options", options, "file", filename.quoteShell]) var p = startProcess(command=c[0], args=c[1.. ^1], - options={poStdErrToStdOut, poUseShell}) + options={poStdErrToStdOut, poUsePath}) let outp = p.outputStream var suc = "" var err = "" @@ -195,7 +195,7 @@ proc generatedFile(path, name: string, target: TTarget): string = proc codegenCheck(test: TTest, check: string, given: var TSpec) = try: - let (path, name, ext2) = test.name.splitFile + let (path, name, _) = test.name.splitFile let genFile = generatedFile(path, name, test.target) let contents = readFile(genFile).string if check[0] == '\\': @@ -287,7 +287,7 @@ proc testSpec(r: var TResults, test: TTest) = let isJsTarget = test.target == targetJS var exeFile: string if isJsTarget: - let (dir, file, ext) = splitFile(tname) + let (dir, file, _) = splitFile(tname) exeFile = dir / "nimcache" / file & ".js" # *TODO* hardcoded "nimcache" else: exeFile = changeFileExt(tname, ExeExt) @@ -332,7 +332,7 @@ proc testSpec(r: var TResults, test: TTest) = proc testNoSpec(r: var TResults, test: TTest) = # does not extract the spec because the file is not supposed to have any - let tname = test.name.addFileExt(".nim") + #let tname = test.name.addFileExt(".nim") inc(r.total) let given = callCompiler(cmdTemplate, test.name, test.options, test.target) r.addResult(test, "", given.msg, given.err) @@ -348,7 +348,7 @@ proc testC(r: var TResults, test: TTest) = r.addResult(test, "", given.msg, given.err) elif test.action == actionRun: let exeFile = changeFileExt(test.name, ExeExt) - var (buf, exitCode) = execCmdEx(exeFile, options = {poStdErrToStdOut, poUseShell}) + var (_, exitCode) = execCmdEx(exeFile, options = {poStdErrToStdOut, poUsePath}) if exitCode != 0: given.err = reExitCodesDiffer if given.err == reSuccess: inc(r.passed) diff --git a/web/news.txt b/web/news.txt index 45bbe8c441..89e075b6c5 100644 --- a/web/news.txt +++ b/web/news.txt @@ -8,7 +8,11 @@ News Changes affecting backwards compatibility ----------------------------------------- - + - ``tables.[]``, ``strtabs.[]``, ``critbits.[]`` **now raise** + the ``KeyError`` **exception when the key does not exist**! Use the + new ``getOrDefault`` instead to get the old behaviour. Compile all your + code with ``-d:nimTableGet`` to get a listing of where your code + uses ``[]``! - The ``rawsockets`` module has been renamed to ``nativesockets`` to avoid confusion with TCP/IP raw sockets, so ``newNativeSocket`` should be used instead of ``newRawSocket``. @@ -68,10 +72,10 @@ News * ``libeay32.dll``: Split into ``libeay32.dll`` and ``libeay64.dll``. Compile with ``-d:nimOldDLLs`` to make the stdlib use the old DLL names. - - Nim VM now treats objects as nkObjConstr nodes, and not nkPar nodes as it - was previously. Macros that generate nkPar nodes when object is expected are - likely to break. Macros that expect nkPar nodes to which objects are passed - are likely to break as well. + - Nim VM now treats objects as ``nkObjConstr`` nodes, and not ``nkPar`` nodes + as it was previously. Macros that generate ``nkPar`` nodes when object is + expected are likely to break. Macros that expect ``nkPar`` nodes to which + objects are passed are likely to break as well. - Base methods now need to be annotated with the ``base`` pragma. This makes multi methods less error-prone to use with the effect system. - Nim's parser directive ``#!`` is now ``#?`` in order to produce no conflicts @@ -86,7 +90,7 @@ News echo f(0, "abc") - The ``ftpclient`` module is now deprecated in favour of the - ``asyncdispatch`` module. + ``asyncftpclient`` module. - In sequtils.nim renamed ``repeat`` function to ``cycle`` (concatenating a sequence by itself the given times), and also introduced ``repeat``, which repeats an element the given times. From 7f4f37eaa20ea8aa5cf8c34e497aaa8245c590b3 Mon Sep 17 00:00:00 2001 From: Araq Date: Tue, 13 Oct 2015 16:31:30 +0200 Subject: [PATCH 32/32] fixes tunittest crash --- compiler/transf.nim | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/compiler/transf.nim b/compiler/transf.nim index 0ea9f7d80d..92319ac193 100644 --- a/compiler/transf.nim +++ b/compiler/transf.nim @@ -825,11 +825,13 @@ proc flattenStmts(n: PNode) = var goOn = true while goOn: goOn = false - for i in 0..