summary refs log tree commit diff stats
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/core/macros.nim2
-rw-r--r--lib/impure/rdstdin.nim66
-rw-r--r--lib/impure/re.nim6
-rw-r--r--lib/nimbase.h20
-rw-r--r--lib/packages/docutils/rst.nim4
-rw-r--r--lib/packages/docutils/rstast.nim10
-rw-r--r--lib/packages/docutils/rstgen.nim6
-rw-r--r--lib/pure/algorithm.nim28
-rw-r--r--lib/pure/asyncdispatch.nim62
-rw-r--r--lib/pure/asyncfile.nim4
-rw-r--r--lib/pure/collections/sequtils.nim33
-rw-r--r--lib/pure/collections/tables.nim6
-rw-r--r--lib/pure/hashes.nim4
-rw-r--r--lib/pure/httpclient.nim10
-rw-r--r--lib/pure/json.nim2
-rw-r--r--lib/pure/lexbase.nim2
-rw-r--r--lib/pure/parsexml.nim40
-rw-r--r--lib/pure/pegs.nim310
-rw-r--r--lib/pure/redis.nim16
-rw-r--r--lib/pure/streams.nim10
-rw-r--r--lib/pure/terminal.nim18
-rw-r--r--lib/pure/times.nim8
-rw-r--r--lib/pure/unicode.nim22
-rw-r--r--lib/pure/uri.nim10
-rw-r--r--lib/pure/xmldom.nim12
-rw-r--r--lib/system.nim204
-rw-r--r--lib/system/deepcopy.nim4
-rw-r--r--lib/system/gc.nim84
-rw-r--r--lib/system/gc2.nim2
-rw-r--r--lib/system/sysstr.nim44
30 files changed, 615 insertions, 434 deletions
diff --git a/lib/core/macros.nim b/lib/core/macros.nim
index 0888a8767..f73dbd241 100644
--- a/lib/core/macros.nim
+++ b/lib/core/macros.nim
@@ -60,7 +60,7 @@ type
     nnkStmtListType, nnkBlockType,
     nnkWith, nnkWithout,
     nnkTypeOfExpr, nnkObjectTy,
-    nnkTupleTy, nnkTypeClassTy, nnkStaticTy,
+    nnkTupleTy, nnkTupleClassTy, nnkTypeClassTy, nnkStaticTy,
     nnkRecList, nnkRecCase, nnkRecWhen,
     nnkRefTy, nnkPtrTy, nnkVarTy,
     nnkConstTy, nnkMutableTy,
diff --git a/lib/impure/rdstdin.nim b/lib/impure/rdstdin.nim
index aaf2ed1ca..f64f9ccb2 100644
--- a/lib/impure/rdstdin.nim
+++ b/lib/impure/rdstdin.nim
@@ -8,16 +8,16 @@
 #
 
 ## This module contains code for reading from `stdin`:idx:. On UNIX the GNU
-## readline library is wrapped and set up to provide default key bindings 
+## readline library is wrapped and set up to provide default key bindings
 ## (e.g. you can navigate with the arrow keys). On Windows ``system.readLine``
-## is used. This suffices because Windows' console already provides the 
+## is used. This suffices because Windows' console already provides the
 ## wanted functionality.
 
 {.deadCodeElim: on.}
 
 when defined(Windows):
   proc readLineFromStdin*(prompt: string): TaintedString {.
-                          tags: [ReadIOEffect, WriteIOEffect].} = 
+                          tags: [ReadIOEffect, WriteIOEffect].} =
     ## Reads a line from stdin.
     stdout.write(prompt)
     result = readLine(stdin)
@@ -33,27 +33,71 @@ when defined(Windows):
     stdout.write(prompt)
     result = readLine(stdin, line)
 
+  import winlean
+
+  const
+    VK_SHIFT* = 16
+    VK_CONTROL* = 17
+    VK_MENU* = 18
+    KEY_EVENT* = 1
+
+  type
+    KEY_EVENT_RECORD = object
+      bKeyDown: WinBool
+      wRepeatCount: uint16
+      wVirtualKeyCode: uint16
+      wVirtualScanCode: uint16
+      unicodeChar: uint16
+      dwControlKeyState: uint32
+    INPUT_RECORD = object
+      eventType*: int16
+      reserved*: int16
+      event*: KEY_EVENT_RECORD
+      safetyBuffer: array[0..5, DWORD]
+
+  proc readConsoleInputW*(hConsoleInput: THANDLE, lpBuffer: var INPUTRECORD,
+                          nLength: uint32,
+                          lpNumberOfEventsRead: var uint32): WINBOOL{.
+      stdcall, dynlib: "kernel32", importc: "ReadConsoleInputW".}
+
+  proc getch(): uint16 =
+    let hStdin = getStdHandle(STD_INPUT_HANDLE)
+    var
+      irInputRecord: INPUT_RECORD
+      dwEventsRead: uint32
+
+    while readConsoleInputW(hStdin, irInputRecord, 1, dwEventsRead) != 0:
+      if irInputRecord.eventType == KEY_EVENT and
+          irInputRecord.event.wVirtualKeyCode notin {VK_SHIFT, VK_MENU, VK_CONTROL}:
+         result = irInputRecord.event.unicodeChar
+         discard readConsoleInputW(hStdin, irInputRecord, 1, dwEventsRead)
+         return result
+
+  from unicode import toUTF8, Rune, runeLenAt
+
   proc readPasswordFromStdin*(prompt: string, password: var TaintedString):
                               bool {.tags: [ReadIOEffect, WriteIOEffect].} =
     ## Reads a `password` from stdin without printing it. `password` must not
     ## be ``nil``! Returns ``false`` if the end of the file has been reached,
     ## ``true`` otherwise.
-    proc getch(): cint {.header: "<conio.h>", importc: "_getch".}
-
     password.setLen(0)
-    var c: char
     stdout.write(prompt)
     while true:
-      c = getch().char
-      case c
+      let c = getch()
+      case c.char
       of '\r', chr(0xA):
         break
       of '\b':
-        password.setLen(password.len - 1)
+        # ensure we delete the whole UTF-8 character:
+        var i = 0
+        var x = 1
+        while i < password.len:
+          x = runeLenAt(password, i)
+          inc i, x
+        password.setLen(password.len -  x)
       else:
-        password.add(c)
+        password.add(toUTF8(c.Rune))
     stdout.write "\n"
-    # TODO: How to detect EOF on Windows?
 
 else:
   import readline, history, termios, unsigned
diff --git a/lib/impure/re.nim b/lib/impure/re.nim
index 7d5ff8948..921a24fd1 100644
--- a/lib/impure/re.nim
+++ b/lib/impure/re.nim
@@ -66,7 +66,7 @@ proc rawCompile(pattern: string, flags: cint): PPcre =
     offset: cint
   result = pcre.compile(pattern, flags, addr(msg), addr(offset), nil)
   if result == nil:
-    raiseInvalidRegex($msg & "\n" & pattern & "\n" & repeatChar(offset) & "^\n")
+    raiseInvalidRegex($msg & "\n" & pattern & "\n" & spaces(offset) & "^\n")
 
 proc finalizeRegEx(x: Regex) = 
   # XXX This is a hack, but PCRE does not export its "free" function properly.
@@ -291,7 +291,7 @@ proc replace*(s: string, sub: Regex, by = ""): string =
   ## accessed in `by`. Examples:
   ##
   ## .. code-block:: nim
-  ##   "var1=key; var2=key2".replace(re"(\w+)'='(\w+)")
+  ##   "var1=key; var2=key2".replace(re"(\w+)=(\w+)")
   ##
   ## Results in:
   ##
@@ -313,7 +313,7 @@ proc replacef*(s: string, sub: Regex, by: string): string =
   ## with the notation ``$i`` and ``$#`` (see strutils.`%`). Examples:
   ##
   ## .. code-block:: nim
-  ## "var1=key; var2=key2".replacef(re"(\w+)'='(\w+)", "$1<-$2$2")
+  ##   "var1=key; var2=key2".replacef(re"(\w+)=(\w+)", "$1<-$2$2")
   ##
   ## Results in:
   ##
diff --git a/lib/nimbase.h b/lib/nimbase.h
index 50c7968ac..e9dad0bb7 100644
--- a/lib/nimbase.h
+++ b/lib/nimbase.h
@@ -67,7 +67,7 @@ __clang__
 #endif
 
 #if (defined(WIN32) || defined(_WIN32) || defined(__WIN32__))
-#  define NIM_THREADVAR __declspec(thread) 
+#  define NIM_THREADVAR __declspec(thread)
 #else
 #  define NIM_THREADVAR __thread
 #endif
@@ -103,7 +103,11 @@ __clang__
 #  define N_FASTCALL_PTR(rettype, name) rettype (__fastcall *name)
 #  define N_SAFECALL_PTR(rettype, name) rettype (__safecall *name)
 
-#  define N_LIB_EXPORT  extern __declspec(dllexport)
+#  ifdef __cplusplus
+#    define N_LIB_EXPORT  extern "C" __declspec(dllexport)
+#  else
+#    define N_LIB_EXPORT  extern __declspec(dllexport)
+#  endif
 #  define N_LIB_IMPORT  extern __declspec(dllimport)
 #else
 #  define N_CDECL(rettype, name) rettype name
@@ -118,7 +122,11 @@ __clang__
 #  define N_FASTCALL_PTR(rettype, name) rettype (*name)
 #  define N_SAFECALL_PTR(rettype, name) rettype (*name)
 
-#  define N_LIB_EXPORT  extern
+#  ifdef __cplusplus
+#    define N_LIB_EXPORT  extern "C"
+#  else
+#    define N_LIB_EXPORT  extern
+#  endif
 #  define N_LIB_IMPORT  extern
 #endif
 
@@ -345,7 +353,7 @@ struct TFrame {
 #define nimln(n, file) \
   F.line = n; F.filename = file;
 
-#define NIM_POSIX_INIT  __attribute__((constructor)) 
+#define NIM_POSIX_INIT  __attribute__((constructor))
 
 #if defined(_MSCVER) && defined(__i386__)
 __declspec(naked) int __fastcall NimXadd(volatile int* pNum, int val) {
@@ -380,7 +388,7 @@ static inline void GCGuard (void *ptr) { asm volatile ("" :: "X" (ptr)); }
 #endif
 
 /* Test to see if Nim and the C compiler agree on the size of a pointer.
-   On disagreement, your C compiler will say something like: 
+   On disagreement, your C compiler will say something like:
    "error: 'assert_numbits' declared as an array with a negative size" */
 typedef int assert_numbits[sizeof(NI) == sizeof(void*) && NIM_INTBITS == sizeof(NI)*8 ? 1 : -1];
 #endif
@@ -398,4 +406,6 @@ typedef int assert_numbits[sizeof(NI) == sizeof(void*) && NIM_INTBITS == sizeof(
 #  include <sys/types.h>
 #  include <types/vxWind.h>
 #  include <tool/gnu/toolMacros.h>
+#elif defined(__FreeBSD__)
+#  include <sys/types.h>
 #endif
diff --git a/lib/packages/docutils/rst.nim b/lib/packages/docutils/rst.nim
index 95d49bad7..97784898e 100644
--- a/lib/packages/docutils/rst.nim
+++ b/lib/packages/docutils/rst.nim
@@ -189,7 +189,7 @@ proc getIndent(L: var TLexer, tok: var TToken) =
   tok.line = L.line
   L.col = tok.ival
   tok.ival = max(tok.ival - L.baseIndent, 0)
-  tok.symbol = "\n" & repeatChar(tok.ival)
+  tok.symbol = "\n" & spaces(tok.ival)
 
 proc rawGetTok(L: var TLexer, tok: var TToken) = 
   tok.symbol = ""
@@ -963,7 +963,7 @@ proc parseLiteralBlock(p: var TRstParser): PRstNode =
           break 
         else: 
           add(n.text, "\n")
-          add(n.text, repeatChar(p.tok[p.idx].ival - indent))
+          add(n.text, spaces(p.tok[p.idx].ival - indent))
           inc(p.idx)
       else: 
         add(n.text, p.tok[p.idx].symbol)
diff --git a/lib/packages/docutils/rstast.nim b/lib/packages/docutils/rstast.nim
index 52af672df..614001d76 100644
--- a/lib/packages/docutils/rstast.nim
+++ b/lib/packages/docutils/rstast.nim
@@ -110,7 +110,7 @@ proc renderRstToRst(d: var TRenderContext, n: PRstNode, result: var string) =
   const 
     lvlToChar: array[0..8, char] = ['!', '=', '-', '~', '`', '<', '*', '|', '+']
   if n == nil: return
-  var ind = repeatChar(d.indent)
+  var ind = spaces(d.indent)
   case n.kind
   of rnInner: 
     renderRstSons(d, n, result)
@@ -124,7 +124,7 @@ proc renderRstToRst(d: var TRenderContext, n: PRstNode, result: var string) =
 
     result.add("\n")
     result.add(ind)
-    result.add repeatChar(headlineLen, lvlToChar[n.level])
+    result.add repeat(lvlToChar[n.level], headlineLen)
   of rnOverline:
     result.add("\n")
     result.add(ind)
@@ -132,7 +132,7 @@ proc renderRstToRst(d: var TRenderContext, n: PRstNode, result: var string) =
     var headline = ""
     renderRstSons(d, n, headline)
     
-    let lvl = repeatChar(headline.len - d.indent, lvlToChar[n.level])
+    let lvl = repeat(lvlToChar[n.level], headline.len - d.indent)
     result.add(lvl)
     result.add("\n")
     result.add(headline)
@@ -143,7 +143,7 @@ proc renderRstToRst(d: var TRenderContext, n: PRstNode, result: var string) =
   of rnTransition: 
     result.add("\n\n")
     result.add(ind)
-    result.add repeatChar(78-d.indent, '-')
+    result.add repeat('-', 78-d.indent)
     result.add("\n\n")
   of rnParagraph:
     result.add("\n\n")
@@ -196,7 +196,7 @@ proc renderRstToRst(d: var TRenderContext, n: PRstNode, result: var string) =
     result.add ':'
     result.add tmp
     result.add ':'
-    result.add repeatChar(L - tmp.len - 2)
+    result.add spaces(L - tmp.len - 2)
     renderRstToRst(d, n.sons[1], result)
     
     dec(d.indent, L)
diff --git a/lib/packages/docutils/rstgen.nim b/lib/packages/docutils/rstgen.nim
index e1e590877..a385336d6 100644
--- a/lib/packages/docutils/rstgen.nim
+++ b/lib/packages/docutils/rstgen.nim
@@ -461,9 +461,9 @@ proc indentToLevel(level: var int, newLevel: int): string =
   if level == newLevel:
     return
   if newLevel > level:
-    result = repeatStr(newLevel - level, "<ul>")
+    result = repeat("<ul>", newLevel - level)
   else:
-    result = repeatStr(level - newLevel, "</ul>")
+    result = repeat("</ul>", level - newLevel)
   level = newLevel
 
 proc generateDocumentationTOC(entries: seq[TIndexEntry]): string =
@@ -701,7 +701,7 @@ proc renderHeadline(d: PDoc, n: PRstNode, result: var string) =
   # Generate index entry using spaces to indicate TOC level for the output HTML.
   assert n.level >= 0
   setIndexTerm(d, refname, tmp.stripTOCHTML,
-    repeatChar(max(0, n.level), ' ') & tmp)
+    spaces(max(0, n.level)) & tmp)
 
 proc renderOverline(d: PDoc, n: PRstNode, result: var string) = 
   if d.meta[metaTitle].len == 0:
diff --git a/lib/pure/algorithm.nim b/lib/pure/algorithm.nim
index 20bfc5c7c..20976e788 100644
--- a/lib/pure/algorithm.nim
+++ b/lib/pure/algorithm.nim
@@ -187,6 +187,34 @@ proc sort*[T](a: var openArray[T],
       dec(m, s*2)
     s = s*2
 
+proc sorted*[T](a: openArray[T], cmp: proc(x, y: T): int {.closure.}, order = SortOrder.Ascending): seq[T] =
+  ## returns `a` sorted by `cmp` in the specified `order`.
+  result = newSeq[T](a.len)
+  for i in 0 .. a.high:
+    result[i] = a[i]
+  sort(result, cmp, order)
+
+template sortByIt*(seq1, op: expr): expr =
+  ## Convenience template around the ``sorted`` proc to reduce typing.
+  ##
+  ## The template injects the ``it`` variable which you can use directly in an
+  ## expression. Example:
+  ##
+  ## .. code-block:: nim
+  ##
+  ##     var users: seq[tuple[id: int, name: string]] =
+  ##       @[(0, "Smith"), (1, "Pratt"), (2, "Sparrow")]
+  ##
+  ##     echo users.sortByIt(it.name)
+  ##
+  var result {.gensym.} = sorted(seq1, proc(x, y: type(seq1[0])): int =
+    var it {.inject.} = x
+    let a = op
+    it = y
+    let b = op
+    result = cmp(a, b))
+  result
+
 proc product*[T](x: openArray[seq[T]]): seq[seq[T]] =
   ## produces the Cartesian product of the array. Warning: complexity
   ## may explode.
diff --git a/lib/pure/asyncdispatch.nim b/lib/pure/asyncdispatch.nim
index d6ed66030..bf905ed49 100644
--- a/lib/pure/asyncdispatch.nim
+++ b/lib/pure/asyncdispatch.nim
@@ -121,7 +121,7 @@ export Port, SocketFlag
 ##
 ## Limitations/Bugs
 ## ----------------
-## 
+##
 ## * ``except`` statement (without `try`) does not work inside async procedures.
 ## * The effect system (``raises: []``) does not work with async procedures.
 ## * Can't await in a ``except`` body
@@ -379,7 +379,7 @@ when defined(windows) or defined(nimdoc):
     if p.handles.len == 0 and p.timers.len == 0:
       raise newException(ValueError,
         "No handles or timers registered in dispatcher.")
-    
+
     let llTimeout =
       if timeout ==  -1: winlean.INFINITE
       else: timeout.int32
@@ -436,12 +436,12 @@ when defined(windows) or defined(nimdoc):
     if not initPointer(dummySock, getAcceptExSockAddrsPtr, WSAID_GETACCEPTEXSOCKADDRS):
       raiseOSError(osLastError())
 
-  proc connectEx(s: SocketHandle, name: ptr SockAddr, namelen: cint, 
+  proc connectEx(s: SocketHandle, name: ptr SockAddr, namelen: cint,
                   lpSendBuffer: pointer, dwSendDataLength: Dword,
                   lpdwBytesSent: PDword, lpOverlapped: POVERLAPPED): bool =
     if connectExPtr.isNil: raise newException(ValueError, "Need to initialise ConnectEx().")
     let fun =
-      cast[proc (s: SocketHandle, name: ptr SockAddr, namelen: cint, 
+      cast[proc (s: SocketHandle, name: ptr SockAddr, namelen: cint,
          lpSendBuffer: pointer, dwSendDataLength: Dword,
          lpdwBytesSent: PDword, lpOverlapped: POVERLAPPED): bool {.stdcall,gcsafe.}](connectExPtr)
 
@@ -475,7 +475,7 @@ when defined(windows) or defined(nimdoc):
                  dwRemoteAddressLength: Dword, LocalSockaddr: ptr ptr SockAddr,
                  LocalSockaddrLength: LPInt, RemoteSockaddr: ptr ptr SockAddr,
                 RemoteSockaddrLength: LPInt) {.stdcall,gcsafe.}](getAcceptExSockAddrsPtr)
-    
+
     fun(lpOutputBuffer, dwReceiveDataLength, dwLocalAddressLength,
                   dwRemoteAddressLength, LocalSockaddr, LocalSockaddrLength,
                   RemoteSockaddr, RemoteSockaddrLength)
@@ -514,7 +514,7 @@ when defined(windows) or defined(nimdoc):
             else:
               retFuture.fail(newException(OSError, osErrorMsg(errcode)))
       )
-      
+
       var ret = connectEx(socket.SocketHandle, it.ai_addr,
                           sizeof(Sockaddr_in).cint, nil, 0, nil,
                           cast[POVERLAPPED](ol))
@@ -565,7 +565,7 @@ when defined(windows) or defined(nimdoc):
     var dataBuf: TWSABuf
     dataBuf.buf = cast[cstring](alloc0(size))
     dataBuf.len = size
-    
+
     var bytesReceived: Dword
     var flagsio = flags.toOSFlags().Dword
     var ol = PCustomOverlapped()
@@ -612,9 +612,9 @@ when defined(windows) or defined(nimdoc):
       # the empty string (which signals a disconnection) when there is
       # nothing left to read.
       retFuture.complete("")
-      # TODO: "For message-oriented sockets, where a zero byte message is often 
-      # allowable, a failure with an error code of WSAEDISCON is used to 
-      # indicate graceful closure." 
+      # TODO: "For message-oriented sockets, where a zero byte message is often
+      # allowable, a failure with an error code of WSAEDISCON is used to
+      # indicate graceful closure."
       # ~ http://msdn.microsoft.com/en-us/library/ms741688%28v=vs.85%29.aspx
     else:
       # Request to read completed immediately.
@@ -748,7 +748,7 @@ when defined(windows) or defined(nimdoc):
 
     # http://msdn.microsoft.com/en-us/library/windows/desktop/ms737524%28v=vs.85%29.aspx
     let ret = acceptEx(socket.SocketHandle, clientSock, addr lpOutputBuf[0],
-                       dwReceiveDataLength, 
+                       dwReceiveDataLength,
                        dwLocalAddressLength,
                        dwRemoteAddressLength,
                        addr dwBytesReceived, cast[POVERLAPPED](ol))
@@ -803,7 +803,7 @@ else:
   else:
     from posix import EINTR, EAGAIN, EINPROGRESS, EWOULDBLOCK, MSG_PEEK,
                       MSG_NOSIGNAL
-  
+
   type
     TAsyncFD* = distinct cint
     TCallback = proc (fd: TAsyncFD): bool {.closure,gcsafe.}
@@ -849,7 +849,7 @@ else:
     result = newRawSocket(domain, typ, protocol).TAsyncFD
     result.SocketHandle.setBlocking(false)
     register(result)
-  
+
   proc closeSocket*(sock: TAsyncFD) =
     let disp = getGlobalDispatcher()
     sock.SocketHandle.close()
@@ -864,14 +864,14 @@ else:
       raise newException(ValueError, "File descriptor not registered.")
     p.selector[fd.SocketHandle].data.PData.readCBs.add(cb)
     update(fd, p.selector[fd.SocketHandle].events + {EvRead})
-  
+
   proc addWrite*(fd: TAsyncFD, cb: TCallback) =
     let p = getGlobalDispatcher()
     if fd.SocketHandle notin p.selector:
       raise newException(ValueError, "File descriptor not registered.")
     p.selector[fd.SocketHandle].data.PData.writeCBs.add(cb)
     update(fd, p.selector[fd.SocketHandle].events + {EvWrite})
-  
+
   proc poll*(timeout = 500) =
     let p = getGlobalDispatcher()
     for info in p.selector.select(timeout):
@@ -892,7 +892,7 @@ else:
           if not cb(data.fd):
             # Callback wants to be called again.
             data.readCBs.add(cb)
-      
+
       if EvWrite in info.events:
         let currentCBs = data.writeCBs
         data.writeCBs = @[]
@@ -900,7 +900,7 @@ else:
           if not cb(data.fd):
             # Callback wants to be called again.
             data.writeCBs.add(cb)
-      
+
       if info.key in p.selector:
         var newEvents: set[Event]
         if data.readCBs.len != 0: newEvents = {EvRead}
@@ -913,16 +913,16 @@ else:
         discard
 
     processTimers(p)
-  
+
   proc connect*(socket: TAsyncFD, address: string, port: Port,
     af = AF_INET): Future[void] =
     var retFuture = newFuture[void]("connect")
-    
+
     proc cb(fd: TAsyncFD): bool =
       # We have connected.
       retFuture.complete()
       return true
-    
+
     var aiList = getAddrInfo(address, port, af)
     var success = false
     var lastError: OSErrorCode
@@ -952,7 +952,7 @@ else:
   proc recv*(socket: TAsyncFD, size: int,
              flags = {SocketFlag.SafeDisconn}): Future[string] =
     var retFuture = newFuture[string]("recv")
-    
+
     var readBuffer = newString(size)
 
     proc cb(sock: TAsyncFD): bool =
@@ -983,9 +983,9 @@ else:
   proc send*(socket: TAsyncFD, data: string,
              flags = {SocketFlag.SafeDisconn}): Future[void] =
     var retFuture = newFuture[void]("send")
-    
+
     var written = 0
-    
+
     proc cb(sock: TAsyncFD): bool =
       result = true
       let netSize = data.len-written
@@ -1222,7 +1222,7 @@ proc processBody(node, retFutureSym: PNimrodNode,
   of nnkTryStmt:
     # try: await x; except: ...
     result = newNimNode(nnkStmtList, node)
-    template wrapInTry(n, tryBody: PNimrodNode) =
+    template wrapInTry(n, tryBody: expr) =
       var temp = n
       n[0] = tryBody
       tryBody = temp
@@ -1315,14 +1315,14 @@ macro async*(prc: stmt): stmt {.immediate.} =
     if returnType.kind == nnkEmpty: newIdentNode("void")
     else: returnType[1]
   outerProcBody.add(
-    newVarStmt(retFutureSym, 
+    newVarStmt(retFutureSym,
       newCall(
         newNimNode(nnkBracketExpr, prc[6]).add(
           newIdentNode(!"newFuture"), # TODO: Strange bug here? Remove the `!`.
           subRetType),
       newLit(prc[0].getName)))) # Get type from return type of this proc
-  
-  # -> iterator nameIter(): FutureBase {.closure.} = 
+
+  # -> iterator nameIter(): FutureBase {.closure.} =
   # ->   var result: T
   # ->   <proc_body>
   # ->   complete(retFuture, result)
@@ -1337,7 +1337,7 @@ macro async*(prc: stmt): stmt {.immediate.} =
   else:
     # -> complete(retFuture)
     procBody.add(newCall(newIdentNode("complete"), retFutureSym))
-  
+
   var closureIterator = newProc(iteratorNameSym, [newIdentNode("FutureBase")],
                                 procBody, nnkIteratorDef)
   closureIterator[4] = newNimNode(nnkPragma, prc[6]).add(newIdentNode("closure"))
@@ -1351,7 +1351,7 @@ macro async*(prc: stmt): stmt {.immediate.} =
 
   # -> return retFuture
   outerProcBody.add newNimNode(nnkReturnStmt, prc[6][prc[6].len-1]).add(retFutureSym)
-  
+
   result = prc
 
   # Remove the 'async' pragma.
@@ -1377,7 +1377,7 @@ proc recvLine*(socket: TAsyncFD): Future[string] {.async.} =
   ## If a full line is read ``\r\L`` is not
   ## added to ``line``, however if solely ``\r\L`` is read then ``line``
   ## will be set to it.
-  ## 
+  ##
   ## If the socket is disconnected, ``line`` will be set to ``""``.
   ##
   ## If the socket is disconnected in the middle of a line (before ``\r\L``
@@ -1388,7 +1388,7 @@ proc recvLine*(socket: TAsyncFD): Future[string] {.async.} =
   ##
   ## **Note**: This procedure is mostly used for testing. You likely want to
   ## use ``asyncnet.recvLine`` instead.
-  
+
   template addNLIfEmpty(): stmt =
     if result.len == 0:
       result.add("\c\L")
diff --git a/lib/pure/asyncfile.nim b/lib/pure/asyncfile.nim
index 752c01eac..844c2ab55 100644
--- a/lib/pure/asyncfile.nim
+++ b/lib/pure/asyncfile.nim
@@ -7,7 +7,7 @@
 #    distribution, for details about the copyright.
 #
 
-## This module implements asynchronous file handling.
+## This module implements asynchronous file reading and writing.
 ##
 ## .. code-block:: Nim
 ##    import asyncfile, asyncdispatch, os
@@ -30,7 +30,7 @@ else:
   import posix
 
 type
-  AsyncFile = ref object
+  AsyncFile* = ref object
     fd: TAsyncFd
     offset: int64
 
diff --git a/lib/pure/collections/sequtils.nim b/lib/pure/collections/sequtils.nim
index e690e8eba..edb904cc6 100644
--- a/lib/pure/collections/sequtils.nim
+++ b/lib/pure/collections/sequtils.nim
@@ -47,6 +47,24 @@ proc concat*[T](seqs: varargs[seq[T]]): seq[T] =
       result[i] = itm
       inc(i)
 
+proc repeat*[T](s: seq[T], n: Natural): seq[T] =
+  ## Returns a new sequence with the items of `s` repeated `n` times.
+  ##
+  ## Example:
+  ##
+  ## .. code-block:
+  ##
+  ##   let
+  ##     s = @[1, 2, 3]
+  ##     total = s.repeat(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 e in s:
+      result[o] = e
+      inc o
+
 proc deduplicate*[T](seq1: seq[T]): seq[T] =
   ## Returns a new sequence without duplicates.
   ##
@@ -86,7 +104,7 @@ proc zip*[S, T](seq1: seq[S], seq2: seq[T]): seq[tuple[a: S, b: T]] =
   newSeq(result, m)
   for i in 0 .. m-1: result[i] = (seq1[i], seq2[i])
 
-proc distribute*[T](s: seq[T], num: int, spread = true): seq[seq[T]] =
+proc distribute*[T](s: seq[T], num: Positive, spread = true): seq[seq[T]] =
   ## Splits and distributes a sequence `s` into `num` sub sequences.
   ##
   ## Returns a sequence of `num` sequences. For some input values this is the
@@ -113,11 +131,12 @@ proc distribute*[T](s: seq[T], num: int, spread = true): seq[seq[T]] =
   ##   assert numbers.distribute(6)[0] == @[1, 2]
   ##   assert numbers.distribute(6)[5] == @[7]
   assert(not s.isNil, "`s` can't be nil")
-  assert(num > 0, "`num` has to be greater than zero")
   if num < 2:
     result = @[s]
     return
 
+  let num = int(num) # XXX probably only needed because of .. bug
+
   # Create the result and calculate the stride size and the remainder if any.
   result = newSeq[seq[T]](num)
   var
@@ -587,4 +606,14 @@ when isMainModule:
     seq2D[0][1] = true
     doAssert seq2D == @[@[true, true], @[true, false], @[false, false], @[false, false]]
 
+  block: # repeat tests
+    let
+      a = @[1, 2, 3]
+      b: seq[int] = @[]
+    
+    doAssert a.repeat(3) == @[1, 2, 3, 1, 2, 3, 1, 2, 3]
+    doAssert a.repeat(0) == @[]
+    #doAssert a.repeat(-1) == @[] # will not compile!
+    doAssert b.repeat(3) == @[]
+
   echo "Finished doc tests"
diff --git a/lib/pure/collections/tables.nim b/lib/pure/collections/tables.nim
index 959688d6a..93a7591ac 100644
--- a/lib/pure/collections/tables.nim
+++ b/lib/pure/collections/tables.nim
@@ -196,7 +196,11 @@ proc mget*[A, B](t: var Table[A, B], key: A): var B =
   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)
+  else:
+    when compiles($key):
+      raise newException(KeyError, "key not found: " & $key)
+    else:
+      raise newException(KeyError, "key not found")
 
 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`.
diff --git a/lib/pure/hashes.nim b/lib/pure/hashes.nim
index 30daaf2dc..a16342d44 100644
--- a/lib/pure/hashes.nim
+++ b/lib/pure/hashes.nim
@@ -33,8 +33,8 @@
 ##  proc hash(x: Something): THash =
 ##    ## Computes a THash from `x`.
 ##    var h: THash = 0
-##    h = h &! hash(x.foo)
-##    h = h &! hash(x.bar)
+##    h = h !& hash(x.foo)
+##    h = h !& hash(x.bar)
 ##    result = !$h
 
 import 
diff --git a/lib/pure/httpclient.nim b/lib/pure/httpclient.nim
index 37af14df3..f11101511 100644
--- a/lib/pure/httpclient.nim
+++ b/lib/pure/httpclient.nim
@@ -390,8 +390,11 @@ proc request*(url: string, httpMethod: string, extraHeaders = "",
   ## server takes longer than specified an ETimeout exception will be raised.
   var r = if proxy == nil: parseUri(url) else: proxy.url
   var headers = substr(httpMethod, len("http"))
+  # TODO: Use generateHeaders further down once it supports proxies.
   if proxy == nil:
-    headers.add(" " & r.path)
+    headers.add ' '
+    if r.path[0] != '/': headers.add '/'
+    headers.add(r.path)
     if r.query.len > 0:
       headers.add("?" & r.query)
   else:
@@ -567,9 +570,12 @@ proc downloadFile*(url: string, outputFilename: string,
 
 proc generateHeaders(r: Uri, httpMethod: string,
                      headers: StringTableRef): string =
+  # TODO: Use this in the blocking HttpClient once it supports proxies.
   result = substr(httpMethod, len("http"))
   # TODO: Proxies
-  result.add(" " & r.path)
+  result.add ' '
+  if r.path[0] != '/': result.add '/'
+  result.add(r.path)
   if r.query.len > 0:
     result.add("?" & r.query)
   result.add(" HTTP/1.1\c\L")
diff --git a/lib/pure/json.nim b/lib/pure/json.nim
index 2038b246d..5041fe2f6 100644
--- a/lib/pure/json.nim
+++ b/lib/pure/json.nim
@@ -816,7 +816,7 @@ proc copy*(p: JsonNode): JsonNode =
 # ------------- pretty printing ----------------------------------------------
 
 proc indent(s: var string, i: int) = 
-  s.add(repeatChar(i))
+  s.add(spaces(i))
 
 proc newIndent(curr, indent: int, ml: bool): int =
   if ml: return curr + indent
diff --git a/lib/pure/lexbase.nim b/lib/pure/lexbase.nim
index a3a3d7b5c..23a87d9f8 100644
--- a/lib/pure/lexbase.nim
+++ b/lib/pure/lexbase.nim
@@ -165,5 +165,5 @@ proc getCurrentLine(L: BaseLexer, marker: bool = true): string =
     inc(i)
   add(result, "\n")
   if marker:
-    add(result, repeatChar(getColNumber(L, L.bufpos)) & "^\n")
+    add(result, spaces(getColNumber(L, L.bufpos)) & "^\n")
 
diff --git a/lib/pure/parsexml.nim b/lib/pure/parsexml.nim
index b957c0cf7..b8f422c31 100644
--- a/lib/pure/parsexml.nim
+++ b/lib/pure/parsexml.nim
@@ -128,6 +128,7 @@ proc open*(my: var XmlParser, input: Stream, filename: string,
   my.kind = xmlError
   my.a = ""
   my.b = ""
+  my.c = ""
   my.options = options
   
 proc close*(my: var XmlParser) {.inline.} = 
@@ -138,43 +139,43 @@ proc kind*(my: XmlParser): XmlEventKind {.inline.} =
   ## returns the current event type for the XML parser
   return my.kind
 
-proc charData*(my: XmlParser): string {.inline.} = 
+template charData*(my: XmlParser): string =
   ## returns the character data for the events: ``xmlCharData``, 
   ## ``xmlWhitespace``, ``xmlComment``, ``xmlCData``, ``xmlSpecial``
   assert(my.kind in {xmlCharData, xmlWhitespace, xmlComment, xmlCData, 
                      xmlSpecial})
-  return my.a
+  my.a
 
-proc elementName*(my: XmlParser): string {.inline.} = 
+template elementName*(my: XmlParser): string =
   ## returns the element name for the events: ``xmlElementStart``, 
   ## ``xmlElementEnd``, ``xmlElementOpen``
   assert(my.kind in {xmlElementStart, xmlElementEnd, xmlElementOpen})
-  return my.a
+  my.a
 
-proc entityName*(my: XmlParser): string {.inline.} = 
+template entityName*(my: XmlParser): string =
   ## returns the entity name for the event: ``xmlEntity``
   assert(my.kind == xmlEntity)
-  return my.a
+  my.a
   
-proc attrKey*(my: XmlParser): string {.inline.} = 
+template attrKey*(my: XmlParser): string =
   ## returns the attribute key for the event ``xmlAttribute``
   assert(my.kind == xmlAttribute)
-  return my.a
+  my.a
   
-proc attrValue*(my: XmlParser): string {.inline.} = 
+template attrValue*(my: XmlParser): string =
   ## returns the attribute value for the event ``xmlAttribute``
   assert(my.kind == xmlAttribute)
-  return my.b
+  my.b
 
-proc piName*(my: XmlParser): string {.inline.} = 
+template piName*(my: XmlParser): string =
   ## returns the processing instruction name for the event ``xmlPI``
   assert(my.kind == xmlPI)
-  return my.a
+  my.a
 
-proc piRest*(my: XmlParser): string {.inline.} = 
+template piRest*(my: XmlParser): string =
   ## returns the rest of the processing instruction for the event ``xmlPI``
   assert(my.kind == xmlPI)
-  return my.b
+  my.b
 
 proc rawData*(my: XmlParser): string {.inline.} =
   ## returns the underlying 'data' string by reference.
@@ -446,13 +447,15 @@ proc parseTag(my: var XmlParser) =
     # an attribute follows:
     my.kind = xmlElementOpen
     my.state = stateAttr
-    my.c = my.a # save for later
+    # save for later:
+    my.c.setLen(my.a.len)
+    my.c[0..my.c.high] = my.a[0..my.a.high]
   else:
     my.kind = xmlElementStart
     if my.buf[my.bufpos] == '/' and my.buf[my.bufpos+1] == '>':
       inc(my.bufpos, 2)
       my.state = stateEmptyElementTag
-      my.c = nil
+      my.c.setLen(0)
     elif my.buf[my.bufpos] == '>':
       inc(my.bufpos)  
     else:
@@ -621,8 +624,9 @@ proc next*(my: var XmlParser) =
   of stateEmptyElementTag:
     my.state = stateNormal
     my.kind = xmlElementEnd
-    if not isNil(my.c):
-      my.a = my.c
+    if my.c.len > 0:
+      my.a.setLen(my.c.len)
+      my.a[0..my.a.high] = my.c[0..my.c.high]
   of stateError: 
     my.kind = xmlError
     my.state = stateNormal
diff --git a/lib/pure/pegs.nim b/lib/pure/pegs.nim
index 419554de5..04c75ecae 100644
--- a/lib/pure/pegs.nim
+++ b/lib/pure/pegs.nim
@@ -29,7 +29,7 @@ when useUnicode:
 const
   InlineThreshold = 5  ## number of leaves; -1 to disable inlining
   MaxSubpatterns* = 20 ## defines the maximum number of subpatterns that
-                       ## can be captured. More subpatterns cannot be captured! 
+                       ## can be captured. More subpatterns cannot be captured!
 
 type
   PegKind = enum
@@ -85,14 +85,14 @@ type
     of pkBackRef..pkBackRefIgnoreStyle: index: range[0..MaxSubpatterns]
     else: sons: seq[TNode]
   NonTerminal* = ref NonTerminalObj
-  
+
   Peg* = TNode ## type that represents a PEG
 
 {.deprecated: [TPeg: Peg].}
 
 proc term*(t: string): Peg {.nosideEffect, rtl, extern: "npegs$1Str".} =
   ## constructs a PEG from a terminal string
-  if t.len != 1:  
+  if t.len != 1:
     result.kind = pkTerminal
     result.term = t
   else:
@@ -116,7 +116,7 @@ proc term*(t: char): Peg {.nosideEffect, rtl, extern: "npegs$1Char".} =
   assert t != '\0'
   result.kind = pkChar
   result.ch = t
-  
+
 proc charSet*(s: set[char]): Peg {.nosideEffect, rtl, extern: "npegs$1".} =
   ## constructs a PEG from a character set `s`
   assert '\0' notin s
@@ -129,12 +129,12 @@ proc add(d: var Peg, s: Peg) {.inline.} = add(d.sons, s)
 
 proc addChoice(dest: var Peg, elem: Peg) =
   var L = dest.len-1
-  if L >= 0 and dest.sons[L].kind == pkCharChoice: 
+  if L >= 0 and dest.sons[L].kind == pkCharChoice:
     # caution! Do not introduce false aliasing here!
     case elem.kind
     of pkCharChoice:
       dest.sons[L] = charSet(dest.sons[L].charChoice[] + elem.charChoice[])
-    of pkChar: 
+    of pkChar:
       dest.sons[L] = charSet(dest.sons[L].charChoice[] + {elem.ch})
     else: add(dest, elem)
   else: add(dest, elem)
@@ -158,12 +158,12 @@ proc `/`*(a: varargs[Peg]): Peg {.
 
 proc addSequence(dest: var Peg, elem: Peg) =
   var L = dest.len-1
-  if L >= 0 and dest.sons[L].kind == pkTerminal: 
+  if L >= 0 and dest.sons[L].kind == pkTerminal:
     # caution! Do not introduce false aliasing here!
     case elem.kind
-    of pkTerminal: 
+    of pkTerminal:
       dest.sons[L] = term(dest.sons[L].term & elem.term)
-    of pkChar: 
+    of pkChar:
       dest.sons[L] = term(dest.sons[L].term & elem.ch)
     else: add(dest, elem)
   else: add(dest, elem)
@@ -172,7 +172,7 @@ proc sequence*(a: varargs[Peg]): Peg {.
   nosideEffect, rtl, extern: "npegs$1".} =
   ## constructs a sequence with all the PEGs from `a`
   multipleOp(pkSequence, addSequence)
- 
+
 proc `?`*(a: Peg): Peg {.nosideEffect, rtl, extern: "npegsOptional".} =
   ## constructs an optional for the PEG `a`
   if a.kind in {pkOption, pkGreedyRep, pkGreedyAny, pkGreedyRepChar,
@@ -207,7 +207,7 @@ proc `!*`*(a: Peg): Peg {.nosideEffect, rtl, extern: "npegsSearch".} =
   result.kind = pkSearch
   result.sons = @[a]
 
-proc `!*\`*(a: Peg): Peg {.noSideEffect, rtl, 
+proc `!*\`*(a: Peg): Peg {.noSideEffect, rtl,
                              extern: "npgegsCapturedSearch".} =
   ## constructs a "captured search" for the PEG `a`
   result.kind = pkCapturedSearch
@@ -216,7 +216,7 @@ proc `!*\`*(a: Peg): Peg {.noSideEffect, rtl,
 proc `+`*(a: Peg): Peg {.nosideEffect, rtl, extern: "npegsGreedyPosRep".} =
   ## constructs a "greedy positive repetition" with the PEG `a`
   return sequence(a, *a)
-  
+
 proc `&`*(a: Peg): Peg {.nosideEffect, rtl, extern: "npegsAndPredicate".} =
   ## constructs an "and predicate" with the PEG `a`
   result.kind = pkAndPredicate
@@ -239,33 +239,33 @@ proc newLine*: Peg {.inline.} =
   ## constructs the PEG `newline`:idx: (``\n``)
   result.kind = pkNewLine
 
-proc unicodeLetter*: Peg {.inline.} = 
+proc unicodeLetter*: Peg {.inline.} =
   ## constructs the PEG ``\letter`` which matches any Unicode letter.
   result.kind = pkLetter
-  
-proc unicodeLower*: Peg {.inline.} = 
+
+proc unicodeLower*: Peg {.inline.} =
   ## constructs the PEG ``\lower`` which matches any Unicode lowercase letter.
-  result.kind = pkLower 
+  result.kind = pkLower
 
-proc unicodeUpper*: Peg {.inline.} = 
+proc unicodeUpper*: Peg {.inline.} =
   ## constructs the PEG ``\upper`` which matches any Unicode uppercase letter.
   result.kind = pkUpper
-  
-proc unicodeTitle*: Peg {.inline.} = 
+
+proc unicodeTitle*: Peg {.inline.} =
   ## constructs the PEG ``\title`` which matches any Unicode title letter.
   result.kind = pkTitle
 
-proc unicodeWhitespace*: Peg {.inline.} = 
-  ## constructs the PEG ``\white`` which matches any Unicode 
+proc unicodeWhitespace*: Peg {.inline.} =
+  ## constructs the PEG ``\white`` which matches any Unicode
   ## whitespace character.
   result.kind = pkWhitespace
 
-proc startAnchor*: Peg {.inline.} = 
-  ## constructs the PEG ``^`` which matches the start of the input.  
+proc startAnchor*: Peg {.inline.} =
+  ## constructs the PEG ``^`` which matches the start of the input.
   result.kind = pkStartAnchor
 
-proc endAnchor*: Peg {.inline.} = 
-  ## constructs the PEG ``$`` which matches the end of the input.  
+proc endAnchor*: Peg {.inline.} =
+  ## constructs the PEG ``$`` which matches the end of the input.
   result = !any()
 
 proc capture*(a: Peg): Peg {.nosideEffect, rtl, extern: "npegsCapture".} =
@@ -274,21 +274,21 @@ proc capture*(a: Peg): Peg {.nosideEffect, rtl, extern: "npegsCapture".} =
   result.sons = @[a]
 
 proc backref*(index: range[1..MaxSubpatterns]): Peg {.
-  nosideEffect, rtl, extern: "npegs$1".} = 
+  nosideEffect, rtl, extern: "npegs$1".} =
   ## constructs a back reference of the given `index`. `index` starts counting
   ## from 1.
   result.kind = pkBackRef
   result.index = index-1
 
 proc backrefIgnoreCase*(index: range[1..MaxSubpatterns]): Peg {.
-  nosideEffect, rtl, extern: "npegs$1".} = 
+  nosideEffect, rtl, extern: "npegs$1".} =
   ## constructs a back reference of the given `index`. `index` starts counting
   ## from 1. Ignores case for matching.
   result.kind = pkBackRefIgnoreCase
   result.index = index-1
 
 proc backrefIgnoreStyle*(index: range[1..MaxSubpatterns]): Peg {.
-  nosideEffect, rtl, extern: "npegs$1".}= 
+  nosideEffect, rtl, extern: "npegs$1".}=
   ## constructs a back reference of the given `index`. `index` starts counting
   ## from 1. Ignores style for matching.
   result.kind = pkBackRefIgnoreStyle
@@ -298,7 +298,7 @@ proc spaceCost(n: Peg): int =
   case n.kind
   of pkEmpty: discard
   of pkTerminal, pkTerminalIgnoreCase, pkTerminalIgnoreStyle, pkChar,
-     pkGreedyRepChar, pkCharChoice, pkGreedyRepSet, 
+     pkGreedyRepChar, pkCharChoice, pkGreedyRepSet,
      pkAny..pkWhitespace, pkGreedyAny:
     result = 1
   of pkNonTerminal:
@@ -310,7 +310,7 @@ proc spaceCost(n: Peg): int =
       if result >= InlineThreshold: break
 
 proc nonterminal*(n: NonTerminal): Peg {.
-  nosideEffect, rtl, extern: "npegs$1".} = 
+  nosideEffect, rtl, extern: "npegs$1".} =
   ## constructs a PEG that consists of the nonterminal symbol
   assert n != nil
   if ntDeclared in n.flags and spaceCost(n.rule) < InlineThreshold:
@@ -331,7 +331,7 @@ proc newNonTerminal*(name: string, line, column: int): NonTerminal {.
 template letters*: expr =
   ## expands to ``charset({'A'..'Z', 'a'..'z'})``
   charSet({'A'..'Z', 'a'..'z'})
-  
+
 template digits*: expr =
   ## expands to ``charset({'0'..'9'})``
   charSet({'0'..'9'})
@@ -339,11 +339,11 @@ template digits*: expr =
 template whitespace*: expr =
   ## expands to ``charset({' ', '\9'..'\13'})``
   charSet({' ', '\9'..'\13'})
-  
+
 template identChars*: expr =
   ## expands to ``charset({'a'..'z', 'A'..'Z', '0'..'9', '_'})``
   charSet({'a'..'z', 'A'..'Z', '0'..'9', '_'})
-  
+
 template identStartChars*: expr =
   ## expands to ``charset({'A'..'Z', 'a'..'z', '_'})``
   charSet({'a'..'z', 'A'..'Z', '_'})
@@ -352,14 +352,14 @@ template ident*: expr =
   ## same as ``[a-zA-Z_][a-zA-z_0-9]*``; standard identifier
   sequence(charSet({'a'..'z', 'A'..'Z', '_'}),
            *charSet({'a'..'z', 'A'..'Z', '0'..'9', '_'}))
-  
+
 template natural*: expr =
   ## same as ``\d+``
   +digits
 
 # ------------------------- debugging -----------------------------------------
 
-proc esc(c: char, reserved = {'\0'..'\255'}): string = 
+proc esc(c: char, reserved = {'\0'..'\255'}): string =
   case c
   of '\b': result = "\\b"
   of '\t': result = "\\t"
@@ -374,38 +374,38 @@ proc esc(c: char, reserved = {'\0'..'\255'}): string =
   elif c < ' ' or c >= '\128': result = '\\' & $ord(c)
   elif c in reserved: result = '\\' & c
   else: result = $c
-  
+
 proc singleQuoteEsc(c: char): string = return "'" & esc(c, {'\''}) & "'"
 
-proc singleQuoteEsc(str: string): string = 
+proc singleQuoteEsc(str: string): string =
   result = "'"
   for c in items(str): add result, esc(c, {'\''})
   add result, '\''
-  
-proc charSetEscAux(cc: set[char]): string = 
+
+proc charSetEscAux(cc: set[char]): string =
   const reserved = {'^', '-', ']'}
   result = ""
   var c1 = 0
-  while c1 <= 0xff: 
-    if chr(c1) in cc: 
+  while c1 <= 0xff:
+    if chr(c1) in cc:
       var c2 = c1
       while c2 < 0xff and chr(succ(c2)) in cc: inc(c2)
-      if c1 == c2: 
+      if c1 == c2:
         add result, esc(chr(c1), reserved)
-      elif c2 == succ(c1): 
+      elif c2 == succ(c1):
         add result, esc(chr(c1), reserved) & esc(chr(c2), reserved)
-      else: 
+      else:
         add result, esc(chr(c1), reserved) & '-' & esc(chr(c2), reserved)
       c1 = c2
     inc(c1)
-  
+
 proc charSetEsc(cc: set[char]): string =
-  if card(cc) >= 128+64: 
+  if card(cc) >= 128+64:
     result = "[^" & charSetEscAux({'\1'..'\xFF'} - cc) & ']'
-  else: 
+  else:
     result = '[' & charSetEscAux(cc) & ']'
-  
-proc toStrAux(r: Peg, res: var string) = 
+
+proc toStrAux(r: Peg, res: var string) =
   case r.kind
   of pkEmpty: add(res, "()")
   of pkAny: add(res, '.')
@@ -469,25 +469,25 @@ proc toStrAux(r: Peg, res: var string) =
     toStrAux(r.sons[0], res)
   of pkCapture:
     add(res, '{')
-    toStrAux(r.sons[0], res)    
+    toStrAux(r.sons[0], res)
     add(res, '}')
-  of pkBackRef: 
+  of pkBackRef:
     add(res, '$')
     add(res, $r.index)
-  of pkBackRefIgnoreCase: 
+  of pkBackRefIgnoreCase:
     add(res, "i$")
     add(res, $r.index)
-  of pkBackRefIgnoreStyle: 
+  of pkBackRefIgnoreStyle:
     add(res, "y$")
     add(res, $r.index)
   of pkRule:
-    toStrAux(r.sons[0], res)    
+    toStrAux(r.sons[0], res)
     add(res, " <- ")
     toStrAux(r.sons[1], res)
   of pkList:
     for i in 0 .. high(r.sons):
       toStrAux(r.sons[i], res)
-      add(res, "\n")  
+      add(res, "\n")
   of pkStartAnchor:
     add(res, '^')
 
@@ -506,8 +506,8 @@ type
 
 {.deprecated: [TCaptures: Captures].}
 
-proc bounds*(c: Captures, 
-             i: range[0..MaxSubpatterns-1]): tuple[first, last: int] = 
+proc bounds*(c: Captures,
+             i: range[0..MaxSubpatterns-1]): tuple[first, last: int] =
   ## returns the bounds ``[first..last]`` of the `i`'th capture.
   result = c.matches[i]
 
@@ -527,7 +527,7 @@ when not useUnicode:
 
 proc rawMatch*(s: string, p: Peg, start: int, c: var Captures): int {.
                nosideEffect, rtl, extern: "npegs$1".} =
-  ## low-level matching proc that implements the PEG interpreter. Use this 
+  ## low-level matching proc that implements the PEG interpreter. Use this
   ## for maximum efficiency (every other PEG operation ends up calling this
   ## proc).
   ## Returns -1 if it does not match, else the length of the match
@@ -541,7 +541,7 @@ proc rawMatch*(s: string, p: Peg, start: int, c: var Captures): int {.
       result = runeLenAt(s, start)
     else:
       result = -1
-  of pkLetter: 
+  of pkLetter:
     if s[start] != '\0':
       var a: Rune
       result = start
@@ -550,7 +550,7 @@ proc rawMatch*(s: string, p: Peg, start: int, c: var Captures): int {.
       else: result = -1
     else:
       result = -1
-  of pkLower: 
+  of pkLower:
     if s[start] != '\0':
       var a: Rune
       result = start
@@ -559,7 +559,7 @@ proc rawMatch*(s: string, p: Peg, start: int, c: var Captures): int {.
       else: result = -1
     else:
       result = -1
-  of pkUpper: 
+  of pkUpper:
     if s[start] != '\0':
       var a: Rune
       result = start
@@ -568,16 +568,16 @@ proc rawMatch*(s: string, p: Peg, start: int, c: var Captures): int {.
       else: result = -1
     else:
       result = -1
-  of pkTitle: 
+  of pkTitle:
     if s[start] != '\0':
       var a: Rune
       result = start
       fastRuneAt(s, result, a)
-      if isTitle(a): dec(result, start) 
+      if isTitle(a): dec(result, start)
       else: result = -1
     else:
       result = -1
-  of pkWhitespace: 
+  of pkWhitespace:
     if s[start] != '\0':
       var a: Rune
       result = start
@@ -641,7 +641,7 @@ proc rawMatch*(s: string, p: Peg, start: int, c: var Captures): int {.
     when false: echo "leave: ", p.nt.name
     if result < 0: c.ml = oldMl
   of pkSequence:
-    var oldMl = c.ml  
+    var oldMl = c.ml
     result = 0
     for i in 0..high(p.sons):
       var x = rawMatch(s, p.sons[i], start+result, c)
@@ -723,11 +723,11 @@ proc rawMatch*(s: string, p: Peg, start: int, c: var Captures): int {.
       #else: silently ignore the capture
     else:
       c.ml = idx
-  of pkBackRef..pkBackRefIgnoreStyle: 
+  of pkBackRef..pkBackRefIgnoreStyle:
     if p.index >= c.ml: return -1
     var (a, b) = c.matches[p.index]
     var n: Peg
-    n.kind = succ(pkTerminal, ord(p.kind)-ord(pkBackRef)) 
+    n.kind = succ(pkTerminal, ord(p.kind)-ord(pkBackRef))
     n.term = s.substr(a, b)
     result = rawMatch(s, n, start, c)
   of pkStartAnchor:
@@ -755,7 +755,7 @@ proc match*(s: string, pattern: Peg, matches: var openArray[string],
   result = rawMatch(s, pattern, start, c) == len(s) - start
   if result: fillMatches(s, matches, c)
 
-proc match*(s: string, pattern: Peg, 
+proc match*(s: string, pattern: Peg,
             start = 0): bool {.nosideEffect, rtl, extern: "npegs$1".} =
   ## returns ``true`` if ``s`` matches the ``pattern`` beginning from ``start``.
   var c: Captures
@@ -773,7 +773,7 @@ proc matchLen*(s: string, pattern: Peg, matches: var openArray[string],
   result = rawMatch(s, pattern, start, c)
   if result >= 0: fillMatches(s, matches, c)
 
-proc matchLen*(s: string, pattern: Peg, 
+proc matchLen*(s: string, pattern: Peg,
                start = 0): int {.nosideEffect, rtl, extern: "npegs$1".} =
   ## the same as ``match``, but it returns the length of the match,
   ## if there is no match, -1 is returned. Note that a match length
@@ -797,11 +797,11 @@ proc find*(s: string, pattern: Peg, matches: var openArray[string],
       return i
   return -1
   # could also use the pattern here: (!P .)* P
-  
+
 proc findBounds*(s: string, pattern: Peg, matches: var openArray[string],
                  start = 0): tuple[first, last: int] {.
                  nosideEffect, rtl, extern: "npegs$1Capture".} =
-  ## returns the starting position and end position of ``pattern`` in ``s`` 
+  ## returns the starting position and end position of ``pattern`` in ``s``
   ## and the captured
   ## substrings in the array ``matches``. If it does not match, nothing
   ## is written into ``matches`` and (-1,0) is returned.
@@ -814,8 +814,8 @@ proc findBounds*(s: string, pattern: Peg, matches: var openArray[string],
       fillMatches(s, matches, c)
       return (i, i+L-1)
   return (-1, 0)
-  
-proc find*(s: string, pattern: Peg, 
+
+proc find*(s: string, pattern: Peg,
            start = 0): int {.nosideEffect, rtl, extern: "npegs$1".} =
   ## returns the starting position of ``pattern`` in ``s``. If it does not
   ## match, -1 is returned.
@@ -824,8 +824,8 @@ proc find*(s: string, pattern: Peg,
   for i in start .. s.len-1:
     if rawMatch(s, pattern, i, c) >= 0: return i
   return -1
-  
-iterator findAll*(s: string, pattern: Peg, start = 0): string = 
+
+iterator findAll*(s: string, pattern: Peg, start = 0): string =
   ## yields all matching *substrings* of `s` that match `pattern`.
   var c: Captures
   c.origStart = start
@@ -838,23 +838,23 @@ iterator findAll*(s: string, pattern: Peg, start = 0): string =
     else:
       yield substr(s, i, i+L-1)
       inc(i, L)
-    
+
 proc findAll*(s: string, pattern: Peg, start = 0): seq[string] {.
-  nosideEffect, rtl, extern: "npegs$1".} = 
+  nosideEffect, rtl, extern: "npegs$1".} =
   ## returns all matching *substrings* of `s` that match `pattern`.
   ## If it does not match, @[] is returned.
   accumulateResult(findAll(s, pattern, start))
 
 when not defined(nimhygiene):
   {.pragma: inject.}
-  
+
 template `=~`*(s: string, pattern: Peg): bool =
-  ## This calls ``match`` with an implicit declared ``matches`` array that 
-  ## can be used in the scope of the ``=~`` call: 
-  ## 
+  ## This calls ``match`` with an implicit declared ``matches`` array that
+  ## can be used in the scope of the ``=~`` call:
+  ##
   ## .. code-block:: nim
   ##
-  ##   if line =~ peg"\s* {\w+} \s* '=' \s* {\w+}": 
+  ##   if line =~ peg"\s* {\w+} \s* '=' \s* {\w+}":
   ##     # matches a key=value pair:
   ##     echo("Key: ", matches[0])
   ##     echo("Value: ", matches[1])
@@ -865,7 +865,7 @@ template `=~`*(s: string, pattern: Peg): bool =
   ##     echo("comment: ", matches[0])
   ##   else:
   ##     echo("syntax error")
-  ##  
+  ##
   bind MaxSubpatterns
   when not declaredInScope(matches):
     var matches {.inject.}: array[0..MaxSubpatterns-1, string]
@@ -902,7 +902,7 @@ proc replacef*(s: string, sub: Peg, by: string): string {.
   ## with the notation ``$i`` and ``$#`` (see strutils.`%`). Examples:
   ##
   ## .. code-block:: nim
-  ##   "var1=key; var2=key2".replace(peg"{\ident}'='{\ident}", "$1<-$2$2")
+  ##   "var1=key; var2=key2".replacef(peg"{\ident}'='{\ident}", "$1<-$2$2")
   ##
   ## Results in:
   ##
@@ -941,10 +941,10 @@ proc replace*(s: string, sub: Peg, by = ""): string {.
       add(result, by)
       inc(i, x)
   add(result, substr(s, i))
-  
+
 proc parallelReplace*(s: string, subs: varargs[
                       tuple[pattern: Peg, repl: string]]): string {.
-                      nosideEffect, rtl, extern: "npegs$1".} = 
+                      nosideEffect, rtl, extern: "npegs$1".} =
   ## Returns a modified copy of `s` with the substitutions in `subs`
   ## applied in parallel.
   result = ""
@@ -964,8 +964,8 @@ proc parallelReplace*(s: string, subs: varargs[
       add(result, s[i])
       inc(i)
   # copy the rest:
-  add(result, substr(s, i))  
-  
+  add(result, substr(s, i))
+
 proc transformFile*(infile, outfile: string,
                     subs: varargs[tuple[pattern: Peg, repl: string]]) {.
                     rtl, extern: "npegs$1".} =
@@ -974,7 +974,7 @@ proc transformFile*(infile, outfile: string,
   ## error occurs. This is supposed to be used for quick scripting.
   var x = readFile(infile).string
   writeFile(outfile, x.parallelReplace(subs))
-  
+
 iterator split*(s: string, sep: Peg): string =
   ## Splits the string `s` into substrings.
   ##
@@ -1049,14 +1049,14 @@ type
     tkBackref,          ## '$'
     tkDollar,           ## '$'
     tkHat               ## '^'
-  
+
   TToken {.final.} = object  ## a token
     kind: TTokKind           ## the type of the token
     modifier: TModifier
     literal: string          ## the parsed (string) literal
     charset: set[char]       ## if kind == tkCharSet
     index: int               ## if kind == tkBackref
-  
+
   PegLexer {.inheritable.} = object          ## the lexer object.
     bufpos: int               ## the current position within the buffer
     buf: cstring              ## the buffer itself
@@ -1086,7 +1086,7 @@ proc handleLF(L: var PegLexer, pos: int): int =
   result = pos+1
   L.lineStart = result
 
-proc init(L: var PegLexer, input, filename: string, line = 1, col = 0) = 
+proc init(L: var PegLexer, input, filename: string, line = 1, col = 0) =
   L.buf = input
   L.bufpos = 0
   L.lineNumber = line
@@ -1094,69 +1094,69 @@ proc init(L: var PegLexer, input, filename: string, line = 1, col = 0) =
   L.lineStart = 0
   L.filename = filename
 
-proc getColumn(L: PegLexer): int {.inline.} = 
+proc getColumn(L: PegLexer): int {.inline.} =
   result = abs(L.bufpos - L.lineStart) + L.colOffset
 
-proc getLine(L: PegLexer): int {.inline.} = 
+proc getLine(L: PegLexer): int {.inline.} =
   result = L.lineNumber
-  
+
 proc errorStr(L: PegLexer, msg: string, line = -1, col = -1): string =
   var line = if line < 0: getLine(L) else: line
   var col = if col < 0: getColumn(L) else: col
   result = "$1($2, $3) Error: $4" % [L.filename, $line, $col, msg]
 
-proc handleHexChar(c: var PegLexer, xi: var int) = 
+proc handleHexChar(c: var PegLexer, xi: var int) =
   case c.buf[c.bufpos]
-  of '0'..'9': 
+  of '0'..'9':
     xi = (xi shl 4) or (ord(c.buf[c.bufpos]) - ord('0'))
     inc(c.bufpos)
-  of 'a'..'f': 
+  of 'a'..'f':
     xi = (xi shl 4) or (ord(c.buf[c.bufpos]) - ord('a') + 10)
     inc(c.bufpos)
-  of 'A'..'F': 
+  of 'A'..'F':
     xi = (xi shl 4) or (ord(c.buf[c.bufpos]) - ord('A') + 10)
     inc(c.bufpos)
   else: discard
 
-proc getEscapedChar(c: var PegLexer, tok: var TToken) = 
+proc getEscapedChar(c: var PegLexer, tok: var TToken) =
   inc(c.bufpos)
   case c.buf[c.bufpos]
-  of 'r', 'R', 'c', 'C': 
+  of 'r', 'R', 'c', 'C':
     add(tok.literal, '\c')
     inc(c.bufpos)
-  of 'l', 'L': 
+  of 'l', 'L':
     add(tok.literal, '\L')
     inc(c.bufpos)
-  of 'f', 'F': 
+  of 'f', 'F':
     add(tok.literal, '\f')
     inc(c.bufpos)
-  of 'e', 'E': 
+  of 'e', 'E':
     add(tok.literal, '\e')
     inc(c.bufpos)
-  of 'a', 'A': 
+  of 'a', 'A':
     add(tok.literal, '\a')
     inc(c.bufpos)
-  of 'b', 'B': 
+  of 'b', 'B':
     add(tok.literal, '\b')
     inc(c.bufpos)
-  of 'v', 'V': 
+  of 'v', 'V':
     add(tok.literal, '\v')
     inc(c.bufpos)
-  of 't', 'T': 
+  of 't', 'T':
     add(tok.literal, '\t')
     inc(c.bufpos)
-  of 'x', 'X': 
+  of 'x', 'X':
     inc(c.bufpos)
     var xi = 0
     handleHexChar(c, xi)
     handleHexChar(c, xi)
     if xi == 0: tok.kind = tkInvalid
     else: add(tok.literal, chr(xi))
-  of '0'..'9': 
+  of '0'..'9':
     var val = ord(c.buf[c.bufpos]) - ord('0')
     inc(c.bufpos)
     var i = 1
-    while (i <= 3) and (c.buf[c.bufpos] in {'0'..'9'}): 
+    while (i <= 3) and (c.buf[c.bufpos] in {'0'..'9'}):
       val = val * 10 + ord(c.buf[c.bufpos]) - ord('0')
       inc(c.bufpos)
       inc(i)
@@ -1169,32 +1169,32 @@ proc getEscapedChar(c: var PegLexer, tok: var TToken) =
   else:
     add(tok.literal, c.buf[c.bufpos])
     inc(c.bufpos)
-  
-proc skip(c: var PegLexer) = 
+
+proc skip(c: var PegLexer) =
   var pos = c.bufpos
   var buf = c.buf
-  while true: 
+  while true:
     case buf[pos]
-    of ' ', '\t': 
+    of ' ', '\t':
       inc(pos)
     of '#':
       while not (buf[pos] in {'\c', '\L', '\0'}): inc(pos)
     of '\c':
       pos = handleCR(c, pos)
       buf = c.buf
-    of '\L': 
+    of '\L':
       pos = handleLF(c, pos)
       buf = c.buf
-    else: 
+    else:
       break                   # EndOfFile also leaves the loop
   c.bufpos = pos
-  
-proc getString(c: var PegLexer, tok: var TToken) = 
+
+proc getString(c: var PegLexer, tok: var TToken) =
   tok.kind = tkStringLit
   var pos = c.bufpos + 1
   var buf = c.buf
   var quote = buf[pos-1]
-  while true: 
+  while true:
     case buf[pos]
     of '\\':
       c.bufpos = pos
@@ -1205,13 +1205,13 @@ proc getString(c: var PegLexer, tok: var TToken) =
       break
     elif buf[pos] == quote:
       inc(pos)
-      break      
+      break
     else:
       add(tok.literal, buf[pos])
       inc(pos)
   c.bufpos = pos
-  
-proc getDollar(c: var PegLexer, tok: var TToken) = 
+
+proc getDollar(c: var PegLexer, tok: var TToken) =
   var pos = c.bufpos + 1
   var buf = c.buf
   if buf[pos] in {'0'..'9'}:
@@ -1223,8 +1223,8 @@ proc getDollar(c: var PegLexer, tok: var TToken) =
   else:
     tok.kind = tkDollar
   c.bufpos = pos
-  
-proc getCharSet(c: var PegLexer, tok: var TToken) = 
+
+proc getCharSet(c: var PegLexer, tok: var TToken) =
   tok.kind = tkCharSet
   tok.charset = {}
   var pos = c.bufpos + 1
@@ -1247,7 +1247,7 @@ proc getCharSet(c: var PegLexer, tok: var TToken) =
     of '\C', '\L', '\0':
       tok.kind = tkInvalid
       break
-    else: 
+    else:
       ch = buf[pos]
       inc(pos)
     incl(tok.charset, ch)
@@ -1267,18 +1267,18 @@ proc getCharSet(c: var PegLexer, tok: var TToken) =
         of '\C', '\L', '\0':
           tok.kind = tkInvalid
           break
-        else: 
+        else:
           ch2 = buf[pos]
           inc(pos)
         for i in ord(ch)+1 .. ord(ch2):
           incl(tok.charset, chr(i))
   c.bufpos = pos
   if caret: tok.charset = {'\1'..'\xFF'} - tok.charset
-  
-proc getSymbol(c: var PegLexer, tok: var TToken) = 
+
+proc getSymbol(c: var PegLexer, tok: var TToken) =
   var pos = c.bufpos
   var buf = c.buf
-  while true: 
+  while true:
     add(tok.literal, buf[pos])
     inc(pos)
     if buf[pos] notin strutils.IdentChars: break
@@ -1294,7 +1294,7 @@ proc getBuiltin(c: var PegLexer, tok: var TToken) =
     tok.kind = tkEscaped
     getEscapedChar(c, tok) # may set tok.kind to tkInvalid
 
-proc getTok(c: var PegLexer, tok: var TToken) = 
+proc getTok(c: var PegLexer, tok: var TToken) =
   tok.kind = tkInvalid
   tok.modifier = modNone
   setLen(tok.literal, 0)
@@ -1309,11 +1309,11 @@ proc getTok(c: var PegLexer, tok: var TToken) =
     else:
       tok.kind = tkCurlyLe
       add(tok.literal, '{')
-  of '}': 
+  of '}':
     tok.kind = tkCurlyRi
     inc(c.bufpos)
     add(tok.literal, '}')
-  of '[': 
+  of '[':
     getCharSet(c, tok)
   of '(':
     tok.kind = tkParLe
@@ -1323,7 +1323,7 @@ proc getTok(c: var PegLexer, tok: var TToken) =
     tok.kind = tkParRi
     inc(c.bufpos)
     add(tok.literal, ')')
-  of '.': 
+  of '.':
     tok.kind = tkAny
     inc(c.bufpos)
     add(tok.literal, '.')
@@ -1331,16 +1331,16 @@ proc getTok(c: var PegLexer, tok: var TToken) =
     tok.kind = tkAnyRune
     inc(c.bufpos)
     add(tok.literal, '_')
-  of '\\': 
+  of '\\':
     getBuiltin(c, tok)
   of '\'', '"': getString(c, tok)
   of '$': getDollar(c, tok)
-  of '\0': 
+  of '\0':
     tok.kind = tkEof
     tok.literal = "[EOF]"
   of 'a'..'z', 'A'..'Z', '\128'..'\255':
     getSymbol(c, tok)
-    if c.buf[c.bufpos] in {'\'', '"'} or 
+    if c.buf[c.bufpos] in {'\'', '"'} or
         c.buf[c.bufpos] == '$' and c.buf[c.bufpos+1] in {'0'..'9'}:
       case tok.literal
       of "i": tok.modifier = modIgnoreCase
@@ -1388,7 +1388,7 @@ proc getTok(c: var PegLexer, tok: var TToken) =
     tok.kind = tkAt
     inc(c.bufpos)
     add(tok.literal, '@')
-    if c.buf[c.bufpos] == '@': 
+    if c.buf[c.bufpos] == '@':
       tok.kind = tkCurlyAt
       inc(c.bufpos)
       add(tok.literal, '@')
@@ -1407,7 +1407,7 @@ proc arrowIsNextTok(c: PegLexer): bool =
   result = c.buf[pos] == '<' and c.buf[pos+1] == '-'
 
 # ----------------------------- parser ----------------------------------------
-    
+
 type
   EInvalidPeg* = object of ValueError ## raised if an invalid
                                          ## PEG has been detected
@@ -1425,7 +1425,7 @@ proc pegError(p: PegParser, msg: string, line = -1, col = -1) =
   e.msg = errorStr(p, msg, line, col)
   raise e
 
-proc getTok(p: var PegParser) = 
+proc getTok(p: var PegParser) =
   getTok(p, p.tok)
   if p.tok.kind == tkInvalid: pegError(p, "invalid token")
 
@@ -1475,7 +1475,7 @@ proc builtin(p: var PegParser): Peg =
   of "white": result = unicodeWhitespace()
   else: pegError(p, "unknown built-in: " & p.tok.literal)
 
-proc token(terminal: Peg, p: PegParser): Peg = 
+proc token(terminal: Peg, p: PegParser): Peg =
   if p.skip.kind == pkEmpty: result = terminal
   else: result = sequence(p.skip, terminal)
 
@@ -1496,7 +1496,7 @@ proc primary(p: var PegParser): Peg =
   else: discard
   case p.tok.kind
   of tkIdentifier:
-    if p.identIsVerbatim: 
+    if p.identIsVerbatim:
       var m = p.tok.modifier
       if m == modNone: m = p.modifier
       result = modifiedTerm(p.tok.literal, m).token(p)
@@ -1539,17 +1539,17 @@ proc primary(p: var PegParser): Peg =
   of tkEscaped:
     result = term(p.tok.literal[0]).token(p)
     getTok(p)
-  of tkDollar: 
+  of tkDollar:
     result = endAnchor()
     getTok(p)
-  of tkHat: 
+  of tkHat:
     result = startAnchor()
     getTok(p)
   of tkBackref:
     var m = p.tok.modifier
     if m == modNone: m = p.modifier
     result = modifiedBackref(p.tok.index, m).token(p)
-    if p.tok.index < 0 or p.tok.index > p.captures: 
+    if p.tok.index < 0 or p.tok.index > p.captures:
       pegError(p, "invalid back reference index: " & $p.tok.index)
     getTok(p)
   else:
@@ -1573,7 +1573,7 @@ proc seqExpr(p: var PegParser): Peg =
   while true:
     case p.tok.kind
     of tkAmp, tkNot, tkAt, tkStringLit, tkCharSet, tkParLe, tkCurlyLe,
-       tkAny, tkAnyRune, tkBuiltin, tkEscaped, tkDollar, tkBackref, 
+       tkAny, tkAnyRune, tkBuiltin, tkEscaped, tkDollar, tkBackref,
        tkHat, tkCurlyAt:
       result = sequence(result, primary(p))
     of tkIdentifier:
@@ -1587,7 +1587,7 @@ proc parseExpr(p: var PegParser): Peg =
   while p.tok.kind == tkBar:
     getTok(p)
     result = result / seqExpr(p)
-  
+
 proc parseRule(p: var PegParser): NonTerminal =
   if p.tok.kind == tkIdentifier and arrowIsNextTok(p):
     result = getNonTerminal(p, p.tok.literal)
@@ -1601,7 +1601,7 @@ proc parseRule(p: var PegParser): NonTerminal =
     incl(result.flags, ntDeclared) # NOW inlining may be attempted
   else:
     pegError(p, "rule expected, but found: " & p.tok.literal)
-  
+
 proc rawParse(p: var PegParser): Peg =
   ## parses a rule or a PEG expression
   while p.tok.kind == tkBuiltin:
@@ -1680,7 +1680,7 @@ when isMainModule:
   assert(not match("W_HI_L", peg"\y 'while'"))
   assert(not match("W_HI_Le", peg"\y v'while'"))
   assert match("W_HI_Le", peg"y'while'")
-  
+
   assert($ +digits == $peg"\d+")
   assert "0158787".match(peg"\d+")
   assert "ABC 0232".match(peg"\w+\s+\d+")
@@ -1693,14 +1693,14 @@ when isMainModule:
 
   var pattern = sequence(ident, *whitespace, term('='), *whitespace, ident)
   assert matchLen("key1=  cal9", pattern) == 11
-  
+
   var ws = newNonTerminal("ws", 1, 1)
   ws.rule = *whitespace
-  
+
   var expr = newNonTerminal("expr", 1, 1)
   expr.rule = sequence(capture(ident), *sequence(
                 nonterminal(ws), term('+'), nonterminal(ws), nonterminal(expr)))
-  
+
   var c: Captures
   var s = "a+b +  c +d+e+f"
   assert rawMatch(s, expr.rule, 0, c) == len(s)
@@ -1722,7 +1722,7 @@ when isMainModule:
     assert matches[0] == "abc"
   else:
     assert false
-  
+
   var g2 = peg"""S <- A B / C D
                  A <- 'a'+
                  B <- 'b'+
@@ -1753,13 +1753,13 @@ when isMainModule:
 
   for x in findAll("abcdef", peg"^{.}", 3):
     assert x == "d"
-    
+
   if "f(a, b)" =~ peg"{[0-9]+} / ({\ident} '(' {@} ')')":
     assert matches[0] == "f"
     assert matches[1] == "a, b"
   else:
     assert false
-  
+
   assert match("eine übersicht und außerdem", peg"(\letter \white*)+")
   # ß is not a lower cased letter?!
   assert match("eine übersicht und auerdem", peg"(\lower \white*)+")
diff --git a/lib/pure/redis.nim b/lib/pure/redis.nim
index 52d81b3a4..64d3e1470 100644
--- a/lib/pure/redis.nim
+++ b/lib/pure/redis.nim
@@ -798,6 +798,22 @@ proc zunionstore*(r: Redis, destination: string, numkeys: string,
   
   return r.readInteger()
 
+# HyperLogLog
+
+proc pfadd*(r: Redis, key: string, elements: varargs[string]): RedisInteger = 
+  ## Add variable number of elements into special 'HyperLogLog' set type
+  r.sendCommand("PFADD", key, elements)
+  return r.readInteger()
+
+proc pfcount*(r: Redis, key: string): RedisInteger =
+  ## Count approximate number of elements in 'HyperLogLog'
+  r.sendCommand("PFCOUNT", key)
+  return r.readInteger()
+
+proc pfmerge*(r: Redis, destination: string, sources: varargs[string]) =
+  ## Merge several source HyperLogLog's into one specified by destKey
+  r.sendCommand("PFMERGE", destination, sources)
+  raiseNoOK(r.readStatus(), r.pipeline.enabled)
 
 # Pub/Sub
 
diff --git a/lib/pure/streams.nim b/lib/pure/streams.nim
index 67c80e592..e706f2016 100644
--- a/lib/pure/streams.nim
+++ b/lib/pure/streams.nim
@@ -224,10 +224,12 @@ proc ssReadData(s: Stream, buffer: pointer, bufLen: int): int =
 
 proc ssWriteData(s: Stream, buffer: pointer, bufLen: int) = 
   var s = StringStream(s)
-  if bufLen > 0: 
-    setLen(s.data, s.data.len + bufLen)
-    copyMem(addr(s.data[s.pos]), buffer, bufLen)
-    inc(s.pos, bufLen)
+  if bufLen <= 0:
+    return
+  if s.pos + bufLen > s.data.len:
+    setLen(s.data, s.pos + bufLen)
+  copyMem(addr(s.data[s.pos]), buffer, bufLen)
+  inc(s.pos, bufLen)
 
 proc ssClose(s: Stream) =
   var s = StringStream(s)
diff --git a/lib/pure/terminal.nim b/lib/pure/terminal.nim
index e0e2aa247..df637dcb6 100644
--- a/lib/pure/terminal.nim
+++ b/lib/pure/terminal.nim
@@ -45,7 +45,6 @@ when defined(windows):
   var
     oldAttr = getAttributes()
 
-  proc winGetch(): cint {.header: "<conio.h>", importc: "_getch".}
 else:
   import termios, unsigned
 
@@ -344,7 +343,7 @@ proc isatty*(f: File): bool =
   else:
     proc isatty(fildes: FileHandle): cint {.
       importc: "_isatty", header: "<io.h>".}
-  
+
   result = isatty(getFileHandle(f)) != 0'i32
 
 proc styledEchoProcessArg(s: string) = write stdout, s
@@ -364,12 +363,11 @@ macro styledEcho*(m: varargs[expr]): stmt =
   result.add(newCall(bindSym"write", bindSym"stdout", newStrLitNode("\n")))
   result.add(newCall(bindSym"resetAttributes"))
 
-proc getch*(): char =
-  ## Read a single character from the terminal, blocking until it is entered.
-  ## The character is not printed to the terminal.
-  when defined(windows):
-    result = winGetch().char
-  else:
+when not defined(windows):
+  proc getch*(): char =
+    ## Read a single character from the terminal, blocking until it is entered.
+    ## The character is not printed to the terminal. This is not available for
+    ## Windows.
     let fd = getFileHandle(stdin)
     var oldMode: Termios
     discard fd.tcgetattr(addr oldMode)
@@ -387,5 +385,5 @@ when isMainModule:
   setForeGroundColor(fgBlue)
   writeln(stdout, "ordinary text")
 
-  styledEcho("styled text ", {styleBright, styleBlink, styleUnderscore}) 
-  
+  styledEcho("styled text ", {styleBright, styleBlink, styleUnderscore})
+
diff --git a/lib/pure/times.nim b/lib/pure/times.nim
index e32ea786a..c39667611 100644
--- a/lib/pure/times.nim
+++ b/lib/pure/times.nim
@@ -628,25 +628,25 @@ proc formatToken(info: TimeInfo, token: string, buf: var string) =
     var fr = ($info.year).len()-2
     if fr < 0: fr = 0
     var fyear = ($info.year)[fr .. ($info.year).len()-1]
-    if fyear.len != 2: fyear = repeatChar(2-fyear.len(), '0') & fyear
+    if fyear.len != 2: fyear = repeat('0', 2-fyear.len()) & fyear
     buf.add(fyear)
   of "yyy":
     var fr = ($info.year).len()-3
     if fr < 0: fr = 0
     var fyear = ($info.year)[fr .. ($info.year).len()-1]
-    if fyear.len != 3: fyear = repeatChar(3-fyear.len(), '0') & fyear
+    if fyear.len != 3: fyear = repeat('0', 3-fyear.len()) & fyear
     buf.add(fyear)
   of "yyyy":
     var fr = ($info.year).len()-4
     if fr < 0: fr = 0
     var fyear = ($info.year)[fr .. ($info.year).len()-1]
-    if fyear.len != 4: fyear = repeatChar(4-fyear.len(), '0') & fyear
+    if fyear.len != 4: fyear = repeat('0', 4-fyear.len()) & fyear
     buf.add(fyear)
   of "yyyyy":
     var fr = ($info.year).len()-5
     if fr < 0: fr = 0
     var fyear = ($info.year)[fr .. ($info.year).len()-1]
-    if fyear.len != 5: fyear = repeatChar(5-fyear.len(), '0') & fyear
+    if fyear.len != 5: fyear = repeat('0', 5-fyear.len()) & fyear
     buf.add(fyear)
   of "z":
     let hrs = (info.timezone div 60) div 60
diff --git a/lib/pure/unicode.nim b/lib/pure/unicode.nim
index 42e6a3195..a6f8f916b 100644
--- a/lib/pure/unicode.nim
+++ b/lib/pure/unicode.nim
@@ -118,21 +118,35 @@ proc toUTF8*(c: Rune): string {.rtl, extern: "nuc$1".} =
   elif i <=% 0x07FF:
     result = newString(2)
     result[0] = chr((i shr 6) or 0b110_00000)
-    result[1] = chr((i and ones(6)) or 0b10_000000)
+    result[1] = chr((i and ones(6)) or 0b10_0000_00)
   elif i <=% 0xFFFF:
     result = newString(3)
     result[0] = chr(i shr 12 or 0b1110_0000)
     result[1] = chr(i shr 6 and ones(6) or 0b10_0000_00)
     result[2] = chr(i and ones(6) or 0b10_0000_00)
-  elif i <=% 0x0010FFFF:
+  elif i <=% 0x001FFFFF:
     result = newString(4)
     result[0] = chr(i shr 18 or 0b1111_0000)
     result[1] = chr(i shr 12 and ones(6) or 0b10_0000_00)
     result[2] = chr(i shr 6 and ones(6) or 0b10_0000_00)
     result[3] = chr(i and ones(6) or 0b10_0000_00)
+  elif i <=% 0x03FFFFFF:
+    result = newString(5)
+    result[0] = chr(i shr 24 or 0b111110_00)
+    result[1] = chr(i shr 18 and ones(6) or 0b10_0000_00)
+    result[2] = chr(i shr 12 and ones(6) or 0b10_0000_00)
+    result[3] = chr(i shr 6 and ones(6) or 0b10_0000_00)
+    result[4] = chr(i and ones(6) or 0b10_0000_00)
+  elif i <=% 0x7FFFFFFF:
+    result = newString(6)
+    result[0] = chr(i shr 30 or 0b1111110_0)
+    result[1] = chr(i shr 24 and ones(6) or 0b10_0000_00)
+    result[2] = chr(i shr 18 and ones(6) or 0b10_0000_00)
+    result[3] = chr(i shr 12 and ones(6) or 0b10_0000_00)
+    result[4] = chr(i shr 6 and ones(6) or 0b10_0000_00)
+    result[5] = chr(i and ones(6) or 0b10_0000_00)
   else:
-    result = newString(1)
-    result[0] = chr(i)
+    discard # error, exception?
 
 proc `$`*(rune: Rune): string =
   ## converts a rune to a string
diff --git a/lib/pure/uri.nim b/lib/pure/uri.nim
index 9a6e273a8..b0afb75f9 100644
--- a/lib/pure/uri.nim
+++ b/lib/pure/uri.nim
@@ -286,6 +286,16 @@ proc `$`*(u: Uri): string =
 
 when isMainModule:
   block:
+    let str = "http://localhost"
+    let test = parseUri(str)
+    doAssert test.path == ""
+
+  block:
+    let str = "http://localhost/"
+    let test = parseUri(str)
+    doAssert test.path == "/"
+
+  block:
     let str = "http://localhost:8080/test"
     let test = parseUri(str)
     doAssert test.scheme == "http"
diff --git a/lib/pure/xmldom.nim b/lib/pure/xmldom.nim
index 2e55ff182..6242e589e 100644
--- a/lib/pure/xmldom.nim
+++ b/lib/pure/xmldom.nim
@@ -1083,7 +1083,7 @@ proc addEscaped(s: string): string =
     else: result.add(c)
 
 proc nodeToXml(n: PNode, indent: int = 0): string =
-  result = repeatChar(indent, ' ') & "<" & n.nodeName
+  result = spaces(indent) & "<" & n.nodeName
   if not isNil(n.attributes):
     for i in items(n.attributes):
       result.add(" " & i.name & "=\"" & addEscaped(i.value) & "\"")
@@ -1098,23 +1098,23 @@ proc nodeToXml(n: PNode, indent: int = 0): string =
       of ElementNode:
         result.add(nodeToXml(i, indent + 2))
       of TextNode:
-        result.add(repeatChar(indent * 2, ' '))
+        result.add(spaces(indent * 2))
         result.add(addEscaped(i.nodeValue))
       of CDataSectionNode:
-        result.add(repeatChar(indent * 2, ' '))
+        result.add(spaces(indent * 2))
         result.add("<![CDATA[" & i.nodeValue & "]]>")
       of ProcessingInstructionNode:
-        result.add(repeatChar(indent * 2, ' '))
+        result.add(spaces(indent * 2))
         result.add("<?" & PProcessingInstruction(i).target & " " &
                           PProcessingInstruction(i).data & " ?>")
       of CommentNode:
-        result.add(repeatChar(indent * 2, ' '))
+        result.add(spaces(indent * 2))
         result.add("<!-- " & i.nodeValue & " -->")
       else:
         continue
       result.add("\n")
     # Add the ending tag - </tag>
-    result.add(repeatChar(indent, ' ') & "</" & n.nodeName & ">")
+    result.add(spaces(indent) & "</" & n.nodeName & ">")
 
 proc `$`*(doc: PDocument): string =
   ## Converts a PDocument object into a string representation of it's XML
diff --git a/lib/system.nim b/lib/system.nim
index abf31c821..4180f24f9 100644
--- a/lib/system.nim
+++ b/lib/system.nim
@@ -89,7 +89,7 @@ type
   SomeOrdinal* = int|int8|int16|int32|int64|bool|enum|uint8|uint16|uint32
     ## type class matching all ordinal types; however this includes enums with
     ## holes.
-  
+
   SomeReal* = float|float32|float64
     ## type class matching all floating point number types
 
@@ -181,7 +181,7 @@ proc new*[T](a: var ref T, finalizer: proc (x: ref T) {.nimcall.}) {.
   ## freeing the object. Note: The `finalizer` refers to the type `T`, not to
   ## the object! This means that for each object of type `T` the finalizer
   ## will be called!
-  
+
 proc reset*[T](obj: var T) {.magic: "Reset", noSideEffect.}
   ## resets an object `obj` to its initial (binary zero) value. This needs to
   ## be called before any possible `object branch transition`:idx:.
@@ -348,7 +348,7 @@ type
                   ## This field is filled automatically in the
                   ## ``raise`` statement.
     msg* {.exportc: "message".}: string ## the exception's message. Not
-                                        ## providing an exception message 
+                                        ## providing an exception message
                                         ## is bad style.
     trace: string
 
@@ -483,7 +483,7 @@ type
 
   E_Base: Exception, ESystem: SystemError, EIO: IOError,
   EOS: OSError, EInvalidLibrary: LibraryError,
-  EResourceExhausted: ResourceExhaustedError, 
+  EResourceExhausted: ResourceExhaustedError,
   EArithmetic: ArithmeticError, EDivByZero: DivByZeroError,
   EOverflow: OverflowError, EAccessViolation: AccessViolationError,
   EAssertionFailed: AssertionError, EInvalidValue: ValueError,
@@ -494,7 +494,7 @@ type
   EInvalidObjectAssignment: ObjectAssignmentError,
   EInvalidObjectConversion: ObjectConversionError,
   EDeadThread: DeadThreadError,
-  EFloatInexact: FloatInexactError, 
+  EFloatInexact: FloatInexactError,
   EFloatUnderflow: FloatUnderflowError,
   EFloatingPoint: FloatingPointError,
   EFloatInvalidOp: FloatInvalidOpError,
@@ -511,11 +511,11 @@ proc sizeof*[T](x: T): Natural {.magic: "SizeOf", noSideEffect.}
 
 proc `<`*[T](x: Ordinal[T]): T {.magic: "UnaryLt", noSideEffect.}
   ## unary ``<`` that can be used for nice looking excluding ranges:
-  ## 
+  ##
   ## .. code-block:: nim
   ##   for i in 0 .. <10: echo i
   ##
-  ## Semantically this is the same as ``pred``. 
+  ## Semantically this is the same as ``pred``.
 
 proc succ*[T](x: Ordinal[T], y = 1): T {.magic: "Succ", noSideEffect.}
   ## returns the ``y``-th successor of the value ``x``. ``T`` has to be
@@ -536,7 +536,7 @@ proc dec*[T: Ordinal|uint|uint64](x: var T, y = 1) {.magic: "Dec", noSideEffect.
   ## decrements the ordinal ``x`` by ``y``. If such a value does not
   ## exist, ``EOutOfRange`` is raised or a compile time error occurs. This is a
   ## short notation for: ``x = pred(x, y)``.
-  
+
 proc newSeq*[T](s: var seq[T], len: int) {.magic: "NewSeq", noSideEffect.}
   ## creates a new sequence of type ``seq[T]`` with length ``len``.
   ## This is equivalent to ``s = @[]; setlen(s, len)``, but more
@@ -636,7 +636,7 @@ when not defined(JS):
 
   proc toU8*(x: int): int8 {.magic: "ToU8", noSideEffect.}
     ## treats `x` as unsigned and converts it to a byte by taking the last 8 bits
-    ## from `x`.    
+    ## from `x`.
   proc toU16*(x: int): int16 {.magic: "ToU16", noSideEffect.}
     ## treats `x` as unsigned and converts it to an ``int16`` by taking the last
     ## 16 bits from `x`.
@@ -800,7 +800,7 @@ proc `%%` *(x, y: int64): int64 {.magic: "ModU", noSideEffect.}
   ## The result is truncated to fit into the result.
   ## This implements modulo arithmetic.
   ## No overflow errors are possible.
-  
+
 proc `<=%` *(x, y: IntMax32): bool {.magic: "LeU", noSideEffect.}
 proc `<=%` *(x, y: int64): bool {.magic: "LeU64", noSideEffect.}
   ## treats `x` and `y` as unsigned and compares them.
@@ -889,7 +889,7 @@ template `notin` * (x, y: expr): expr {.immediate, dirty.} = not contains(y, x)
 
 proc `is` *[T, S](x: T, y: S): bool {.magic: "Is", noSideEffect.}
   ## Checks if T is of the same type as S
-  ## 
+  ##
   ## .. code-block:: Nim
   ##   proc test[T](a: T): int =
   ##     when (T is int):
@@ -924,7 +924,7 @@ proc cmp*(x, y: string): int {.noSideEffect, procvar.}
 proc `@` * [IDX, T](a: array[IDX, T]): seq[T] {.
   magic: "ArrToSeq", nosideeffect.}
   ## turns an array into a sequence. This most often useful for constructing
-  ## sequences with the array constructor: ``@[1, 2, 3]`` has the type 
+  ## sequences with the array constructor: ``@[1, 2, 3]`` has the type
   ## ``seq[int]``, while ``[1, 2, 3]`` has the type ``array[0..2, int]``.
 
 proc setLen*[T](s: var seq[T], newlen: int) {.
@@ -933,14 +933,14 @@ proc setLen*[T](s: var seq[T], newlen: int) {.
   ## ``T`` may be any sequence type.
   ## If the current length is greater than the new length,
   ## ``s`` will be truncated. `s` cannot be nil! To initialize a sequence with
-  ## a size, use ``newSeq`` instead. 
+  ## a size, use ``newSeq`` instead.
 
 proc setLen*(s: var string, newlen: int) {.
   magic: "SetLengthStr", noSideEffect.}
   ## sets the length of `s` to `newlen`.
   ## If the current length is greater than the new length,
   ## ``s`` will be truncated. `s` cannot be nil! To initialize a string with
-  ## a size, use ``newString`` instead. 
+  ## a size, use ``newString`` instead.
 
 proc newString*(len: int): string {.
   magic: "NewString", importc: "mnewString", noSideEffect.}
@@ -953,7 +953,7 @@ proc newString*(len: int): string {.
 proc newStringOfCap*(cap: int): string {.
   magic: "NewStringOfCap", importc: "rawNewString", noSideEffect.}
   ## returns a new string of length ``0`` but with capacity `cap`.This
-  ## procedure exists only for optimization purposes; the same effect can 
+  ## procedure exists only for optimization purposes; the same effect can
   ## be achieved with the ``&`` operator or with ``add``.
 
 proc `&` * (x: string, y: char): string {.
@@ -982,7 +982,7 @@ proc `&` * (x: char, y: string): string {.
   ##   assert('a' & "bc" == "abc")
 
 # implementation note: These must all have the same magic value "ConStrStr" so
-# that the merge optimization works properly. 
+# that the merge optimization works properly.
 
 proc add*(x: var string, y: char) {.magic: "AppendStrCh", noSideEffect.}
   ## Appends `y` to `x` in place
@@ -1039,15 +1039,15 @@ proc compileOption*(option: string): bool {.
   ## can be used to determine an on|off compile-time option. Example:
   ##
   ## .. code-block:: nim
-  ##   when compileOption("floatchecks"): 
+  ##   when compileOption("floatchecks"):
   ##     echo "compiled with floating point NaN and Inf checks"
-  
+
 proc compileOption*(option, arg: string): bool {.
   magic: "CompileOptionArg", noSideEffect.}
   ## can be used to determine an enum compile-time option. Example:
   ##
   ## .. code-block:: nim
-  ##   when compileOption("opt", "size") and compileOption("gc", "boehm"): 
+  ##   when compileOption("opt", "size") and compileOption("gc", "boehm"):
   ##     echo "compiled with optimization for size and uses Boehm's GC"
 
 const
@@ -1056,16 +1056,16 @@ const
   taintMode = compileOption("taintmode")
 
 when taintMode:
-  type TaintedString* = distinct string ## a distinct string type that 
+  type TaintedString* = distinct string ## a distinct string type that
                                         ## is `tainted`:idx:. It is an alias for
                                         ## ``string`` if the taint mode is not
                                         ## turned on. Use the ``-d:taintMode``
                                         ## command line switch to turn the taint
                                         ## mode on.
-  
+
   proc len*(s: TaintedString): int {.borrow.}
 else:
-  type TaintedString* = string          ## a distinct string type that 
+  type TaintedString* = string          ## a distinct string type that
                                         ## is `tainted`:idx:. It is an alias for
                                         ## ``string`` if the taint mode is not
                                         ## turned on. Use the ``-d:taintMode``
@@ -1136,25 +1136,25 @@ proc add *[T](x: var seq[T], y: openArray[T]) {.noSideEffect.} =
 proc shallowCopy*[T](x: var T, y: T) {.noSideEffect, magic: "ShallowCopy".}
   ## use this instead of `=` for a `shallow copy`:idx:. The shallow copy
   ## only changes the semantics for sequences and strings (and types which
-  ## contain those). Be careful with the changed semantics though! There 
+  ## contain those). Be careful with the changed semantics though! There
   ## is a reason why the default assignment does a deep copy of sequences
   ## and strings.
 
-proc del*[T](x: var seq[T], i: int) {.noSideEffect.} = 
+proc del*[T](x: var seq[T], i: int) {.noSideEffect.} =
   ## deletes the item at index `i` by putting ``x[high(x)]`` into position `i`.
   ## This is an O(1) operation.
   let xl = x.len
   shallowCopy(x[i], x[xl-1])
   setLen(x, xl-1)
-  
-proc delete*[T](x: var seq[T], i: int) {.noSideEffect.} = 
+
+proc delete*[T](x: var seq[T], i: int) {.noSideEffect.} =
   ## deletes the item at index `i` by moving ``x[i+1..]`` by one position.
   ## This is an O(n) operation.
   let xl = x.len
-  for j in i..xl-2: shallowCopy(x[j], x[j+1]) 
+  for j in i..xl-2: shallowCopy(x[j], x[j+1])
   setLen(x, xl-1)
-  
-proc insert*[T](x: var seq[T], item: T, i = 0) {.noSideEffect.} = 
+
+proc insert*[T](x: var seq[T], item: T, i = 0) {.noSideEffect.} =
   ## inserts `item` into `x` at position `i`.
   let xl = x.len
   setLen(x, xl+1)
@@ -1233,7 +1233,7 @@ type # these work for most platforms:
     ## This is binary compatible to the type ``char**`` in *C*. The array's
     ## high value is large enough to disable bounds checking in practice.
     ## Use `cstringArrayToSeq` to convert it into a ``seq[string]``.
-  
+
   PFloat32* = ptr float32 ## an alias for ``ptr float32``
   PFloat64* = ptr float64 ## an alias for ``ptr float64``
   PInt64* = ptr int64 ## an alias for ``ptr int64``
@@ -1280,7 +1280,7 @@ proc addQuitProc*(QuitProc: proc() {.noconv.}) {.
 proc copy*(s: string, first = 0): string {.
   magic: "CopyStr", importc: "copyStr", noSideEffect, deprecated.}
 proc copy*(s: string, first, last: int): string {.
-  magic: "CopyStrLast", importc: "copyStrLast", noSideEffect, 
+  magic: "CopyStrLast", importc: "copyStrLast", noSideEffect,
   deprecated.}
   ## copies a slice of `s` into a new string and returns this new
   ## string. The bounds `first` and `last` denote the indices of
@@ -1358,7 +1358,7 @@ when not defined(nimrodVM):
       ## The allocated memory belongs to its allocating thread!
       ## Use `createShared` to allocate from a shared heap.
       cast[ptr T](alloc0(T.sizeof * size))
-    proc realloc*(p: pointer, newSize: int): pointer {.noconv, rtl, tags: [], 
+    proc realloc*(p: pointer, newSize: int): pointer {.noconv, rtl, tags: [],
                                                        benign.}
       ## grows or shrinks a given memory block. If p is **nil** then a new
       ## memory block is returned. In either way the block has at least
@@ -1381,7 +1381,7 @@ when not defined(nimrodVM):
       ## ``realloc``. This procedure is dangerous! If one forgets to
       ## free the memory a leak occurs; if one tries to access freed
       ## memory (or just freeing it twice!) a core dump may happen
-      ## or other memory may be corrupted. 
+      ## or other memory may be corrupted.
       ## The freed memory must belong to its allocating thread!
       ## Use `deallocShared` to deallocate from a shared heap.
     proc free*[T](p: ptr T) {.inline, benign.} =
@@ -1390,30 +1390,30 @@ when not defined(nimrodVM):
       ## allocates a new memory block on the shared heap with at
       ## least ``size`` bytes. The block has to be freed with
       ## ``reallocShared(block, 0)`` or ``deallocShared(block)``. The block
-      ## is not initialized, so reading from it before writing to it is 
+      ## is not initialized, so reading from it before writing to it is
       ## undefined behaviour!
-    proc createSharedU*(T: typedesc, size = 1.Positive): ptr T {.inline, 
+    proc createSharedU*(T: typedesc, size = 1.Positive): ptr T {.inline,
                                                                  benign.} =
       ## allocates a new memory block on the shared heap with at
       ## least ``T.sizeof * size`` bytes. The block has to be freed with
       ## ``resizeShared(block, 0)`` or ``freeShared(block)``. The block
-      ## is not initialized, so reading from it before writing to it is 
+      ## is not initialized, so reading from it before writing to it is
       ## undefined behaviour!
       cast[ptr T](allocShared(T.sizeof * size))
     proc allocShared0*(size: int): pointer {.noconv, rtl, benign.}
-      ## allocates a new memory block on the shared heap with at 
+      ## allocates a new memory block on the shared heap with at
       ## least ``size`` bytes. The block has to be freed with
       ## ``reallocShared(block, 0)`` or ``deallocShared(block)``.
       ## The block is initialized with all bytes
       ## containing zero, so it is somewhat safer than ``allocShared``.
     proc createShared*(T: typedesc, size = 1.Positive): ptr T {.inline.} =
-      ## allocates a new memory block on the shared heap with at 
+      ## allocates a new memory block on the shared heap with at
       ## least ``T.sizeof * size`` bytes. The block has to be freed with
       ## ``resizeShared(block, 0)`` or ``freeShared(block)``.
       ## The block is initialized with all bytes
       ## containing zero, so it is somewhat safer than ``createSharedU``.
       cast[ptr T](allocShared0(T.sizeof * size))
-    proc reallocShared*(p: pointer, newSize: int): pointer {.noconv, rtl, 
+    proc reallocShared*(p: pointer, newSize: int): pointer {.noconv, rtl,
                                                              benign.}
       ## grows or shrinks a given memory block on the heap. If p is **nil**
       ## then a new memory block is returned. In either way the block has at
@@ -1525,7 +1525,7 @@ const
   NimVersion*: string = $NimMajor & "." & $NimMinor & "." & $NimPatch
     ## is the version of Nim as a string.
 
-{.deprecated: [TEndian: Endianness, NimrodVersion: NimVersion, 
+{.deprecated: [TEndian: Endianness, NimrodVersion: NimVersion,
     NimrodMajor: NimMajor, NimrodMinor: NimMinor, NimrodPatch: NimPatch].}
 
 # GC interface:
@@ -1805,7 +1805,7 @@ proc `==` *[I, T](x, y: array[I, T]): bool =
       return
   result = true
 
-proc `@`*[T](a: openArray[T]): seq[T] = 
+proc `@`*[T](a: openArray[T]): seq[T] =
   ## turns an openarray into a sequence. This is not as efficient as turning
   ## a fixed length array into a sequence as it always copies every element
   ## of `a`.
@@ -1853,7 +1853,7 @@ when not defined(NimrodVM):
   else:
     proc seqToPtr[T](x: seq[T]): pointer {.asmNoStackFrame, nosideeffect.} =
       asm """return `x`"""
-  
+
   proc `==` *[T](x, y: seq[T]): bool {.noSideEffect.} =
     ## Generic equals operator for sequences: relies on a equals operator for
     ## the element type `T`.
@@ -1879,7 +1879,7 @@ proc contains*[T](a: openArray[T], item: T): bool {.inline.}=
   ## for ``find(a, item) >= 0``.
   return find(a, item) >= 0
 
-proc pop*[T](s: var seq[T]): T {.inline, noSideEffect.} = 
+proc pop*[T](s: var seq[T]): T {.inline, noSideEffect.} =
   ## returns the last item of `s` and decreases ``s.len`` by one. This treats
   ## `s` as a stack and implements the common *pop* operation.
   var L = s.len-1
@@ -1941,7 +1941,7 @@ iterator fields*[T: tuple|object](x: T): RootObj {.
 iterator fields*[S:tuple|object, T:tuple|object](x: S, y: T): tuple[a,b: expr] {.
   magic: "Fields", noSideEffect.}
   ## iterates over every field of `x` and `y`.
-  ## Warning: This is really transforms the 'for' and unrolls the loop. 
+  ## Warning: This is really transforms the 'for' and unrolls the loop.
   ## The current implementation also has a bug that affects symbol binding
   ## in the loop body.
 iterator fieldPairs*[T: tuple|object](x: T): RootObj {.
@@ -1982,18 +1982,18 @@ iterator fieldPairs*[S: tuple|object, T: tuple|object](x: S, y: T): tuple[
   a, b: expr] {.
   magic: "FieldPairs", noSideEffect.}
   ## iterates over every field of `x` and `y`.
-  ## Warning: This really transforms the 'for' and unrolls the loop. 
+  ## Warning: This really transforms the 'for' and unrolls the loop.
   ## The current implementation also has a bug that affects symbol binding
   ## in the loop body.
 
-proc `==`*[T: tuple|object](x, y: T): bool = 
+proc `==`*[T: tuple|object](x, y: T): bool =
   ## generic ``==`` operator for tuples that is lifted from the components
   ## of `x` and `y`.
   for a, b in fields(x, y):
     if a != b: return false
   return true
 
-proc `<=`*[T: tuple](x, y: T): bool = 
+proc `<=`*[T: tuple](x, y: T): bool =
   ## generic ``<=`` operator for tuples that is lifted from the components
   ## of `x` and `y`. This implementation uses `cmp`.
   for a, b in fields(x, y):
@@ -2002,7 +2002,7 @@ proc `<=`*[T: tuple](x, y: T): bool =
     if c > 0: return false
   return true
 
-proc `<`*[T: tuple](x, y: T): bool = 
+proc `<`*[T: tuple](x, y: T): bool =
   ## generic ``<`` operator for tuples that is lifted from the components
   ## of `x` and `y`. This implementation uses `cmp`.
   for a, b in fields(x, y):
@@ -2011,7 +2011,7 @@ proc `<`*[T: tuple](x, y: T): bool =
     if c > 0: return false
   return false
 
-proc `$`*[T: tuple|object](x: T): string = 
+proc `$`*[T: tuple|object](x: T): string =
   ## generic ``$`` operator for tuples that is lifted from the components
   ## of `x`. Example:
   ##
@@ -2021,13 +2021,13 @@ proc `$`*[T: tuple|object](x: T): string =
   result = "("
   var firstElement = true
   for name, value in fieldPairs(x):
-    if not(firstElement): result.add(", ")
+    if not firstElement: result.add(", ")
     result.add(name)
     result.add(": ")
     result.add($value)
     firstElement = false
   result.add(")")
-  
+
 proc collectionToString[T](x: T, b, e: string): string =
   result = b
   var firstElement = true
@@ -2037,7 +2037,7 @@ proc collectionToString[T](x: T, b, e: string): string =
     firstElement = false
   result.add(e)
 
-proc `$`*[T](x: set[T]): string = 
+proc `$`*[T](x: set[T]): string =
   ## generic ``$`` operator for sets that is lifted from the components
   ## of `x`. Example:
   ##
@@ -2045,7 +2045,7 @@ proc `$`*[T](x: set[T]): string =
   ##   ${23, 45} == "{23, 45}"
   collectionToString(x, "{", "}")
 
-proc `$`*[T](x: seq[T]): string = 
+proc `$`*[T](x: seq[T]): string =
   ## generic ``$`` operator for seqs that is lifted from the components
   ## of `x`. Example:
   ##
@@ -2056,7 +2056,7 @@ proc `$`*[T](x: seq[T]): string =
 when false:
   # causes bootstrapping to fail as we use array of chars and cstring should
   # match better ...
-  proc `$`*[T, IDX](x: array[IDX, T]): string = 
+  proc `$`*[T, IDX](x: array[IDX, T]): string =
     collectionToString(x, "[", "]")
 
 # ----------------- GC interface ---------------------------------------------
@@ -2098,14 +2098,14 @@ when not defined(nimrodVM) and hostOS != "standalone":
   proc GC_getStatistics*(): string {.rtl, benign.}
     ## returns an informative string about the GC's activity. This may be useful
     ## for tweaking.
-    
+
   proc GC_ref*[T](x: ref T) {.magic: "GCref", benign.}
   proc GC_ref*[T](x: seq[T]) {.magic: "GCref", benign.}
   proc GC_ref*(x: string) {.magic: "GCref", benign.}
     ## marks the object `x` as referenced, so that it will not be freed until
     ## it is unmarked via `GC_unref`. If called n-times for the same object `x`,
-    ## n calls to `GC_unref` are needed to unmark `x`. 
-    
+    ## n calls to `GC_unref` are needed to unmark `x`.
+
   proc GC_unref*[T](x: ref T) {.magic: "GCunref", benign.}
   proc GC_unref*[T](x: seq[T]) {.magic: "GCunref", benign.}
   proc GC_unref*(x: string) {.magic: "GCunref", benign.}
@@ -2141,19 +2141,19 @@ var
     ## application code should never set this hook! You better know what you
     ## do when setting this. If ``localRaiseHook`` returns false, the exception
     ## is caught and does not propagate further through the call stack.
-    
+
   outOfMemHook*: proc () {.nimcall, tags: [], benign.}
-    ## set this variable to provide a procedure that should be called 
+    ## set this variable to provide a procedure that should be called
     ## in case of an `out of memory`:idx: event. The standard handler
     ## writes an error message and terminates the program. `outOfMemHook` can
     ## be used to raise an exception in case of OOM like so:
-    ## 
+    ##
     ## .. code-block:: nim
     ##
     ##   var gOutOfMem: ref EOutOfMemory
     ##   new(gOutOfMem) # need to be allocated *before* OOM really happened!
     ##   gOutOfMem.msg = "out of memory"
-    ## 
+    ##
     ##   proc handleOOM() =
     ##     raise gOutOfMem
     ##
@@ -2210,7 +2210,7 @@ proc echo*(x: varargs[expr, `$`]) {.magic: "Echo", tags: [WriteIOEffect],
   ## <manual.html#nosideeffect-pragma>`_ you can use `debugEcho <#debugEcho>`_
   ## instead.
 
-proc debugEcho*(x: varargs[expr, `$`]) {.magic: "Echo", noSideEffect, 
+proc debugEcho*(x: varargs[expr, `$`]) {.magic: "Echo", noSideEffect,
                                            tags: [], raises: [].}
   ## Same as `echo <#echo>`_, but as a special semantic rule, ``debugEcho``
   ## pretends to be free of side effects, so that it can be used for debugging
@@ -2262,7 +2262,7 @@ proc abs*(x: int16): int16 {.magic: "AbsI", noSideEffect.} =
 proc abs*(x: int32): int32 {.magic: "AbsI", noSideEffect.} =
   if x < 0: -x else: x
 proc abs*(x: int64): int64 {.magic: "AbsI64", noSideEffect.} =
-  ## returns the absolute value of `x`. If `x` is ``low(x)`` (that 
+  ## returns the absolute value of `x`. If `x` is ``low(x)`` (that
   ## is -MININT for its type), an overflow exception is thrown (if overflow
   ## checking is turned on).
   if x < 0: -x else: x
@@ -2318,14 +2318,14 @@ when not defined(JS): #and not defined(NimrodVM):
       # we use binary mode in Windows:
       setmode(fileno(c_stdin), O_BINARY)
       setmode(fileno(c_stdout), O_BINARY)
-    
+
     when defined(endb):
       proc endbStep()
 
   # ----------------- IO Part ------------------------------------------------
   when hostOS != "standalone":
     type
-      CFile {.importc: "FILE", header: "<stdio.h>", 
+      CFile {.importc: "FILE", header: "<stdio.h>",
               final, incompletestruct.} = object
       File* = ptr CFile ## The type representing a file handle.
 
@@ -2375,9 +2375,9 @@ when not defined(JS): #and not defined(NimrodVM):
       ## Creates a ``TFile`` from a `filehandle` with given `mode`.
       ##
       ## Default mode is readonly. Returns true iff the file could be opened.
-      
+
     proc open*(filename: string,
-               mode: FileMode = fmRead, bufSize: int = -1): File = 
+               mode: FileMode = fmRead, bufSize: int = -1): File =
       ## Opens a file named `filename` with given `mode`.
       ##
       ## Default mode is readonly. Raises an ``IO`` exception if the file
@@ -2387,7 +2387,7 @@ when not defined(JS): #and not defined(NimrodVM):
 
     proc reopen*(f: File, filename: string, mode: FileMode = fmRead): bool {.
       tags: [], benign.}
-      ## reopens the file `f` with given `filename` and `mode`. This 
+      ## reopens the file `f` with given `filename` and `mode`. This
       ## is often used to redirect the `stdin`, `stdout` or `stderr`
       ## file variables.
       ##
@@ -2398,7 +2398,7 @@ when not defined(JS): #and not defined(NimrodVM):
 
     proc endOfFile*(f: File): bool {.tags: [], benign.}
       ## Returns true iff `f` is at the end.
-      
+
     proc readChar*(f: File): char {.
       importc: "fgetc", header: "<stdio.h>", tags: [ReadIOEffect].}
       ## Reads a single character from the stream `f`.
@@ -2411,7 +2411,7 @@ when not defined(JS): #and not defined(NimrodVM):
       ##
       ## Raises an IO exception in case of an error. It is an error if the
       ## current file position is not at the beginning of the file.
-    
+
     proc readFile*(filename: string): TaintedString {.tags: [ReadIOEffect], benign.}
       ## Opens a file named `filename` for reading.
       ##
@@ -2440,8 +2440,8 @@ when not defined(JS): #and not defined(NimrodVM):
       ## reads a line of text from the file `f`. May throw an IO exception.
       ## A line of text may be delimited by ``CR``, ``LF`` or
       ## ``CRLF``. The newline character(s) are not part of the returned string.
-    
-    proc readLine*(f: File, line: var TaintedString): bool {.tags: [ReadIOEffect], 
+
+    proc readLine*(f: File, line: var TaintedString): bool {.tags: [ReadIOEffect],
                   benign.}
       ## reads a line of text from the file `f` into `line`. `line` must not be
       ## ``nil``! May throw an IO exception.
@@ -2450,7 +2450,7 @@ when not defined(JS): #and not defined(NimrodVM):
       ## Returns ``false`` if the end of the file has been reached, ``true``
       ## otherwise. If ``false`` is returned `line` contains no new data.
 
-    proc writeln*[Ty](f: File, x: varargs[Ty, `$`]) {.inline, 
+    proc writeln*[Ty](f: File, x: varargs[Ty, `$`]) {.inline,
                              tags: [WriteIOEffect], benign.}
       ## writes the values `x` to `f` and then writes "\n".
       ## May throw an IO exception.
@@ -2544,11 +2544,11 @@ when not defined(JS): #and not defined(NimrodVM):
       dealloc(a)
 
   when not defined(NimrodVM):
-    proc atomicInc*(memLoc: var int, x: int = 1): int {.inline, 
+    proc atomicInc*(memLoc: var int, x: int = 1): int {.inline,
       discardable, benign.}
       ## atomic increment of `memLoc`. Returns the value after the operation.
-    
-    proc atomicDec*(memLoc: var int, x: int = 1): int {.inline, 
+
+    proc atomicDec*(memLoc: var int, x: int = 1): int {.inline,
       discardable, benign.}
       ## atomic decrement of `memLoc`. Returns the value after the operation.
 
@@ -2562,7 +2562,7 @@ when not defined(JS): #and not defined(NimrodVM):
       context: C_JmpBuf
       hasRaiseAction: bool
       raiseAction: proc (e: ref Exception): bool {.closure.}
-  
+
   when declared(initAllocator):
     initAllocator()
   when hasThreadSupport:
@@ -2576,7 +2576,7 @@ when not defined(JS): #and not defined(NimrodVM):
     proc setControlCHook*(hook: proc () {.noconv.} not nil)
       ## allows you to override the behaviour of your application when CTRL+C
       ## is pressed. Only one such hook is supported.
-      
+
     proc writeStackTrace*() {.tags: [WriteIOEffect].}
       ## writes the current stack trace to ``stderr``. This is only works
       ## for debug builds.
@@ -2587,20 +2587,20 @@ when not defined(JS): #and not defined(NimrodVM):
       proc getStackTrace*(e: ref Exception): string
         ## gets the stack trace associated with `e`, which is the stack that
         ## lead to the ``raise`` statement. This only works for debug builds.
-        
+
     {.push stack_trace: off, profiler:off.}
     when hostOS == "standalone":
       include "system/embedded"
     else:
       include "system/excpt"
     include "system/chcks"
-      
+
     # we cannot compile this with stack tracing on
     # as it would recurse endlessly!
     include "system/arithm"
     {.pop.} # stack trace
   {.pop.} # stack trace
-      
+
   when hostOS != "standalone" and not defined(NimrodVM):
     include "system/dyncalls"
   when not defined(NimrodVM):
@@ -2608,7 +2608,7 @@ when not defined(JS): #and not defined(NimrodVM):
 
     const
       GenericSeqSize = (2 * sizeof(int))
-      
+
     proc getDiscriminant(aa: pointer, n: ptr TNimNode): int =
       sysAssert(n.kind == nkCase, "getDiscriminant: node != nkCase")
       var d: int
@@ -2728,7 +2728,7 @@ when not defined(JS): #and not defined(NimrodVM):
       ##       process(value)
       ##     else:
       ##       echo "Value too big!"
-    
+
     proc unlikely*(val: bool): bool {.importc: "unlikely", nodecl, nosideeffect.}
       ## Hints the optimizer that `val` is likely going to be false.
       ##
@@ -2742,7 +2742,7 @@ when not defined(JS): #and not defined(NimrodVM):
       ##       echo "Value too big!"
       ##     else:
       ##       process(value)
-      
+
     proc rawProc*[T: proc](x: T): pointer {.noSideEffect, inline.} =
       ## retrieves the raw proc pointer of the closure `x`. This is
       ## useful for interfacing closures with C.
@@ -2774,7 +2774,7 @@ elif defined(JS):
   proc GC_enableMarkAndSweep() = discard
   proc GC_disableMarkAndSweep() = discard
   proc GC_getStatistics(): string = return ""
-  
+
   proc getOccupiedMem(): int = return -1
   proc getFreeMem(): int = return -1
   proc getTotalMem(): int = return -1
@@ -2797,7 +2797,7 @@ elif defined(JS):
       if x == y: return 0
       if x < y: return -1
       return 1
-  
+
   when defined(nimffi):
     include "system/sysio"
 
@@ -2831,14 +2831,14 @@ template spliceImpl(s, a, L, b: expr): stmt {.immediate.} =
     # cut down:
     setLen(s, newLen)
   # fill the hole:
-  for i in 0 .. <b.len: s[i+a] = b[i]  
+  for i in 0 .. <b.len: s[i+a] = b[i]
 
 when hostOS != "standalone":
   proc `[]`*(s: string, x: Slice[int]): string {.inline.} =
     ## slice operation for strings. Negative indexes are supported.
     result = s.substr(x.a-|s, x.b-|s)
 
-  proc `[]=`*(s: var string, x: Slice[int], b: string) = 
+  proc `[]=`*(s: var string, x: Slice[int], b: string) =
     ## slice assignment for strings. Negative indexes are supported. If
     ## ``b.len`` is not exactly the number of elements that are referred to
     ## by `x`, a `splice`:idx: is performed:
@@ -2880,7 +2880,7 @@ proc `[]`*[Idx, T](a: array[Idx, T], x: Slice[Idx]): seq[T] =
   var L = ord(x.b) - ord(x.a) + 1
   newSeq(result, L)
   var j = x.a
-  for i in 0.. <L: 
+  for i in 0.. <L:
     result[i] = a[j]
     inc(j)
 
@@ -2890,23 +2890,23 @@ proc `[]=`*[Idx, T](a: var array[Idx, T], x: Slice[Idx], b: openArray[T]) =
   var L = ord(x.b) - ord(x.a) + 1
   if L == b.len:
     var j = x.a
-    for i in 0 .. <L: 
+    for i in 0 .. <L:
       a[j] = b[i]
       inc(j)
   else:
     sysFatal(RangeError, "different lengths for slice assignment")
 
-proc `[]`*[T](s: seq[T], x: Slice[int]): seq[T] = 
+proc `[]`*[T](s: seq[T], x: Slice[int]): seq[T] =
   ## slice operation for sequences. Negative indexes are supported.
   var a = x.a-|s
   var L = x.b-|s - a + 1
   newSeq(result, L)
   for i in 0.. <L: result[i] = s[i + a]
 
-proc `[]=`*[T](s: var seq[T], x: Slice[int], b: openArray[T]) = 
+proc `[]=`*[T](s: var seq[T], x: Slice[int], b: openArray[T]) =
   ## slice assignment for sequences. Negative indexes are supported. If
   ## ``b.len`` is not exactly the number of elements that are referred to
-  ## by `x`, a `splice`:idx: is performed. 
+  ## by `x`, a `splice`:idx: is performed.
   var a = x.a-|s
   var L = x.b-|s - a + 1
   if L == b.len:
@@ -2937,7 +2937,7 @@ proc staticExec*(command: string, input = ""): string {.
   ## to the executed program.
   ##
   ## .. code-block:: nim
-  ##     const buildInfo = "Revision " & staticExec("git rev-parse HEAD") & 
+  ##     const buildInfo = "Revision " & staticExec("git rev-parse HEAD") &
   ##                       "\nCompiled on " & staticExec("uname -v")
   ##
   ## `gorge <#gorge>`_ is an alias for ``staticExec``. Note that you can use
@@ -2979,7 +2979,7 @@ proc `&=`* (x: var string, y: string) {.magic: "AppendStrStr", noSideEffect.}
 proc astToStr*[T](x: T): string {.magic: "AstToStr", noSideEffect.}
   ## converts the AST of `x` into a string representation. This is very useful
   ## for debugging.
-  
+
 proc instantiationInfo*(index = -1, fullPaths = false): tuple[
   filename: string, line: int] {. magic: "InstantiationInfo", noSideEffect.}
   ## provides access to the compiler's instantiation stack line information.
@@ -3090,16 +3090,16 @@ template onFailedAssert*(msg: expr, code: stmt): stmt {.dirty, immediate.} =
   ## Sets an assertion failure handler that will intercept any assert
   ## statements following `onFailedAssert` in the current lexical scope.
   ## Can be defined multiple times in a single function.
-  ##  
+  ##
   ## .. code-block:: nim
   ##
   ##   proc example(x: int): TErrorCode =
   ##     onFailedAssert(msg):
   ##       log msg
   ##       return E_FAIL
-  ## 
+  ##
   ##     assert(...)
-  ##     
+  ##
   ##     onFailedAssert(msg):
   ##       raise newException(EMyException, msg)
   ##
@@ -3111,7 +3111,7 @@ template onFailedAssert*(msg: expr, code: stmt): stmt {.dirty, immediate.} =
 
 proc shallow*[T](s: var seq[T]) {.noSideEffect, inline.} =
   ## marks a sequence `s` as `shallow`:idx:. Subsequent assignments will not
-  ## perform deep copies of `s`. This is only useful for optimization 
+  ## perform deep copies of `s`. This is only useful for optimization
   ## purposes.
   when not defined(JS) and not defined(NimrodVM):
     var s = cast[PGenericSeq](s)
@@ -3119,7 +3119,7 @@ proc shallow*[T](s: var seq[T]) {.noSideEffect, inline.} =
 
 proc shallow*(s: var string) {.noSideEffect, inline.} =
   ## marks a string `s` as `shallow`:idx:. Subsequent assignments will not
-  ## perform deep copies of `s`. This is only useful for optimization 
+  ## perform deep copies of `s`. This is only useful for optimization
   ## purposes.
   when not defined(JS) and not defined(NimrodVM):
     var s = cast[PGenericSeq](s)
@@ -3141,13 +3141,13 @@ else:
 when false:
   template eval*(blk: stmt): stmt =
     ## executes a block of code at compile time just as if it was a macro
-    ## optionally, the block can return an AST tree that will replace the 
+    ## optionally, the block can return an AST tree that will replace the
     ## eval expression
     macro payload: stmt {.gensym.} = blk
     payload()
 
 when hostOS != "standalone":
-  proc insert*(x: var string, item: string, i = 0) {.noSideEffect.} = 
+  proc insert*(x: var string, item: string, i = 0) {.noSideEffect.} =
     ## inserts `item` into `x` at position `i`.
     var xl = x.len
     setLen(x, xl+item.len)
diff --git a/lib/system/deepcopy.nim b/lib/system/deepcopy.nim
index 7a26a17c5..093c0f3a7 100644
--- a/lib/system/deepcopy.nim
+++ b/lib/system/deepcopy.nim
@@ -34,9 +34,9 @@ proc genericDeepCopyAux(dest, src: pointer, n: ptr TNimNode) {.benign.} =
 
 proc copyDeepString(src: NimString): NimString {.inline.} =
   if src != nil:
-    result = rawNewString(src.space)
+    result = rawNewStringNoInit(src.len)
     result.len = src.len
-    c_memcpy(result.data, src.data, (src.len + 1) * sizeof(char))
+    c_memcpy(result.data, src.data, src.len + 1)
 
 proc genericDeepCopyAux(dest, src: pointer, mt: PNimType) =
   var
diff --git a/lib/system/gc.nim b/lib/system/gc.nim
index 1f4279c8f..bbf8cbf66 100644
--- a/lib/system/gc.nim
+++ b/lib/system/gc.nim
@@ -1,7 +1,7 @@
 #
 #
 #            Nim's Runtime Library
-#        (c) Copyright 2013 Andreas Rumpf
+#        (c) Copyright 2015 Andreas Rumpf
 #
 #    See the file "copying.txt", included in this
 #    distribution, for details about the copyright.
@@ -48,7 +48,7 @@ type
   TWalkOp = enum
     waMarkGlobal,    # part of the backup/debug mark&sweep
     waMarkPrecise,   # part of the backup/debug mark&sweep
-    waZctDecRef, waPush, waCycleDecRef, waMarkGray, waScan, waScanBlack, 
+    waZctDecRef, waPush, waCycleDecRef, waMarkGray, waScan, waScanBlack,
     waCollectWhite #, waDebug
 
   TFinalizer {.compilerproc.} = proc (self: pointer) {.nimcall, benign.}
@@ -61,9 +61,9 @@ type
     maxThreshold: int        # max threshold that has been set
     maxStackSize: int        # max stack size
     maxStackCells: int       # max stack cells in ``decStack``
-    cycleTableSize: int      # max entries in cycle table  
+    cycleTableSize: int      # max entries in cycle table
     maxPause: int64          # max measured GC pause in nanoseconds
-  
+
   TGcHeap {.final, pure.} = object # this contains the zero count and
                                    # non-zero count table
     stackBottom: pointer
@@ -88,11 +88,11 @@ var
 when not defined(useNimRtl):
   instantiateForRegion(gch.region)
 
-template acquire(gch: TGcHeap) = 
+template acquire(gch: TGcHeap) =
   when hasThreadSupport and hasSharedHeap:
     acquireSys(HeapLock)
 
-template release(gch: TGcHeap) = 
+template release(gch: TGcHeap) =
   when hasThreadSupport and hasSharedHeap:
     releaseSys(HeapLock)
 
@@ -117,7 +117,7 @@ proc usrToCell(usr: pointer): PCell {.inline.} =
   # convert pointer to userdata to object (=pointer to refcount)
   result = cast[PCell](cast[ByteAddress](usr)-%ByteAddress(sizeof(TCell)))
 
-proc canbeCycleRoot(c: PCell): bool {.inline.} =
+proc canBeCycleRoot(c: PCell): bool {.inline.} =
   result = ntfAcyclic notin c.typ.flags
 
 proc extGetCellType(c: pointer): PNimType {.compilerproc.} =
@@ -163,7 +163,7 @@ when hasThreadSupport and hasSharedHeap:
   template `--`(x: expr): expr = atomicDec(x, rcIncrement) <% rcIncrement
   template `++`(x: expr): stmt = discard atomicInc(x, rcIncrement)
 else:
-  template `--`(x: expr): expr = 
+  template `--`(x: expr): expr =
     dec(x, rcIncrement)
     x <% rcIncrement
   template `++`(x: expr): stmt = inc(x, rcIncrement)
@@ -181,7 +181,7 @@ proc prepareDealloc(cell: PCell) =
     (cast[TFinalizer](cell.typ.finalizer))(cellToUsr(cell))
     dec(gch.recGcLock)
 
-proc rtlAddCycleRoot(c: PCell) {.rtl, inl.} = 
+proc rtlAddCycleRoot(c: PCell) {.rtl, inl.} =
   # we MUST access gch as a global here, because this crosses DLL boundaries!
   when hasThreadSupport and hasSharedHeap:
     acquireSys(HeapLock)
@@ -211,7 +211,7 @@ proc decRef(c: PCell) {.inline.} =
     rtlAddCycleRoot(c)
     #writeCell("decRef", c)
 
-proc incRef(c: PCell) {.inline.} = 
+proc incRef(c: PCell) {.inline.} =
   gcAssert(isAllocatedPtr(gch.region, c), "incRef: interiorPtr")
   c.refcount = c.refcount +% rcIncrement
   # and not colorMask
@@ -246,12 +246,12 @@ proc asgnRef(dest: PPointer, src: pointer) {.compilerProc, inline.} =
   dest[] = src
 
 proc asgnRefNoCycle(dest: PPointer, src: pointer) {.compilerProc, inline.} =
-  # the code generator calls this proc if it is known at compile time that no 
+  # the code generator calls this proc if it is known at compile time that no
   # cycle is possible.
   if src != nil:
     var c = usrToCell(src)
     ++c.refcount
-  if dest[] != nil: 
+  if dest[] != nil:
     var c = usrToCell(dest[])
     if --c.refcount:
       rtlAddZCT(c)
@@ -269,7 +269,7 @@ proc unsureAsgnRef(dest: PPointer, src: pointer) {.compilerProc.} =
     if cast[int](dest[]) >=% PageSize: decRef(usrToCell(dest[]))
   else:
     # can't be an interior pointer if it's a stack location!
-    gcAssert(interiorAllocatedPtr(gch.region, dest) == nil, 
+    gcAssert(interiorAllocatedPtr(gch.region, dest) == nil,
              "stack loc AND interior pointer")
   dest[] = src
 
@@ -321,7 +321,7 @@ when useMarkForDebug or useBackupGc:
       echo "[GC] cannot register global variable; too many global variables"
       quit 1
 
-proc cellsetReset(s: var TCellSet) = 
+proc cellsetReset(s: var TCellSet) =
   deinit(s)
   init(s)
 
@@ -336,7 +336,7 @@ proc forAllSlotsAux(dest: pointer, n: ptr TNimNode, op: TWalkOp) {.benign.} =
         if n.sons[i].typ.kind in {tyRef, tyString, tySequence}:
           doOperation(cast[PPointer](d +% n.sons[i].offset)[], op)
         else:
-          forAllChildrenAux(cast[pointer](d +% n.sons[i].offset), 
+          forAllChildrenAux(cast[pointer](d +% n.sons[i].offset),
                             n.sons[i].typ, op)
       else:
         forAllSlotsAux(dest, n.sons[i], op)
@@ -384,7 +384,7 @@ proc addNewObjToZCT(res: PCell, gch: var TGcHeap) {.inline.} =
   # we check the last 8 entries (cache line) for a slot that could be reused.
   # In 63% of all cases we succeed here! But we have to optimize the heck
   # out of this small linear search so that ``newObj`` is not slowed down.
-  # 
+  #
   # Slots to try          cache hit
   # 1                     32%
   # 4                     59%
@@ -481,7 +481,7 @@ proc newObjRC1(typ: PNimType, size: int): pointer {.compilerRtl.} =
   gcAssert(typ.kind in {tyRef, tyString, tySequence}, "newObj: 1")
   collectCT(gch)
   sysAssert(allocInv(gch.region), "newObjRC1 after collectCT")
-  
+
   var res = cast[PCell](rawAlloc(gch.region, size + sizeof(TCell)))
   sysAssert(allocInv(gch.region), "newObjRC1 after rawAlloc")
   sysAssert((cast[ByteAddress](res) and (MemAlign-1)) == 0, "newObj: 2")
@@ -510,7 +510,7 @@ proc newSeqRC1(typ: PNimType, len: int): pointer {.compilerRtl.} =
   cast[PGenericSeq](result).len = len
   cast[PGenericSeq](result).reserved = len
   when defined(memProfiler): nimProfile(size)
-  
+
 proc growObj(old: pointer, newsize: int, gch: var TGcHeap): pointer =
   acquire(gch)
   collectCT(gch)
@@ -522,7 +522,7 @@ proc growObj(old: pointer, newsize: int, gch: var TGcHeap): pointer =
   var res = cast[PCell](rawAlloc(gch.region, newsize + sizeof(TCell)))
   var elemSize = 1
   if ol.typ.kind != tyString: elemSize = ol.typ.base.size
-  
+
   var oldsize = cast[PGenericSeq](old).len*elemSize + GenericSeqSize
   copyMem(res, ol, oldsize + sizeof(TCell))
   zeroMem(cast[pointer](cast[ByteAddress](res)+% oldsize +% sizeof(TCell)),
@@ -536,7 +536,7 @@ proc growObj(old: pointer, newsize: int, gch: var TGcHeap): pointer =
     writeCell("growObj new cell", res)
   gcTrace(ol, csZctFreed)
   gcTrace(res, csAllocated)
-  when reallyDealloc: 
+  when reallyDealloc:
     sysAssert(allocInv(gch.region), "growObj before dealloc")
     if ol.refcount shr rcShift <=% 1:
       # free immediately to save space:
@@ -580,7 +580,7 @@ proc freeCyclicCell(gch: var TGcHeap, c: PCell) =
   prepareDealloc(c)
   gcTrace(c, csCycFreed)
   when logGC: writeCell("cycle collector dealloc cell", c)
-  when reallyDealloc: 
+  when reallyDealloc:
     sysAssert(allocInv(gch.region), "free cyclic cell")
     rawDealloc(gch.region, c)
   else:
@@ -767,7 +767,7 @@ proc collectCycles(gch: var TGcHeap) =
       gcAssert isAllocatedPtr(gch.region, c), "addBackStackRoots"
       gcAssert c.refcount >=% rcIncrement, "addBackStackRoots: dead cell"
       if canBeCycleRoot(c):
-        #if c notin gch.cycleRoots: 
+        #if c notin gch.cycleRoots:
         inc cycleRootsLen
         incl(gch.cycleRoots, c)
       gcAssert c.typ != nil, "addBackStackRoots 2"
@@ -794,12 +794,12 @@ proc gcMark(gch: var TGcHeap, p: pointer) {.inline.} =
         add(gch.decStack, cell)
   sysAssert(allocInv(gch.region), "gcMark end")
 
-proc markThreadStacks(gch: var TGcHeap) = 
+proc markThreadStacks(gch: var TGcHeap) =
   when hasThreadSupport and hasSharedHeap:
     {.error: "not fully implemented".}
     var it = threadList
     while it != nil:
-      # mark registers: 
+      # mark registers:
       for i in 0 .. high(it.registers): gcMark(gch, it.registers[i])
       var sp = cast[TAddress](it.stackBottom)
       var max = cast[TAddress](it.stackTop)
@@ -933,7 +933,7 @@ else:
       while sp <=% max:
         gcMark(gch, cast[PPointer](sp)[])
         sp = sp +% sizeof(pointer)
-    
+
 proc markStackAndRegisters(gch: var TGcHeap) {.noinline, cdecl.} =
   forEachStackSlot(gch, gcMark)
 
@@ -946,13 +946,13 @@ when useMarkForDebug or useBackupGc:
 # ----------------------------------------------------------------------------
 
 proc collectZCT(gch: var TGcHeap): bool =
-  # Note: Freeing may add child objects to the ZCT! So essentially we do 
-  # deep freeing, which is bad for incremental operation. In order to 
+  # Note: Freeing may add child objects to the ZCT! So essentially we do
+  # deep freeing, which is bad for incremental operation. In order to
   # avoid a deep stack, we move objects to keep the ZCT small.
   # This is performance critical!
   const workPackage = 100
   var L = addr(gch.zct.len)
-  
+
   when withRealTime:
     var steps = workPackage
     var t0: TTicks
@@ -962,15 +962,15 @@ proc collectZCT(gch: var TGcHeap): bool =
     sysAssert(isAllocatedPtr(gch.region, c), "CollectZCT: isAllocatedPtr")
     # remove from ZCT:
     gcAssert((c.refcount and ZctFlag) == ZctFlag, "collectZCT")
-    
+
     c.refcount = c.refcount and not ZctFlag
     gch.zct.d[0] = gch.zct.d[L[] - 1]
     dec(L[])
     when withRealTime: dec steps
-    if c.refcount <% rcIncrement: 
+    if c.refcount <% rcIncrement:
       # It may have a RC > 0, if it is in the hardware stack or
       # it has not been removed yet from the ZCT. This is because
-      # ``incref`` does not bother to remove the cell from the ZCT 
+      # ``incref`` does not bother to remove the cell from the ZCT
       # as this might be too slow.
       # In any case, it should be removed from the ZCT. But not
       # freed. **KEEP THIS IN MIND WHEN MAKING THIS INCREMENTAL!**
@@ -983,7 +983,7 @@ proc collectZCT(gch: var TGcHeap): bool =
       # access invalid memory. This is done by prepareDealloc():
       prepareDealloc(c)
       forAllChildren(c, waZctDecRef)
-      when reallyDealloc: 
+      when reallyDealloc:
         sysAssert(allocInv(gch.region), "collectZCT: rawDealloc")
         rawDealloc(gch.region, c)
       else:
@@ -994,7 +994,7 @@ proc collectZCT(gch: var TGcHeap): bool =
         steps = workPackage
         if gch.maxPause > 0:
           let duration = getticks() - t0
-          # the GC's measuring is not accurate and needs some cleanup actions 
+          # the GC's measuring is not accurate and needs some cleanup actions
           # (stack unmarking), so subtract some short amount of time in
           # order to miss deadlines less often:
           if duration >= gch.maxPause - 50_000:
@@ -1017,7 +1017,7 @@ proc collectCTBody(gch: var TGcHeap) =
   when withRealTime:
     let t0 = getticks()
   sysAssert(allocInv(gch.region), "collectCT: begin")
-  
+
   gch.stat.maxStackSize = max(gch.stat.maxStackSize, stackSize())
   sysAssert(gch.decStack.len == 0, "collectCT")
   prepareForInteriorPointerChecking(gch.region)
@@ -1036,7 +1036,7 @@ proc collectCTBody(gch: var TGcHeap) =
         gch.stat.maxThreshold = max(gch.stat.maxThreshold, gch.cycleThreshold)
   unmarkStackAndRegisters(gch)
   sysAssert(allocInv(gch.region), "collectCT: end")
-  
+
   when withRealTime:
     let duration = getticks() - t0
     gch.stat.maxPause = max(gch.stat.maxPause, duration)
@@ -1050,8 +1050,12 @@ when useMarkForDebug or useBackupGc:
     markGlobals(gch)
 
 proc collectCT(gch: var TGcHeap) =
-  if (gch.zct.len >= ZctThreshold or (cycleGC and
-      getOccupiedMem(gch.region)>=gch.cycleThreshold) or alwaysGC) and 
+  # stackMarkCosts prevents some pathological behaviour: Stack marking
+  # becomes more expensive with large stacks and large stacks mean that
+  # cells with RC=0 are more likely to be kept alive by the stack.
+  let stackMarkCosts = max(stackSize() div (16*sizeof(int)), ZctThreshold)
+  if (gch.zct.len >= stackMarkCosts or (cycleGC and
+      getOccupiedMem(gch.region)>=gch.cycleThreshold) or alwaysGC) and
       gch.recGcLock == 0:
     when useMarkForDebug:
       prepareForInteriorPointerChecking(gch.region)
@@ -1070,7 +1074,7 @@ when withRealTime:
     acquire(gch)
     gch.maxPause = us.toNano
     if (gch.zct.len >= ZctThreshold or (cycleGC and
-        getOccupiedMem(gch.region)>=gch.cycleThreshold) or alwaysGC) or 
+        getOccupiedMem(gch.region)>=gch.cycleThreshold) or alwaysGC) or
         strongAdvice:
       collectCTBody(gch)
     release(gch)
@@ -1078,13 +1082,13 @@ when withRealTime:
   proc GC_step*(us: int, strongAdvice = false) = GC_step(gch, us, strongAdvice)
 
 when not defined(useNimRtl):
-  proc GC_disable() = 
+  proc GC_disable() =
     when hasThreadSupport and hasSharedHeap:
       discard atomicInc(gch.recGcLock, 1)
     else:
       inc(gch.recGcLock)
   proc GC_enable() =
-    if gch.recGcLock > 0: 
+    if gch.recGcLock > 0:
       when hasThreadSupport and hasSharedHeap:
         discard atomicDec(gch.recGcLock, 1)
       else:
diff --git a/lib/system/gc2.nim b/lib/system/gc2.nim
index ae2d2c85d..b8a61d627 100644
--- a/lib/system/gc2.nim
+++ b/lib/system/gc2.nim
@@ -593,7 +593,7 @@ proc addNewObjToZCT(res: PCell, gch: var TGcHeap) {.inline.} =
         return
     add(gch.zct, res)
 
-proc rawNewObj(typ: PNimType, size: int, gch: var TGcHeap, rc1: bool): pointer =
+proc rawNewObj(typ: PNimType, size: int, gch: var TGcHeap, rc1 = false): pointer =
   # generates a new object and sets its reference counter to 0
   acquire(gch)
   sysAssert(allocInv(gch.region), "rawNewObj begin")
diff --git a/lib/system/sysstr.nim b/lib/system/sysstr.nim
index cfbc24f0c..11780a9aa 100644
--- a/lib/system/sysstr.nim
+++ b/lib/system/sysstr.nim
@@ -30,18 +30,30 @@ proc eqStrings(a, b: NimString): bool {.inline, compilerProc.} =
   if a == b: return true
   if a == nil or b == nil: return false
   return a.len == b.len and
-    c_memcmp(a.data, b.data, a.len * sizeof(char)) == 0'i32
+    c_memcmp(a.data, b.data, a.len) == 0'i32
 
 when declared(allocAtomic):
   template allocStr(size: expr): expr =
     cast[NimString](allocAtomic(size))
+
+  template allocStrNoInit(size: expr): expr =
+    cast[NimString](boehmAllocAtomic(size))
 else:
   template allocStr(size: expr): expr =
     cast[NimString](newObj(addr(strDesc), size))
 
+  template allocStrNoInit(size: expr): expr =
+    cast[NimString](rawNewObj(addr(strDesc), size, gch))
+
+proc rawNewStringNoInit(space: int): NimString {.compilerProc.} =
+  var s = space
+  if s < 7: s = 7
+  result = allocStrNoInit(sizeof(TGenericSeq) + s + 1)
+  result.reserved = s
+
 proc rawNewString(space: int): NimString {.compilerProc.} =
   var s = space
-  if s < 8: s = 7
+  if s < 7: s = 7
   result = allocStr(sizeof(TGenericSeq) + s + 1)
   result.reserved = s
 
@@ -53,10 +65,10 @@ proc copyStrLast(s: NimString, start, last: int): NimString {.compilerProc.} =
   var start = max(start, 0)
   var len = min(last, s.len-1) - start + 1
   if len > 0:
-    result = rawNewString(len)
+    result = rawNewStringNoInit(len)
     result.len = len
-    c_memcpy(result.data, addr(s.data[start]), len * sizeof(char))
-    #result.data[len] = '\0'
+    c_memcpy(result.data, addr(s.data[start]), len)
+    result.data[len] = '\0'
   else:
     result = rawNewString(len)
 
@@ -64,10 +76,9 @@ proc copyStr(s: NimString, start: int): NimString {.compilerProc.} =
   result = copyStrLast(s, start, s.len-1)
 
 proc toNimStr(str: cstring, len: int): NimString {.compilerProc.} =
-  result = rawNewString(len)
+  result = rawNewStringNoInit(len)
   result.len = len
-  c_memcpy(result.data, str, (len+1) * sizeof(char))
-  #result.data[len] = '\0' # readline relies on this!
+  c_memcpy(result.data, str, len + 1)
 
 proc cstrToNimstr(str: cstring): NimString {.compilerRtl.} =
   result = toNimStr(str, c_strlen(str))
@@ -77,23 +88,24 @@ proc copyString(src: NimString): NimString {.compilerRtl.} =
     if (src.reserved and seqShallowFlag) != 0:
       result = src
     else:
-      result = rawNewString(src.space)
+      result = rawNewStringNoInit(src.len)
       result.len = src.len
-      c_memcpy(result.data, src.data, (src.len + 1) * sizeof(char))
+      c_memcpy(result.data, src.data, src.len + 1)
 
 proc copyStringRC1(src: NimString): NimString {.compilerRtl.} =
   if src != nil:
-    var s = src.space
-    if s < 8: s = 7
     when declared(newObjRC1):
+      var s = src.len
+      if s < 7: s = 7
       result = cast[NimString](newObjRC1(addr(strDesc), sizeof(TGenericSeq) +
                                s+1))
+      result.reserved = s
     else:
-      result = allocStr(sizeof(TGenericSeq) + s + 1)
-    result.reserved = s
+      result = rawNewStringNoInit(src.len)
     result.len = src.len
     c_memcpy(result.data, src.data, src.len + 1)
 
+
 proc hashString(s: string): int {.compilerproc.} =
   # the compiler needs exactly the same hash function!
   # this used to be used for efficient generation of string case statements
@@ -113,7 +125,7 @@ proc addChar(s: NimString, c: char): NimString =
   if result.len >= result.space:
     result.reserved = resize(result.space)
     result = cast[NimString](growObj(result,
-      sizeof(TGenericSeq) + (result.reserved+1) * sizeof(char)))
+      sizeof(TGenericSeq) + result.reserved + 1))
   result.data[result.len] = c
   result.data[result.len+1] = '\0'
   inc(result.len)
@@ -157,7 +169,7 @@ proc resizeString(dest: NimString, addlen: int): NimString {.compilerRtl.} =
     result = cast[NimString](growObj(dest, sizeof(TGenericSeq) + sp + 1))
     result.reserved = sp
     #result = rawNewString(sp)
-    #copyMem(result, dest, dest.len * sizeof(char) + sizeof(TGenericSeq))
+    #copyMem(result, dest, dest.len + sizeof(TGenericSeq))
     # DO NOT UPDATE LEN YET: dest.len = newLen
 
 proc appendString(dest, src: NimString) {.compilerproc, inline.} =