summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rwxr-xr-xcompiler/ccgexprs.nim2
-rw-r--r--compiler/lambdalifting.nim2
-rwxr-xr-xcompiler/semexprs.nim4
-rwxr-xr-xcompiler/semstmts.nim38
-rwxr-xr-xdoc/manual.txt58
-rwxr-xr-xdoc/tut1.txt41
-rwxr-xr-xdoc/tut2.txt16
-rwxr-xr-xexamples/maximum.nim2
-rw-r--r--lib/pure/collections/sequtils.nim4
-rw-r--r--lib/pure/ftpclient.nim2
-rw-r--r--lib/pure/irc.nim21
-rwxr-xr-xlib/pure/os.nim2
-rwxr-xr-xlib/system.nim47
-rw-r--r--tests/compile/tclosure4.nim4
-rw-r--r--tests/compile/tclosurebug2.nim194
-rw-r--r--tests/compile/tnamedparamanonproc.nim14
-rwxr-xr-xtests/compile/toverprc.nim2
-rw-r--r--tests/run/tdomulttest.nim1
-rw-r--r--tests/run/tmultim6.nim2
-rwxr-xr-xtodo.txt4
-rwxr-xr-xweb/index.txt2
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