diff options
-rwxr-xr-x | compiler/ccgexprs.nim | 2 | ||||
-rw-r--r-- | compiler/lambdalifting.nim | 2 | ||||
-rwxr-xr-x | compiler/semexprs.nim | 4 | ||||
-rwxr-xr-x | compiler/semstmts.nim | 38 | ||||
-rwxr-xr-x | doc/manual.txt | 58 | ||||
-rwxr-xr-x | doc/tut1.txt | 41 | ||||
-rwxr-xr-x | doc/tut2.txt | 16 | ||||
-rwxr-xr-x | examples/maximum.nim | 2 | ||||
-rw-r--r-- | lib/pure/collections/sequtils.nim | 4 | ||||
-rw-r--r-- | lib/pure/ftpclient.nim | 2 | ||||
-rw-r--r-- | lib/pure/irc.nim | 21 | ||||
-rwxr-xr-x | lib/pure/os.nim | 2 | ||||
-rwxr-xr-x | lib/system.nim | 47 | ||||
-rw-r--r-- | tests/compile/tclosure4.nim | 4 | ||||
-rw-r--r-- | tests/compile/tclosurebug2.nim | 194 | ||||
-rw-r--r-- | tests/compile/tnamedparamanonproc.nim | 14 | ||||
-rwxr-xr-x | tests/compile/toverprc.nim | 2 | ||||
-rw-r--r-- | tests/run/tdomulttest.nim | 1 | ||||
-rw-r--r-- | tests/run/tmultim6.nim | 2 | ||||
-rwxr-xr-x | todo.txt | 4 | ||||
-rwxr-xr-x | web/index.txt | 2 |
21 files changed, 396 insertions, 66 deletions
diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index 26144c152..7781040d9 100755 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -1,7 +1,7 @@ # # # The Nimrod Compiler -# (c) Copyright 2012 Andreas Rumpf +# (c) Copyright 2013 Andreas Rumpf # # See the file "copying.txt", included in this # distribution, for details about the copyright. diff --git a/compiler/lambdalifting.nim b/compiler/lambdalifting.nim index bca5b8c1d..0c3eea3be 100644 --- a/compiler/lambdalifting.nim +++ b/compiler/lambdalifting.nim @@ -1,7 +1,7 @@ # # # The Nimrod Compiler -# (c) Copyright 2012 Andreas Rumpf +# (c) Copyright 2013 Andreas Rumpf # # See the file "copying.txt", included in this # distribution, for details about the copyright. diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index d0fbcab6f..4b4cb5bdf 100755 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -1,7 +1,7 @@ # # # The Nimrod Compiler -# (c) Copyright 2012 Andreas Rumpf +# (c) Copyright 2013 Andreas Rumpf # # See the file "copying.txt", included in this # distribution, for details about the copyright. @@ -318,7 +318,7 @@ proc semIs(c: PContext, n: PNode): PNode = if not containsGenericType(t1): result = evalIsOp(n) proc semOpAux(c: PContext, n: PNode) = - let flags = {efDetermineType} + const flags = {efDetermineType} for i in countup(1, n.sonsLen- 1): var a = n.sons[i] if a.kind == nkExprEqExpr and sonsLen(a) == 2: diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index 363cff89a..e3956b918 100755 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -686,17 +686,18 @@ proc semLambda(c: PContext, n: PNode, flags: TExprFlags): PNode = if n.sons[pragmasPos].kind != nkEmpty: pragma(c, s, n.sons[pragmasPos], lambdaPragmas) s.options = gOptions - if n.sons[bodyPos].kind != nkEmpty: - if sfImportc in s.flags: + if n.sons[bodyPos].kind != nkEmpty: + if sfImportc in s.flags: LocalError(n.sons[bodyPos].info, errImplOfXNotAllowed, s.name.s) - if efDetermineType notin flags: - pushProcCon(c, s) - addResult(c, s.typ.sons[0], n.info, skProc) - let semBody = hloBody(c, semProcBody(c, n.sons[bodyPos])) - n.sons[bodyPos] = transformBody(c.module, semBody, s) - addResultNode(c, n) - popProcCon(c) - sideEffectsCheck(c, s) + #if efDetermineType notin flags: + # XXX not good enough; see tnamedparamanonproc.nim + pushProcCon(c, s) + addResult(c, s.typ.sons[0], n.info, skProc) + let semBody = hloBody(c, semProcBody(c, n.sons[bodyPos])) + n.sons[bodyPos] = transformBody(c.module, semBody, s) + addResultNode(c, n) + popProcCon(c) + sideEffectsCheck(c, s) else: LocalError(n.info, errImplOfXexpected, s.name.s) closeScope(c.tab) # close scope for parameters @@ -706,13 +707,16 @@ proc semLambda(c: PContext, n: PNode, flags: TExprFlags): PNode = proc activate(c: PContext, n: PNode) = # XXX: This proc is part of my plan for getting rid of # forward declarations. stay tuned. - case n.kind - of nkLambdaKinds: - discard semLambda(c, n, {}) - of nkCallKinds: - for i in 1 .. <n.len: activate(c, n[i]) - else: - nil + when false: + # well for now it breaks code ... I added the test case in main.nim of the + # compiler itself to break bootstrapping :P + case n.kind + of nkLambdaKinds: + discard semLambda(c, n, {}) + of nkCallKinds: + for i in 1 .. <n.len: activate(c, n[i]) + else: + nil proc instantiateDestructor*(c: PContext, typ: PType): bool diff --git a/doc/manual.txt b/doc/manual.txt index 2a79c0f99..1ac241b06 100755 --- a/doc/manual.txt +++ b/doc/manual.txt @@ -2232,7 +2232,6 @@ Type casts ---------- Example: - .. code-block:: nimrod cast[int](x) @@ -2243,11 +2242,27 @@ only needed for low-level programming and are inherently unsafe. The addr operator ----------------- -The `addr` operator returns the address of an l-value. If the -type of the location is ``T``, the `addr` operator result is -of the type ``ptr T``. Taking the address of an object that resides -on the stack is **unsafe**, as the pointer may live longer than the -object on the stack and can thus reference a non-existing object. +The `addr`:idx: operator returns the address of an l-value. If the type of the +location is ``T``, the `addr` operator result is of the type ``ptr T``. An +address is always an untraced reference. Taking the address of an object that +resides on the stack is **unsafe**, as the pointer may live longer than the +object on the stack and can thus reference a non-existing object. You can get +the address of variables, but you can't use it on variables declared through +``let`` statements: + +.. code-block:: nimrod + + let t1 = "Hello" + var + t2 = t1 + t3 : pointer = addr(t2) + echo repr(addr(t2)) + # --> ref 0x7fff6b71b670 --> 0x10bb81050"Hello" + echo cast[ptr string](t3)[] + # --> Hello + # The following line doesn't compile: + echo repr(addr(t1)) + # Error: expression has no address Procedures @@ -2682,16 +2697,14 @@ In contrast to that, a `closure iterator`:idx: can be passed around: invoke(count0) invoke(count2) - Closure iterators have other restrictions than inline iterators: -1.) ``yield`` in a closure iterator can not occur in a ``try`` statement. -2.) For now, a closure iterator cannot be evaluated at compile time. -3.) ``return`` is allowed in a closure iterator (but rarely useful). -4.) Since closure iterators can be used as a collaborative tasking - system, ``void`` is a valid return type for them. -5.) Both inline and closure iterators cannot be recursive. - +1. ``yield`` in a closure iterator can not occur in a ``try`` statement. +2. For now, a closure iterator cannot be evaluated at compile time. +3. ``return`` is allowed in a closure iterator (but rarely useful). +4. Since closure iterators can be used as a collaborative tasking + system, ``void`` is a valid return type for them. +5. Both inline and closure iterators cannot be recursive. Iterators that are neither marked ``{.closure.}`` nor ``{.inline.}`` explicitly default to being inline, but that this may change in future versions of the @@ -2843,6 +2856,23 @@ in an implicit try block: finally: close(f) ... +The ``except`` statement has a limitation in this form: you can't specify the +type of the exception, you have to catch everything. Also, if you want to use +both ``finally`` and ``except`` you need to reverse the usual sequence of the +statements. Example: + +.. code-block:: nimrod + proc test() = + raise newException(E_base, "Hey ho") + + proc tester() = + finally: echo "3. Finally block" + except: echo "2. Except block" + echo "1. Pre exception" + test() + echo "4. Post exception" + # --> 1, 2, 3 is printed, 4 is never reached + Raise statement --------------- diff --git a/doc/tut1.txt b/doc/tut1.txt index 2ae7e9540..746d11f01 100755 --- a/doc/tut1.txt +++ b/doc/tut1.txt @@ -349,6 +349,7 @@ provides. The example uses the built-in ``countup`` iterator: echo("Counting to ten: ") for i in countup(1, 10): echo($i) + # --> Outputs 1 2 3 4 5 6 7 8 9 10 on different lines The built-in ``$`` operator turns an integer (``int``) and many other types into a string. The variable ``i`` is implicitly declared by the ``for`` loop @@ -362,6 +363,7 @@ the same: while i <= 10: echo($i) inc(i) # increment i by 1 + # --> Outputs 1 2 3 4 5 6 7 8 9 10 on different lines Counting down can be achieved as easily (but is less often needed): @@ -369,6 +371,7 @@ Counting down can be achieved as easily (but is less often needed): echo("Counting down from 10 to 1: ") for i in countdown(10, 1): echo($i) + # --> Outputs 10 9 8 7 6 5 4 3 2 1 on different lines Since counting up occurs so often in programs, Nimrod also has a ``..`` iterator that does the same: @@ -1202,6 +1205,28 @@ raised) for performance reasons. Thus one should use empty sequences ``@[]`` rather than ``nil`` as the *empty* value. But ``@[]`` creates a sequence object on the heap, so there is a trade-off to be made here. +The ``for`` statement can be used with one or two variables when used with a +sequence. When you use the one variable form, the variable will hold the value +provided by the sequence. The ``for`` statement is looping over the results +from the ``items()`` iterator from the `system <system.html>`_ module. But if +you use the two variable form, the first variable will hold the index position +and the second variable will hold the value. Here the ``for`` statement is +looping over the results from the ``pairs()`` iterator from the `system +<system.html>`_ module. Examples: + +.. code-block:: nimrod + for i in @[3, 4, 5]: + echo($i) + # --> 3 + # --> 4 + # --> 5 + + for i, value in @[3, 4, 5]: + echo("index: ", $i, ", value:", $value) + # --> index: 0, value:3 + # --> index: 1, value:4 + # --> index: 2, value:5 + Open arrays ----------- @@ -1303,14 +1328,10 @@ untraced references are *unsafe*. However for certain low-level operations Traced references are declared with the **ref** keyword, untraced references are declared with the **ptr** keyword. -The empty ``[]`` subscript notation can be used to *derefer* a reference, -meaning to retrieve the item the reference points to. The ``addr`` operator -returns the address of an item. An address is always an untraced reference: -``addr`` is an *unsafe* feature. - -The ``.`` (access a tuple/object field operator) -and ``[]`` (array/string/sequence index operator) operators perform implicit -dereferencing operations for reference types: +The empty ``[]`` subscript notation can be used to *derefer* a reference, +meaning to retrieve the item the reference points to. The ``.`` (access a +tuple/object field operator) and ``[]`` (array/string/sequence index operator) +operators perform implicit dereferencing operations for reference types: .. code-block:: nimrod @@ -1327,8 +1348,8 @@ dereferencing operations for reference types: To allocate a new traced object, the built-in procedure ``new`` has to be used. To deal with untraced memory, the procedures ``alloc``, ``dealloc`` and -``realloc`` can be used. The documentation of the system module contains -further information. +``realloc`` can be used. The documentation of the `system <system.html>`_ +module contains further information. If a reference points to *nothing*, it has the value ``nil``. diff --git a/doc/tut2.txt b/doc/tut2.txt index 9f9dbe2db..c080d1339 100755 --- a/doc/tut2.txt +++ b/doc/tut2.txt @@ -218,7 +218,7 @@ So "pure object oriented" code is easy to write: import strutils stdout.writeln("Give a list of numbers (separated by spaces): ") - stdout.write(stdin.readLine.split.each(parseInt).max.`$`) + stdout.write(stdin.readLine.split.map(parseInt).max.`$`) stdout.writeln(" is the maximum!") @@ -433,6 +433,20 @@ handled, it is propagated through the call stack. This means that often the rest of the procedure - that is not within a ``finally`` clause - is not executed (if an exception occurs). +If you need to *access* the actual exception object or message inside an +``except`` branch you can use the getCurrentException() and +getCurrentExceptionMsg() procs from the `system <system.html>`_ module. +Example: + +.. code-block:: nimrod + try: + doSomethingHere() + except: + let + e = getCurrentException() + msg = getCurrentExceptionMsg() + echo "Got exception ", repr(e), " with message ", msg + Exception hierarchy ------------------- diff --git a/examples/maximum.nim b/examples/maximum.nim index 1e26ee1a7..ac6160f76 100755 --- a/examples/maximum.nim +++ b/examples/maximum.nim @@ -3,4 +3,4 @@ import strutils echo "Give a list of numbers (separated by spaces): " -stdin.readLine.split.each(parseInt).max.`$`.echo(" is the maximum!") +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 73713eec9..298e7f27e 100644 --- a/lib/pure/collections/sequtils.nim +++ b/lib/pure/collections/sequtils.nim @@ -12,8 +12,8 @@ ## This module implements operations for the built-in `seq`:idx: type which ## were inspired by functional programming languages. If you are looking for ## the typical `map` function which applies a function to every element in a -## sequence, it already exists as the `each` proc in the `system -## <system.html>`_ module in both mutable and immutable styles. +## sequence, it already exists in the `system <system.html>`_ module in both +## mutable and immutable styles. ## ## Also, for functional style programming you may want to pass `anonymous procs ## <manual.html#anonymous-procs>`_ to procs like ``filter`` to reduce typing. diff --git a/lib/pure/ftpclient.nim b/lib/pure/ftpclient.nim index e656d001e..b61793866 100644 --- a/lib/pure/ftpclient.nim +++ b/lib/pure/ftpclient.nim @@ -114,7 +114,7 @@ proc getDSock(ftp: PFTPClient): TSocket = proc getCSock(ftp: PFTPClient): TSocket = if ftp.isAsync: return ftp.asyncCSock else: return ftp.csock -template blockingOperation(sock: TSocket, body: stmt) = +template blockingOperation(sock: TSocket, body: stmt) {.immediate.} = if ftp.isAsync: sock.setBlocking(true) body diff --git a/lib/pure/irc.nim b/lib/pure/irc.nim index 8916681f7..aa4e2d557 100644 --- a/lib/pure/irc.nim +++ b/lib/pure/irc.nim @@ -32,7 +32,7 @@ ## **Warning:** The API of this module is unstable, and therefore is subject ## to change. -import sockets, strutils, parseutils, times, asyncio +import sockets, strutils, parseutils, times, asyncio, os type TIRC* = object of TObject @@ -56,6 +56,7 @@ type channelsToJoin: seq[string] msgLimit: bool messageBuffer: seq[tuple[timeToSend: float, m: string]] + lastReconnect: float PIRC* = ref TIRC @@ -235,12 +236,19 @@ proc connect*(irc: PIRC) = irc.send("NICK " & irc.nick, true) irc.send("USER $1 * 0 :$2" % [irc.user, irc.realname], true) -proc reconnect*(irc: PIRC) = +proc reconnect*(irc: PIRC, timeout = 5000) = ## Reconnects to an IRC server. ## + ## ``Timeout`` specifies the time to wait in miliseconds between multiple + ## consecutive reconnections. + ## ## This should be used when an ``EvDisconnected`` event occurs. + let secSinceReconnect = int(epochTime() - irc.lastReconnect) + if secSinceReconnect < timeout: + sleep(timeout - secSinceReconnect) irc.sock = socket() irc.connect() + irc.lastReconnect = epochTime() proc irc*(address: string, port: TPort = 6667.TPort, nick = "NimrodBot", @@ -409,15 +417,22 @@ proc connect*(irc: PAsyncIRC) = irc.asyncSock.connect(irc.address, irc.port) -proc reconnect*(irc: PAsyncIRC) = +proc reconnect*(irc: PAsyncIRC, timeout = 5000) = ## Reconnects to an IRC server. ## + ## ``Timeout`` specifies the time to wait in miliseconds between multiple + ## consecutive reconnections. + ## ## This should be used when an ``EvDisconnected`` event occurs. ## ## When successfully reconnected an ``EvConnected`` event will occur. + let secSinceReconnect = int(epochTime() - irc.lastReconnect) + if secSinceReconnect < timeout: + sleep(timeout - secSinceReconnect) irc.asyncSock = AsyncSocket() irc.myDispatcher.register(irc) irc.connect() + irc.lastReconnect = epochTime() proc asyncIRC*(address: string, port: TPort = 6667.TPort, nick = "NimrodBot", diff --git a/lib/pure/os.nim b/lib/pure/os.nim index 9513dbffb..01daf5ad6 100755 --- a/lib/pure/os.nim +++ b/lib/pure/os.nim @@ -1449,7 +1449,7 @@ proc sleep*(milsecs: int) {.rtl, extern: "nos$1", tags: [FTime].} = else: var a, b: Ttimespec a.tv_sec = TTime(milsecs div 1000) - a.tv_nsec = (milsecs mod 1000) * 1000 + a.tv_nsec = (milsecs mod 1000) * 1000 * 1000 discard posix.nanosleep(a, b) proc getFileSize*(file: string): biggestInt {.rtl, extern: "nos$1", diff --git a/lib/system.nim b/lib/system.nim index 26e5ac228..85d952376 100755 --- a/lib/system.nim +++ b/lib/system.nim @@ -38,7 +38,8 @@ type char* {.magic: Char.} ## built-in 8 bit character type (unsigned) string* {.magic: String.} ## built-in string type cstring* {.magic: Cstring.} ## built-in cstring (*compatible string*) type - pointer* {.magic: Pointer.} ## built-in pointer type + pointer* {.magic: Pointer.} ## built-in pointer type, use the ``addr`` + ## operator to get a pointer to a variable const on* = true ## alias for ``true`` @@ -1460,15 +1461,51 @@ proc pop*[T](s: var seq[T]): T {.inline, noSideEffect.} = result = s[L] setLen(s, L) -proc each*[T, S](data: openArray[T], op: proc (x: T): S {.closure.}): seq[S] = - ## The well-known `map`:idx: operation from functional programming. Applies +proc each*[T, S](data: openArray[T], op: proc (x: T): S {.closure.}): seq[S] {. + deprecated.} = + ## The well-known ``map`` operation from functional programming. Applies ## `op` to every item in `data` and returns the result as a sequence. + ## + ## **Deprecated since version 0.9:** Use the ``map`` proc instead. newSeq(result, data.len) for i in 0..data.len-1: result[i] = op(data[i]) -proc each*[T](data: var openArray[T], op: proc (x: var T) {.closure.}) = - ## The well-known `map`:idx: operation from functional programming. Applies +proc each*[T](data: var openArray[T], op: proc (x: var T) {.closure.}) {. + deprecated.} = + ## The well-known ``map`` operation from functional programming. Applies ## `op` to every item in `data` modifying it directly. + ## + ## **Deprecated since version 0.9:** Use the ``map`` proc instead. + for i in 0..data.len-1: op(data[i]) + +proc map*[T, S](data: openArray[T], op: proc (x: T): S {.closure.}): seq[S] = + ## Returns a new sequence with the results of `op` applied to every item in + ## `data`. + ## + ## Since the input is not modified you can use this version of ``map`` to + ## transform the type of the elements in the input sequence. Example: + ## + ## .. code-block:: nimrod + ## let + ## a = @[1, 2, 3, 4] + ## b = map(a, proc(x: int): string = $x) + ## assert b == @["1", "2", "3", "4"] + newSeq(result, data.len) + for i in 0..data.len-1: result[i] = op(data[i]) + +proc map*[T](data: var openArray[T], op: proc (x: var T) {.closure.}) = + ## Applies `op` to every item in `data` modifying it directly. + ## + ## Note that this version of ``map`` requires your input and output types to + ## be the same, since they are modified in-place. Example: + ## + ## .. code-block:: nimrod + ## 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]) iterator fields*[T: tuple](x: T): TObject {. diff --git a/tests/compile/tclosure4.nim b/tests/compile/tclosure4.nim index 9584fa98a..8e08376b6 100644 --- a/tests/compile/tclosure4.nim +++ b/tests/compile/tclosure4.nim @@ -4,8 +4,8 @@ import json, tables proc run(json_params: TTable) = let json_elems = json_params["files"].elems # These fail compilation. - var files = each(json_elems, proc (x: PJsonNode): string = x.str) - #var files = json_elems.each do (x: PJsonNode) -> string: x.str + var files = map(json_elems, proc (x: PJsonNode): string = x.str) + #var files = json_elems.map do (x: PJsonNode) -> string: x.str echo "Hey!" when isMainModule: diff --git a/tests/compile/tclosurebug2.nim b/tests/compile/tclosurebug2.nim new file mode 100644 index 000000000..ec4f0045b --- /dev/null +++ b/tests/compile/tclosurebug2.nim @@ -0,0 +1,194 @@ +import hashes, math + +type + TSlotEnum = enum seEmpty, seFilled, seDeleted + TKeyValuePair[A, B] = tuple[slot: TSlotEnum, key: A, val: B] + TKeyValuePairSeq[A, B] = seq[TKeyValuePair[A, B]] + + TOrderedKeyValuePair[A, B] = tuple[ + slot: TSlotEnum, next: int, key: A, val: B] + TOrderedKeyValuePairSeq[A, B] = seq[TOrderedKeyValuePair[A, B]] + TOrderedTable*[A, B] = object ## table that remembers insertion order + data: TOrderedKeyValuePairSeq[A, B] + counter, first, last: int + +const + growthFactor = 2 + +proc mustRehash(length, counter: int): bool {.inline.} = + assert(length > counter) + result = (length * 2 < counter * 3) or (length - counter < 4) + +proc nextTry(h, maxHash: THash): THash {.inline.} = + result = ((5 * h) + 1) and maxHash + +template rawGetImpl() {.dirty.} = + var h: THash = hash(key) and high(t.data) # start with real hash value + while t.data[h].slot != seEmpty: + if t.data[h].key == key and t.data[h].slot == seFilled: + return h + h = nextTry(h, high(t.data)) + result = -1 + +template rawInsertImpl() {.dirty.} = + var h: THash = hash(key) and high(data) + while data[h].slot == seFilled: + h = nextTry(h, high(data)) + data[h].key = key + data[h].val = val + data[h].slot = seFilled + +template AddImpl() {.dirty.} = + if mustRehash(len(t.data), t.counter): Enlarge(t) + RawInsert(t, t.data, key, val) + inc(t.counter) + +template PutImpl() {.dirty.} = + var index = RawGet(t, key) + if index >= 0: + t.data[index].val = val + else: + AddImpl() + +proc len*[A, B](t: TOrderedTable[A, B]): int {.inline.} = + ## returns the number of keys in `t`. + result = t.counter + +template forAllOrderedPairs(yieldStmt: stmt) {.dirty, immediate.} = + var h = t.first + while h >= 0: + var nxt = t.data[h].next + if t.data[h].slot == seFilled: yieldStmt + h = nxt + +iterator pairs*[A, B](t: TOrderedTable[A, B]): tuple[key: A, val: B] = + ## iterates over any (key, value) pair in the table `t` in insertion + ## order. + forAllOrderedPairs: + yield (t.data[h].key, t.data[h].val) + +iterator mpairs*[A, B](t: var TOrderedTable[A, B]): tuple[key: A, val: var B] = + ## iterates over any (key, value) pair in the table `t` in insertion + ## order. The values can be modified. + forAllOrderedPairs: + yield (t.data[h].key, t.data[h].val) + +iterator keys*[A, B](t: TOrderedTable[A, B]): A = + ## iterates over any key in the table `t` in insertion order. + forAllOrderedPairs: + yield t.data[h].key + +iterator values*[A, B](t: TOrderedTable[A, B]): B = + ## iterates over any value in the table `t` in insertion order. + forAllOrderedPairs: + yield t.data[h].val + +iterator mvalues*[A, B](t: var TOrderedTable[A, B]): var B = + ## iterates over any value in the table `t` in insertion order. The values + ## can be modified. + forAllOrderedPairs: + yield t.data[h].val + +proc RawGet[A, B](t: TOrderedTable[A, B], key: A): int = + rawGetImpl() + +proc `[]`*[A, B](t: TOrderedTable[A, B], key: A): B = + ## retrieves the value at ``t[key]``. If `key` is not in `t`, + ## default empty value for the type `B` is returned + ## and no exception is raised. One can check with ``hasKey`` whether the key + ## exists. + var index = RawGet(t, key) + if index >= 0: result = t.data[index].val + +proc mget*[A, B](t: var TOrderedTable[A, B], key: A): var B = + ## retrieves the value at ``t[key]``. The value can be modified. + ## If `key` is not in `t`, the ``EInvalidKey`` exception is raised. + var index = RawGet(t, key) + if index >= 0: result = t.data[index].val + else: raise newException(EInvalidKey, "key not found: " & $key) + +proc hasKey*[A, B](t: TOrderedTable[A, B], key: A): bool = + ## returns true iff `key` is in the table `t`. + result = rawGet(t, key) >= 0 + +proc RawInsert[A, B](t: var TOrderedTable[A, B], + data: var TOrderedKeyValuePairSeq[A, B], + key: A, val: B) = + rawInsertImpl() + data[h].next = -1 + if t.first < 0: t.first = h + if t.last >= 0: data[t.last].next = h + t.last = h + +proc Enlarge[A, B](t: var TOrderedTable[A, B]) = + var n: TOrderedKeyValuePairSeq[A, B] + newSeq(n, len(t.data) * growthFactor) + var h = t.first + t.first = -1 + t.last = -1 + while h >= 0: + var nxt = t.data[h].next + if t.data[h].slot == seFilled: + RawInsert(t, n, t.data[h].key, t.data[h].val) + h = nxt + swap(t.data, n) + +proc `[]=`*[A, B](t: var TOrderedTable[A, B], key: A, val: B) = + ## puts a (key, value)-pair into `t`. + putImpl() + +proc add*[A, B](t: var TOrderedTable[A, B], key: A, val: B) = + ## puts a new (key, value)-pair into `t` even if ``t[key]`` already exists. + AddImpl() + +proc initOrderedTable*[A, B](initialSize=64): TOrderedTable[A, B] = + ## creates a new ordered hash table that is empty. `initialSize` needs to be + ## a power of two. + assert isPowerOfTwo(initialSize) + result.counter = 0 + result.first = -1 + result.last = -1 + newSeq(result.data, initialSize) + +proc toOrderedTable*[A, B](pairs: openarray[tuple[key: A, + val: B]]): TOrderedTable[A, B] = + ## creates a new ordered hash table that contains the given `pairs`. + result = initOrderedTable[A, B](nextPowerOfTwo(pairs.len+10)) + for key, val in items(pairs): result[key] = val + +proc sort*[A, B](t: var TOrderedTable[A,B], + cmp: proc (x, y: tuple[key: A, val: B]): int {.closure.}) = + ## sorts the ordered table so that the entry with the highest counter comes + ## first. This is destructive (with the advantage of being efficient)! + ## You must not modify `t` afterwards! + ## You can use the iterators `pairs`, `keys`, and `values` to iterate over + ## `t` in the sorted order. + + # we use shellsort here; fast enough and simple + var h = 1 + while true: + h = 3 * h + 1 + if h >= high(t.data): break + while true: + h = h div 3 + for i in countup(h, high(t.data)): + var j = i + #echo(t.data.len, " ", j, " - ", h) + #echo(repr(t.data[j-h])) + proc rawCmp(x, y: TOrderedKeyValuePair[A, B]): int = + if x.slot in {seEmpty, seDeleted} and y.slot in {seEmpty, seDeleted}: + return 0 + elif x.slot in {seEmpty, seDeleted}: + return -1 + elif y.slot in {seEmpty, seDeleted}: + return 1 + else: + let item1 = (x.key, x.val) + let item2 = (y.key, y.val) + return cmp(item1, item2) + + while rawCmp(t.data[j-h], t.data[j]) <= 0: + swap(t.data[j], t.data[j-h]) + j = j-h + if j < h: break + if h == 1: break diff --git a/tests/compile/tnamedparamanonproc.nim b/tests/compile/tnamedparamanonproc.nim new file mode 100644 index 000000000..272b84e91 --- /dev/null +++ b/tests/compile/tnamedparamanonproc.nim @@ -0,0 +1,14 @@ + +type + PButton = ref object + TButtonClicked = proc(button: PButton) {.nimcall.} + +proc newButton*(onClick: TButtonClicked) = + nil + +proc main() = + newButton(onClick = proc(b: PButton) = + var requestomat = 12 + ) + +main() diff --git a/tests/compile/toverprc.nim b/tests/compile/toverprc.nim index 43271b684..f3aa66b80 100755 --- a/tests/compile/toverprc.nim +++ b/tests/compile/toverprc.nim @@ -21,7 +21,7 @@ proc takeParseInt(x: proc (y: string): int {.noSideEffect.}): int = result = x("123") echo "Give a list of numbers (separated by spaces): " -var x = stdin.readline.split.each(parseInt).max +var x = stdin.readline.split.map(parseInt).max echo x, " is the maximum!" echo "another number: ", takeParseInt(parseInt) diff --git a/tests/run/tdomulttest.nim b/tests/run/tdomulttest.nim index 6842d38ed..4ee6de128 100644 --- a/tests/run/tdomulttest.nim +++ b/tests/run/tdomulttest.nim @@ -1,6 +1,7 @@ discard """ file: "tdomulttest.nim" output: "555\ntest\nmulti lines\n99999999\nend" + disabled: true """ proc foo(bar, baz: proc (x: int): int) = echo bar(555) diff --git a/tests/run/tmultim6.nim b/tests/run/tmultim6.nim index a55b69e37..5f45f572a 100644 --- a/tests/run/tmultim6.nim +++ b/tests/run/tmultim6.nim @@ -1,5 +1,5 @@ discard """ - output: "collide: unit, thing | collide: unit, thing | collide: thing, unit" + output: "collide: unit, thing | collide: unit, thing | collide: thing, unit |" """ # Test multi methods diff --git a/todo.txt b/todo.txt index 56a27e0fa..14f892b4e 100755 --- a/todo.txt +++ b/todo.txt @@ -3,9 +3,8 @@ version 0.9.2 - implement constructors + full 'not nil' checking - ``restrict`` pragma + backend support -- fix closure bug finally - fix marshal bug -- investigate nimgame bug +- fix: 'result' is not properly cleaned for NRVO version 0.9.4 @@ -62,6 +61,7 @@ version 0.9.XX not in a 'let/var' context (p(a.openFile, b.openFile) makes no sense anyway) - document nimdoc properly finally - make 'clamp' a magic for the range stuff +- better type syntax for functions and tuples: tuple(int, int); (int,int)->int Not essential for 1.0.0 diff --git a/web/index.txt b/web/index.txt index 207e425ae..99beb3743 100755 --- a/web/index.txt +++ b/web/index.txt @@ -33,7 +33,7 @@ from that model. # Prints the maximum integer from a list of integers # delimited by whitespace read from stdin. let tokens = stdin.readLine.split - echo tokens.each(parseInt).max, " is the maximum." + echo tokens.map(parseInt).max, " is the maximum." Nimrod is efficient |