summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--compiler/hlo.nim3
-rw-r--r--compiler/nimrod.nimrod.cfg1
-rw-r--r--compiler/sem.nim19
-rw-r--r--compiler/semdata.nim2
-rw-r--r--compiler/semexprs.nim17
-rw-r--r--compiler/semgnrc.nim8
-rw-r--r--compiler/semtempl.nim4
-rw-r--r--compiler/semtypes.nim10
-rw-r--r--compiler/sigmatch.nim2
-rw-r--r--compiler/transf.nim1
-rw-r--r--compiler/vm.nim12
-rw-r--r--compiler/vmgen.nim2
-rw-r--r--doc/lib.txt28
-rw-r--r--lib/nimbase.h2
-rw-r--r--lib/pure/asyncdispatch.nim68
-rw-r--r--lib/pure/asynchttpserver.nim179
-rw-r--r--lib/pure/asyncnet.nim38
-rw-r--r--lib/pure/httpclient.nim44
-rw-r--r--lib/pure/irc.nim1
-rw-r--r--lib/pure/math.nim26
-rw-r--r--lib/pure/net.nim11
-rw-r--r--lib/pure/parseurl.nim5
-rw-r--r--lib/pure/rawsockets.nim34
-rw-r--r--lib/pure/redis.nim54
-rw-r--r--lib/pure/selectors.nim39
-rw-r--r--lib/pure/sockets.nim14
-rw-r--r--lib/pure/uri.nim8
-rw-r--r--lib/system/sysio.nim5
-rw-r--r--lib/windows/winlean.nim7
-rw-r--r--tests/assert/tfailedassert.nim2
-rw-r--r--tests/trmacros/targlist.nim (renamed from tests/patterns/targlist.nim)0
-rw-r--r--tests/trmacros/tcse.nim (renamed from tests/patterns/tcse.nim)0
-rw-r--r--tests/trmacros/thoist.nim (renamed from tests/patterns/thoist.nim)0
-rw-r--r--tests/trmacros/tmatrix.nim (renamed from tests/patterns/tmatrix.nim)0
-rw-r--r--tests/trmacros/tnoalias.nim (renamed from tests/patterns/tnoalias.nim)0
-rw-r--r--tests/trmacros/tnoendlessrec.nim (renamed from tests/patterns/tnoendlessrec.nim)0
-rw-r--r--tests/trmacros/tor.nim (renamed from tests/patterns/tor.nim)9
-rw-r--r--tests/trmacros/tpartial.nim (renamed from tests/patterns/tpartial.nim)0
-rw-r--r--tests/trmacros/tpatterns.nim (renamed from tests/patterns/tpatterns.nim)0
-rw-r--r--tests/trmacros/tstar.nim (renamed from tests/patterns/tstar.nim)0
-rw-r--r--tests/trmacros/tstmtlist.nim (renamed from tests/patterns/tstmtlist.nim)0
-rw-r--r--tests/typerel/texplicitcmp.nim32
-rw-r--r--tests/typerel/tvarargsexpr.nim18
-rw-r--r--tests/vm/tarrayboundeval.nim23
-rw-r--r--web/news.txt238
-rw-r--r--web/nimrod.ini3
46 files changed, 732 insertions, 237 deletions
diff --git a/compiler/hlo.nim b/compiler/hlo.nim
index 7982d4aa1..c75d6519f 100644
--- a/compiler/hlo.nim
+++ b/compiler/hlo.nim
@@ -68,7 +68,8 @@ proc hlo(c: PContext, n: PNode): PNode =
     result = n
   else:
     if n.kind in {nkFastAsgn, nkAsgn, nkIdentDefs, nkVarTuple} and
-        n.sons[0].kind == nkSym and sfGlobal in n.sons[0].sym.flags:
+        n.sons[0].kind == nkSym and 
+        {sfGlobal, sfPure} * n.sons[0].sym.flags == {sfGlobal, sfPure}:
       # do not optimize 'var g {.global} = re(...)' again!
       return n
     result = applyPatterns(c, n)
diff --git a/compiler/nimrod.nimrod.cfg b/compiler/nimrod.nimrod.cfg
index cc27d9f36..2c6e6f249 100644
--- a/compiler/nimrod.nimrod.cfg
+++ b/compiler/nimrod.nimrod.cfg
@@ -20,3 +20,4 @@ import:testability
 define:useStdoutAsStdmsg
 
 cs:partial
+#define:useNodeIds
diff --git a/compiler/sem.nim b/compiler/sem.nim
index c35cff027..b34972219 100644
--- a/compiler/sem.nim
+++ b/compiler/sem.nim
@@ -161,12 +161,13 @@ proc paramsTypeCheck(c: PContext, typ: PType) {.inline.} =
     localError(typ.n.info, errXisNoType, typeToString(typ))
 
 proc expectMacroOrTemplateCall(c: PContext, n: PNode): PSym
-proc semTemplateExpr(c: PContext, n: PNode, s: PSym, semCheck = true): PNode
 proc semDirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode
 proc semWhen(c: PContext, n: PNode, semCheck: bool = true): PNode
 proc isOpImpl(c: PContext, n: PNode): PNode
+proc semTemplateExpr(c: PContext, n: PNode, s: PSym,
+                     flags: TExprFlags = {}): PNode
 proc semMacroExpr(c: PContext, n, nOrig: PNode, sym: PSym,
-                  semCheck: bool = true): PNode
+                  flags: TExprFlags = {}): PNode
 
 proc symFromType(t: PType, info: TLineInfo): PSym =
   if t.sym != nil: return t.sym
@@ -265,7 +266,8 @@ proc semConstExpr(c: PContext, n: PNode): PNode =
 
 include hlo, seminst, semcall
 
-proc semAfterMacroCall(c: PContext, n: PNode, s: PSym): PNode = 
+proc semAfterMacroCall(c: PContext, n: PNode, s: PSym,
+                       flags: TExprFlags): PNode =
   inc(evalTemplateCounter)
   if evalTemplateCounter > 100:
     globalError(s.info, errTemplateInstantiationTooNested)
@@ -281,7 +283,7 @@ proc semAfterMacroCall(c: PContext, n: PNode, s: PSym): PNode =
       # BUGFIX: we cannot expect a type here, because module aliases would not 
       # work then (see the ``tmodulealias`` test)
       # semExprWithType(c, result)
-      result = semExpr(c, result)
+      result = semExpr(c, result, flags)
     of tyStmt:
       result = semStmt(c, result)
     of tyTypeDesc:
@@ -290,14 +292,14 @@ proc semAfterMacroCall(c: PContext, n: PNode, s: PSym): PNode =
       result.typ = makeTypeDesc(c, typ)
       #result = symNodeFromType(c, typ, n.info)
     else:
-      result = semExpr(c, result)
+      result = semExpr(c, result, flags)
       result = fitNode(c, s.typ.sons[0], result)
       #GlobalError(s.info, errInvalidParamKindX, typeToString(s.typ.sons[0]))
   dec(evalTemplateCounter)
   c.friendModule = oldFriend
 
-proc semMacroExpr(c: PContext, n, nOrig: PNode, sym: PSym, 
-                  semCheck: bool = true): PNode = 
+proc semMacroExpr(c: PContext, n, nOrig: PNode, sym: PSym,
+                  flags: TExprFlags = {}): PNode =
   markUsed(n, sym)
   if sym == c.p.owner:
     globalError(n.info, errRecursiveDependencyX, sym.name.s)
@@ -306,7 +308,8 @@ proc semMacroExpr(c: PContext, n, nOrig: PNode, sym: PSym,
   #  c.evalContext = c.createEvalContext(emStatic)
 
   result = evalMacroCall(c.module, n, nOrig, sym)
-  if semCheck: result = semAfterMacroCall(c, result, sym)
+  if efNoSemCheck notin flags:
+    result = semAfterMacroCall(c, result, sym, flags)
 
 proc forceBool(c: PContext, n: PNode): PNode = 
   result = fitNode(c, getSysType(tyBool), n)
diff --git a/compiler/semdata.nim b/compiler/semdata.nim
index b46d83a92..4cb5ad38c 100644
--- a/compiler/semdata.nim
+++ b/compiler/semdata.nim
@@ -42,7 +42,7 @@ type
 
   TExprFlag* = enum 
     efLValue, efWantIterator, efInTypeof, efWantStmt, efDetermineType,
-    efAllowDestructor, efWantValue, efOperand
+    efAllowDestructor, efWantValue, efOperand, efNoSemCheck
   TExprFlags* = set[TExprFlag]
 
   PContext* = ref TContext
diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim
index 6743768a2..9b3b2d73e 100644
--- a/compiler/semexprs.nim
+++ b/compiler/semexprs.nim
@@ -10,11 +10,12 @@
 # this module does the semantic checking for expressions
 # included from sem.nim
 
-proc semTemplateExpr(c: PContext, n: PNode, s: PSym, semCheck = true): PNode = 
+proc semTemplateExpr(c: PContext, n: PNode, s: PSym,
+                     flags: TExprFlags = {}): PNode =
   markUsed(n, s)
   pushInfoContext(n.info)
   result = evalTemplate(n, s, getCurrOwner())
-  if semCheck: result = semAfterMacroCall(c, result, s)
+  if efNoSemCheck notin flags: result = semAfterMacroCall(c, result, s, flags)
   popInfoContext()
 
 proc semFieldAccess(c: PContext, n: PNode, flags: TExprFlags = {}): PNode
@@ -95,8 +96,8 @@ proc semSym(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode =
       else: result = newSymNode(s, n.info)
     else:
       result = newSymNode(s, n.info)
-  of skMacro: result = semMacroExpr(c, n, n, s)
-  of skTemplate: result = semTemplateExpr(c, n, s)
+  of skMacro: result = semMacroExpr(c, n, n, s, flags)
+  of skTemplate: result = semTemplateExpr(c, n, s, flags)
   of skVar, skLet, skResult, skParam, skForVar:
     markUsed(n, s)
     # if a proc accesses a global variable, it is not side effect free:
@@ -793,8 +794,8 @@ proc afterCallActions(c: PContext; n, orig: PNode, flags: TExprFlags): PNode =
   result = n
   let callee = result.sons[0].sym
   case callee.kind
-  of skMacro: result = semMacroExpr(c, result, orig, callee)
-  of skTemplate: result = semTemplateExpr(c, result, callee)
+  of skMacro: result = semMacroExpr(c, result, orig, callee, flags)
+  of skTemplate: result = semTemplateExpr(c, result, callee, flags)
   else:
     semFinishOperands(c, result)
     activate(c, result)
@@ -1966,13 +1967,13 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
           result = semDirectOp(c, n, flags)
         else:
           var p = fixImmediateParams(n)
-          result = semMacroExpr(c, p, p, s)
+          result = semMacroExpr(c, p, p, s, flags)
       of skTemplate:
         if sfImmediate notin s.flags:
           result = semDirectOp(c, n, flags)
         else:
           var p = fixImmediateParams(n)
-          result = semTemplateExpr(c, p, s)
+          result = semTemplateExpr(c, p, s, flags)
       of skType:
         # XXX think about this more (``set`` procs)
         if n.len == 2:
diff --git a/compiler/semgnrc.nim b/compiler/semgnrc.nim
index ffc1a43b2..da4a2a132 100644
--- a/compiler/semgnrc.nim
+++ b/compiler/semgnrc.nim
@@ -47,12 +47,12 @@ proc semGenericStmtSymbol(c: PContext, n: PNode, s: PSym): PNode =
   of skTemplate:
     if macroToExpand(s):
       let n = fixImmediateParams(n)
-      result = semTemplateExpr(c, n, s, false)
+      result = semTemplateExpr(c, n, s, {efNoSemCheck})
     else:
       result = symChoice(c, n, s, scOpen)
   of skMacro: 
     if macroToExpand(s):
-      result = semMacroExpr(c, n, n, s, false)
+      result = semMacroExpr(c, n, n, s, {efNoSemCheck})
     else:
       result = symChoice(c, n, s, scOpen)
   of skGenericParam: 
@@ -126,14 +126,14 @@ proc semGenericStmt(c: PContext, n: PNode,
       case s.kind
       of skMacro:
         if macroToExpand(s):
-          result = semMacroExpr(c, n, n, s, false)
+          result = semMacroExpr(c, n, n, s, {efNoSemCheck})
         else:
           n.sons[0] = symChoice(c, n.sons[0], s, scOption)
           result = n
       of skTemplate: 
         if macroToExpand(s):
           let n = fixImmediateParams(n)
-          result = semTemplateExpr(c, n, s, false)
+          result = semTemplateExpr(c, n, s, {efNoSemCheck})
         else:
           n.sons[0] = symChoice(c, n.sons[0], s, scOption)
           result = n
diff --git a/compiler/semtempl.nim b/compiler/semtempl.nim
index 1432b76f0..ad34eea65 100644
--- a/compiler/semtempl.nim
+++ b/compiler/semtempl.nim
@@ -539,7 +539,7 @@ proc semPatternBody(c: var TemplCtx, n: PNode): PNode =
       elif contains(c.toBind, s.id):
         result = symChoice(c.c, n, s, scClosed)
       elif templToExpand(s):
-        result = semPatternBody(c, semTemplateExpr(c.c, n, s, false))
+        result = semPatternBody(c, semTemplateExpr(c.c, n, s, {efNoSemCheck}))
       else:
         discard
         # we keep the ident unbound for matching instantiated symbols and
@@ -584,7 +584,7 @@ proc semPatternBody(c: var TemplCtx, n: PNode): PNode =
       if s.owner == c.owner and s.kind == skParam: discard
       elif contains(c.toBind, s.id): discard
       elif templToExpand(s):
-        return semPatternBody(c, semTemplateExpr(c.c, n, s, false))
+        return semPatternBody(c, semTemplateExpr(c.c, n, s, {efNoSemCheck}))
     
     if n.kind == nkInfix and n.sons[0].kind == nkIdent:
       # we interpret `*` and `|` only as pattern operators if they occur in
diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim
index c53dc0f7d..a563cf06c 100644
--- a/compiler/semtypes.nim
+++ b/compiler/semtypes.nim
@@ -225,8 +225,16 @@ proc semArray(c: PContext, n: PNode, prev: PType): PType =
         # properly filled-out in semtypinst (see how tyStaticExpr
         # is handled there).
         indx = makeRangeWithStaticExpr(c, e)
-      else:
+      elif e.kind == nkIdent:
         indx = e.typ.skipTypes({tyTypeDesc})
+      else:
+        let x = semConstExpr(c, e)
+        if x.kind in {nkIntLit..nkUInt64Lit}:
+          indx = makeRangeType(c, 0, x.intVal-1, n.info, 
+                               x.typ.skipTypes({tyTypeDesc}))
+        else:
+          indx = x.typ.skipTypes({tyTypeDesc})
+          #localError(n[1].info, errConstExprExpected)
     addSonSkipIntLit(result, indx)
     if indx.kind == tyGenericInst: indx = lastSon(indx)
     if indx.kind notin {tyGenericParam, tyStatic, tyFromExpr}:
diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim
index b9fb0c957..b83c27d22 100644
--- a/compiler/sigmatch.nim
+++ b/compiler/sigmatch.nim
@@ -668,6 +668,8 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
         result = isNone
     else: discard
   of tyOpenArray, tyVarargs:
+    # varargs[expr] is special
+    if f.kind == tyVarargs and f.sons[0].kind == tyExpr: return
     case a.kind
     of tyOpenArray, tyVarargs:
       result = typeRel(c, base(f), base(a))
diff --git a/compiler/transf.nim b/compiler/transf.nim
index 7922acbe9..fb5e321b6 100644
--- a/compiler/transf.nim
+++ b/compiler/transf.nim
@@ -166,6 +166,7 @@ proc transformVarSection(c: PTransf, v: PNode): PTransNode =
         idNodeTablePut(c.transCon.mapping, it.sons[j].sym, newSymNode(newVar))
         defs[j] = newSymNode(newVar).PTransNode
       assert(it.sons[L-2].kind == nkEmpty)
+      defs[L-2] = ast.emptyNode.PTransNode
       defs[L-1] = transform(c, it.sons[L-1])
       result[i] = defs
 
diff --git a/compiler/vm.nim b/compiler/vm.nim
index b365dba9a..fb8749250 100644
--- a/compiler/vm.nim
+++ b/compiler/vm.nim
@@ -48,9 +48,17 @@ type
                               # XXX 'break' should perform cleanup actions
                               # What does the C backend do for it?
 
-proc stackTraceAux(c: PCtx; x: PStackFrame; pc: int) =
+proc stackTraceAux(c: PCtx; x: PStackFrame; pc: int; recursionLimit=100) =
   if x != nil:
-    stackTraceAux(c, x.next, x.comesFrom)
+    if recursionLimit == 0:
+      var calls = 0
+      var x = x
+      while x != nil:
+        inc calls
+        x = x.next
+      msgWriteln($calls & " calls omitted\n")
+      return
+    stackTraceAux(c, x.next, x.comesFrom, recursionLimit-1)
     var info = c.debug[pc]
     # we now use the same format as in system/except.nim
     var s = toFilename(info)
diff --git a/compiler/vmgen.nim b/compiler/vmgen.nim
index 434cb0932..7c0c3d4f5 100644
--- a/compiler/vmgen.nim
+++ b/compiler/vmgen.nim
@@ -1501,7 +1501,7 @@ proc gen(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags = {}) =
     else:
       localError(n.info, errGenerated, "VM is not allowed to 'cast'")
   else:
-    internalError n.info, "too implement " & $n.kind
+    internalError n.info, "cannot generate VM code for " & n.renderTree
 
 proc removeLastEof(c: PCtx) =
   let last = c.code.len-1
diff --git a/doc/lib.txt b/doc/lib.txt
index ca2539631..62efe6a5d 100644
--- a/doc/lib.txt
+++ b/doc/lib.txt
@@ -223,6 +223,34 @@ Internet Protocols and Support
 * `uri <uri.html>`_
   This module provides functions for working with URIs.
 
+* `asyncdispatch <asyncdispatch.html>`_
+  This module implements an asynchronous dispatcher for IO operations.
+
+  **Note:** This module is still largely experimental.
+
+* `asyncnet <asyncnet.html>`_
+  This module implements asynchronous sockets based on the ``asyncdispatch``
+  module.
+
+  **Note:** This module is still largely experimental.
+
+* `asynchttpserver <asynchttpserver.html>`_
+  This module implements an asynchronous HTTP server using the ``asyncnet``
+  module.
+
+  **Note:** This module is still largely experimental.
+
+* `net <net.html>`_
+  This module implements a high-level sockets API. It will replace the
+  ``sockets`` module in the future.
+
+* `rawsockets <rawsockets.html>`_
+  This module implements a low-level sockets API.
+
+* `selectors <selectors.html>`_
+  This module implements a selector API with backends specific to each OS.
+  Currently epoll on Linux and select on other operating systems.
+
 Parsers
 -------
 
diff --git a/lib/nimbase.h b/lib/nimbase.h
index b16b27b2c..cfd33dca1 100644
--- a/lib/nimbase.h
+++ b/lib/nimbase.h
@@ -376,7 +376,7 @@ static inline void GCGuard (void *ptr) { asm volatile ("" :: "X" (ptr)); }
 #  define GC_GUARD
 #endif
 
-/* Test to see if nimrod and the C compiler agrees on the size of a pointer.
+/* Test to see if nimrod and the C compiler agree on the size of a pointer.
    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];
diff --git a/lib/pure/asyncdispatch.nim b/lib/pure/asyncdispatch.nim
index 84b0ebbf8..880458ee5 100644
--- a/lib/pure/asyncdispatch.nim
+++ b/lib/pure/asyncdispatch.nim
@@ -10,13 +10,22 @@
 import os, oids, tables, strutils, macros
 
 import rawsockets
+export TPort
 
 ## AsyncDispatch
-## --------
+## -------------
 ##
 ## This module implements a brand new dispatcher based on Futures.
-## On Windows IOCP is used and on other operating systems the selectors module
-## is used instead.
+## On Windows IOCP is used and on other operating systems the ``selectors``
+## module is used instead.
+##
+## **Note:** This module is still largely experimental.
+
+
+# TODO: Discarded void PFutures need to checked for exception.
+# TODO: Exceptions are currently uncatchable due to the limitation that 
+# you cannot have yield in a try stmt. Perhaps I can get the macro to put
+# a user's try except around ``future.read``.
 
 # -- Futures
 
@@ -151,7 +160,7 @@ when defined(windows) or defined(nimdoc):
     let p = getGlobalDispatcher()
     if CreateIOCompletionPort(sock.THandle, p.ioPort,
                               cast[TCompletionKey](sock), 1) == 0:
-      OSError(OSLastError())
+      osError(osLastError())
     p.handles.incl(sock)
 
   proc verifyPresence(sock: TAsyncFD) =
@@ -188,7 +197,7 @@ when defined(windows) or defined(nimdoc):
           lpNumberOfBytesTransferred, TOSErrorCode(-1))
       dealloc(customOverlapped)
     else:
-      let errCode = OSLastError()
+      let errCode = osLastError()
       if lpOverlapped != nil:
         assert customOverlapped.data.sock == lpCompletionKey.TAsyncFD
         customOverlapped.data.cb(customOverlapped.data.sock,
@@ -198,7 +207,7 @@ when defined(windows) or defined(nimdoc):
         if errCode.int32 == WAIT_TIMEOUT:
           # Timed out
           discard
-        else: OSError(errCode)
+        else: osError(errCode)
 
   var connectExPtr: pointer = nil
   var acceptExPtr: pointer = nil
@@ -215,11 +224,11 @@ when defined(windows) or defined(nimdoc):
   proc initAll() =
     let dummySock = newRawSocket()
     if not initPointer(dummySock, connectExPtr, WSAID_CONNECTEX):
-      OSError(OSLastError())
+      osError(osLastError())
     if not initPointer(dummySock, acceptExPtr, WSAID_ACCEPTEX):
-      OSError(OSLastError())
+      osError(osLastError())
     if not initPointer(dummySock, getAcceptExSockAddrsPtr, WSAID_GETACCEPTEXSOCKADDRS):
-      OSError(OSLastError())
+      osError(osLastError())
 
   proc connectEx(s: TSocketHandle, name: ptr TSockAddr, namelen: cint, 
                   lpSendBuffer: pointer, dwSendDataLength: dword,
@@ -280,7 +289,7 @@ when defined(windows) or defined(nimdoc):
     saddr.sin_addr.s_addr = INADDR_ANY
     if bindAddr(socket.TSocketHandle, cast[ptr TSockAddr](addr(saddr)),
                   sizeof(saddr).TSockLen) < 0'i32:
-      OSError(OSLastError())
+      osError(osLastError())
 
     var aiList = getAddrInfo(address, port, af)
     var success = false
@@ -311,7 +320,7 @@ when defined(windows) or defined(nimdoc):
         # free ``ol``.
         break
       else:
-        lastError = OSLastError()
+        lastError = osLastError()
         if lastError.int32 == ERROR_IO_PENDING:
           # In this case ``ol`` will be deallocated in ``poll``.
           success = true
@@ -331,7 +340,7 @@ when defined(windows) or defined(nimdoc):
     ## Reads **up to** ``size`` bytes from ``socket``. Returned future will
     ## complete once all the data requested is read, a part of the data has been
     ## read, or the socket has disconnected in which case the future will
-    ## complete with a value of ``""`.
+    ## complete with a value of ``""``.
 
 
     # Things to note:
@@ -367,7 +376,7 @@ when defined(windows) or defined(nimdoc):
     let ret = WSARecv(socket.TSocketHandle, addr dataBuf, 1, addr bytesReceived,
                       addr flagsio, cast[POverlapped](ol), nil)
     if ret == -1:
-      let err = OSLastError()
+      let err = osLastError()
       if err.int32 != ERROR_IO_PENDING:
         retFuture.fail(newException(EOS, osErrorMsg(err)))
         dealloc(ol)
@@ -391,7 +400,6 @@ when defined(windows) or defined(nimdoc):
           size
         else:
           bytesReceived
-      assert dataBuf.buf[0] != '\0'
       var data = newString(realSize)
       copyMem(addr data[0], addr dataBuf.buf[0], realSize)
       retFuture.complete($data)
@@ -446,7 +454,7 @@ when defined(windows) or defined(nimdoc):
     var retFuture = newFuture[tuple[address: string, client: TAsyncFD]]()
 
     var clientSock = newRawSocket()
-    if clientSock == OSInvalidSocket: osError(osLastError())
+    if clientSock == osInvalidSocket: osError(osLastError())
 
     const lpOutputLen = 1024
     var lpOutputBuf = newString(lpOutputLen)
@@ -656,8 +664,7 @@ else:
     var retFuture = newFuture[string]()
     
     var readBuffer = newString(size)
-    var sizeRead = 0
-    
+
     proc cb(sock: TAsyncFD): bool =
       result = true
       let res = recv(sock.TSocketHandle, addr readBuffer[0], size,
@@ -670,12 +677,11 @@ else:
         else:
           result = false # We still want this callback to be called.
       elif res == 0:
-        #echo("Disconnected recv: ", sizeRead)
         # Disconnected
         retFuture.complete("")
       else:
+        readBuffer.setLen(res)
         retFuture.complete(readBuffer)
-      #echo("Recv cb result: ", result)
   
     addRead(socket, cb)
     return retFuture
@@ -764,14 +770,24 @@ template createVar(futSymName: string, asyncProc: PNimrodNode,
   result.add newNimNode(nnkYieldStmt).add(futSym) # -> yield future<x>
   valueReceiver = newDotExpr(futSym, newIdentNode("read")) # -> future<x>.read
 
-proc processBody(node, retFutureSym: PNimrodNode): PNimrodNode {.compileTime.} =
+proc processBody(node, retFutureSym: PNimrodNode,
+                 subtypeName: string): PNimrodNode {.compileTime.} =
   result = node
   case node.kind
   of nnkReturnStmt:
     result = newNimNode(nnkStmtList)
-    result.add newCall(newIdentNode("complete"), retFutureSym,
-      if node[0].kind == nnkEmpty: newIdentNode("result") else: node[0])
-    result.add newNimNode(nnkYieldStmt).add(newNilLit())
+    if node[0].kind == nnkEmpty:
+      if subtypeName != "void":
+        result.add newCall(newIdentNode("complete"), retFutureSym,
+            newIdentNode("result"))
+      else:
+        result.add newCall(newIdentNode("complete"), retFutureSym)
+    else:
+      result.add newCall(newIdentNode("complete"), retFutureSym,
+        node[0].processBody(retFutureSym, subtypeName))
+
+    result.add newNimNode(nnkReturnStmt).add(newNilLit())
+    return # Don't process the children of this return stmt
   of nnkCommand:
     if node[0].kind == nnkIdent and node[0].ident == !"await":
       case node[1].kind
@@ -819,7 +835,7 @@ proc processBody(node, retFutureSym: PNimrodNode): PNimrodNode {.compileTime.} =
   else: discard
   
   for i in 0 .. <result.len:
-    result[i] = processBody(result[i], retFutureSym)
+    result[i] = processBody(result[i], retFutureSym, subtypeName)
   #echo(treeRepr(result))
 
 proc getName(node: PNimrodNode): string {.compileTime.} =
@@ -867,7 +883,7 @@ macro async*(prc: stmt): stmt {.immediate.} =
   # ->   <proc_body>
   # ->   complete(retFuture, result)
   var iteratorNameSym = genSym(nskIterator, $prc[0].getName & "Iter")
-  var procBody = prc[6].processBody(retFutureSym)
+  var procBody = prc[6].processBody(retFutureSym, subtypeName)
   if subtypeName != "void":
     procBody.insert(0, newNimNode(nnkVarSection).add(
       newIdentDefs(newIdentNode("result"), returnType[1]))) # -> var result: T
@@ -906,7 +922,7 @@ macro async*(prc: stmt): stmt {.immediate.} =
 
   result[6] = outerProcBody
 
-  echo(toStrLit(result))
+  #echo(toStrLit(result))
 
 proc recvLine*(socket: TAsyncFD): PFuture[string] {.async.} =
   ## Reads a line of data from ``socket``. Returned future will complete once
diff --git a/lib/pure/asynchttpserver.nim b/lib/pure/asynchttpserver.nim
new file mode 100644
index 000000000..74b044e05
--- /dev/null
+++ b/lib/pure/asynchttpserver.nim
@@ -0,0 +1,179 @@
+#
+#
+#            Nimrod's Runtime Library
+#        (c) Copyright 2014 Dominik Picheta
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+## This module implements a high performance asynchronous HTTP server.
+##
+## **Note:** This module is still largely experimental.
+
+import strtabs, asyncnet, asyncdispatch, parseutils, parseurl, strutils
+type
+  TRequest* = object
+    client: PAsyncSocket # TODO: Separate this into a Response object?
+    reqMethod*: string
+    headers*: PStringTable
+    protocol*: tuple[orig: string, major, minor: int]
+    url*: TURL
+    hostname*: string ## The hostname of the client that made the request.
+
+  PAsyncHttpServer* = ref object
+    socket: PAsyncSocket
+
+  THttpCode* = enum
+    Http200 = "200 OK",
+    Http303 = "303 Moved",
+    Http400 = "400 Bad Request",
+    Http404 = "404 Not Found",
+    Http500 = "500 Internal Server Error",
+    Http502 = "502 Bad Gateway"
+
+  THttpVersion* = enum
+    HttpVer11,
+    HttpVer10
+
+proc `==`*(protocol: tuple[orig: string, major, minor: int],
+           ver: THttpVersion): bool =
+  let major =
+    case ver
+    of HttpVer11, HttpVer10: 1
+  let minor =
+    case ver
+    of HttpVer11: 1
+    of HttpVer10: 0
+  result = protocol.major == major and protocol.minor == minor
+
+proc newAsyncHttpServer*(): PAsyncHttpServer =
+  new result
+
+proc sendHeaders*(req: TRequest, headers: PStringTable) {.async.} =
+  ## Sends the specified headers to the requesting client.
+  for k, v in headers:
+    await req.client.send(k & ": " & v & "\c\L")
+
+proc respond*(req: TRequest, code: THttpCode,
+        content: string, headers: PStringTable = newStringTable()) {.async.} =
+  ## Responds to the request with the specified ``HttpCode``, headers and
+  ## content.
+  ##
+  ## This procedure will **not** close the client socket.
+  var customHeaders = headers
+  customHeaders["Content-Length"] = $content.len
+  await req.client.send("HTTP/1.1 " & $code & "\c\L")
+  await sendHeaders(req, headers)
+  await req.client.send("\c\L" & content)
+
+proc newRequest(): TRequest =
+  result.headers = newStringTable(modeCaseInsensitive)
+
+proc parseHeader(line: string): tuple[key, value: string] =
+  var i = 0
+  i = line.parseUntil(result.key, ':')
+  inc(i) # skip :
+  i += line.skipWhiteSpace(i)
+  i += line.parseUntil(result.value, {'\c', '\L'}, i)
+
+proc parseProtocol(protocol: string):  tuple[orig: string, major, minor: int] =
+  var i = protocol.skipIgnoreCase("HTTP/")
+  if i != 5:
+    raise newException(EInvalidValue, "Invalid request protocol. Got: " &
+        protocol)
+  result.orig = protocol
+  i.inc protocol.parseInt(result.major, i)
+  i.inc # Skip .
+  i.inc protocol.parseInt(result.minor, i)
+
+proc processClient(client: PAsyncSocket, address: string,
+                 callback: proc (request: TRequest): PFuture[void]) {.async.} =
+  # GET /path HTTP/1.1
+  # Header: val
+  # \n
+
+  var request = newRequest()
+  # First line - GET /path HTTP/1.1
+  let line = await client.recvLine() # TODO: Timeouts.
+  if line == "":
+    client.close()
+    return
+  let lineParts = line.split(' ')
+  if lineParts.len != 3:
+    request.respond(Http400, "Invalid request. Got: " & line)
+
+  let reqMethod = lineParts[0]
+  let path = lineParts[1]
+  let protocol = lineParts[2]
+
+  # Headers
+  var i = 0
+  while true:
+    i = 0
+    let headerLine = await client.recvLine()
+    if headerLine == "":
+      client.close(); return
+    if headerLine == "\c\L": break
+    # TODO: Compiler crash
+    #let (key, value) = parseHeader(headerLine)
+    let kv = parseHeader(headerLine)
+    request.headers[kv.key] = kv.value
+
+  request.reqMethod = reqMethod
+  request.url = parseUrl(path)
+  try:
+    request.protocol = protocol.parseProtocol()
+  except EInvalidValue:
+    request.respond(Http400, "Invalid request protocol. Got: " & protocol)
+    return
+  request.hostname = address
+  request.client = client
+  
+  case reqMethod.normalize
+  of "get":
+    await callback(request)
+  else:
+    echo(reqMethod.repr)
+    echo(line.repr)
+    request.respond(Http400, "Invalid request method. Got: " & reqMethod)
+
+  # Persistent connections
+  if (request.protocol == HttpVer11 and
+      request.headers["connection"].normalize != "close") or
+     (request.protocol == HttpVer10 and
+      request.headers["connection"].normalize == "keep-alive"):
+    # In HTTP 1.1 we assume that connection is persistent. Unless connection
+    # header states otherwise.
+    # In HTTP 1.0 we assume that the connection should not be persistent.
+    # Unless the connection header states otherwise.
+    await processClient(client, address, callback)
+  else:
+    request.client.close()
+
+proc serve*(server: PAsyncHttpServer, port: TPort,
+            callback: proc (request: TRequest): PFuture[void],
+            address = "") {.async.} =
+  ## Starts the process of listening for incoming HTTP connections on the
+  ## specified address and port.
+  ##
+  ## When a request is made by a client the specified callback will be called.
+  server.socket = newAsyncSocket()
+  server.socket.bindAddr(port, address)
+  server.socket.listen()
+  
+  while true:
+    # TODO: Causes compiler crash.
+    #var (address, client) = await server.socket.acceptAddr()
+    var fut = await server.socket.acceptAddr()
+    processClient(fut.client, fut.address, callback)
+
+when isMainModule:
+  var server = newAsyncHttpServer()
+  proc cb(req: TRequest) {.async.} =
+    #echo(req.reqMethod, " ", req.url)
+    #echo(req.headers)
+    await req.respond(Http200, "Hello World")
+
+  server.serve(TPort(5555), cb)
+  runForever()
diff --git a/lib/pure/asyncnet.nim b/lib/pure/asyncnet.nim
index 748566aaa..daa6c8839 100644
--- a/lib/pure/asyncnet.nim
+++ b/lib/pure/asyncnet.nim
@@ -6,6 +6,44 @@
 #    See the file "copying.txt", included in this
 #    distribution, for details about the copyright.
 #
+
+## This module implements a high-level asynchronous sockets API based on the
+## asynchronous dispatcher defined in the ``asyncdispatch`` module.
+##
+## Example
+## =======
+## 
+## The following example demonstrates a simple chat server.
+##
+## .. code-block::nimrod
+##
+##   import asyncnet, asyncdispatch
+##
+##   var clients: seq[PAsyncSocket] = @[]
+##
+##   proc processClient(client: PAsyncSocket) {.async.} =
+##     while true:
+##       let line = await client.recvLine()
+##       for c in clients:
+##         await c.send(line & "\c\L")
+##
+##   proc serve() {.async.} =
+##     var server = newAsyncSocket()
+##     server.bindAddr(TPort(12345))
+##     server.listen()
+##
+##     while true:
+##       let client = await server.accept()
+##       clients.add client
+##
+##       processClient(client)
+##
+##   serve()
+##   runForever()
+##
+##
+## **Note:** This module is still largely experimental.
+
 import asyncdispatch
 import rawsockets
 import net
diff --git a/lib/pure/httpclient.nim b/lib/pure/httpclient.nim
index 68adf5f49..2a145eb89 100644
--- a/lib/pure/httpclient.nim
+++ b/lib/pure/httpclient.nim
@@ -430,20 +430,30 @@ proc generateHeaders(r: TURL, httpMethod: THttpMethod,
   add(result, "\c\L")
 
 type
-  PAsyncHttpClient = ref object
+  PAsyncHttpClient* = ref object
     socket: PAsyncSocket
     connected: bool
     currentURL: TURL ## Where we are currently connected.
     headers: PStringTable
+    maxRedirects: int
     userAgent: string
 
-proc newAsyncHttpClient*(): PAsyncHttpClient =
+proc newAsyncHttpClient*(userAgent = defUserAgent,
+    maxRedirects = 5): PAsyncHttpClient =
+  ## Creates a new PAsyncHttpClient instance.
+  ##
+  ## ``userAgent`` specifies the user agent that will be used when making
+  ## requests.
+  ##
+  ## ``maxRedirects`` specifies the maximum amount of redirects to follow,
+  ## default is 5.
   new result
   result.headers = newStringTable(modeCaseInsensitive)
   result.userAgent = defUserAgent
+  result.maxRedirects = maxRedirects
 
 proc close*(client: PAsyncHttpClient) =
-  ## Closes any connections held by the HttpClient.
+  ## Closes any connections held by the HTTP client.
   if client.connected:
     client.socket.close()
     client.connected = false
@@ -453,7 +463,9 @@ proc recvFull(socket: PAsyncSocket, size: int): PFuture[string] {.async.} =
   result = ""
   while true:
     if size == result.len: break
-    result.add await socket.recv(size - result.len)
+    let data = await socket.recv(size - result.len)
+    if data == "": break # We've been disconnected.
+    result.add data
 
 proc parseChunks(client: PAsyncHttpClient): PFuture[string] {.async.} =
   result = ""
@@ -534,9 +546,6 @@ proc parseResponse(client: PAsyncHttpClient,
       # Parse HTTP version info and status code.
       var le = skipIgnoreCase(line, "HTTP/", linei)
       if le <= 0:
-        while true:
-          let nl = await client.socket.recvLine()
-          echo("Got another line: ", nl)
         httpError("invalid http version, " & line.repr)
       inc(linei, le)
       le = skipIgnoreCase(line, "1.1", linei)
@@ -586,6 +595,14 @@ proc newConnection(client: PAsyncHttpClient, url: TURL) {.async.} =
 
 proc request*(client: PAsyncHttpClient, url: string, httpMethod = httpGET,
               body = ""): PFuture[TResponse] {.async.} =
+  ## Connects to the hostname specified by the URL and performs a request
+  ## using the method specified.
+  ##
+  ## Connection will kept alive. Further requests on the same ``client`` to
+  ## the same hostname will not require a new connection to be made. The
+  ## connection can be closed by using the ``close`` procedure.
+  ##
+  ## The returned future will complete once the request is completed.
   let r = parseUrl(url)
   await newConnection(client, r)
 
@@ -600,6 +617,19 @@ proc request*(client: PAsyncHttpClient, url: string, httpMethod = httpGET,
   
   result = await parseResponse(client, httpMethod != httpHEAD)
 
+proc get*(client: PAsyncHttpClient, url: string): PFuture[TResponse] {.async.} =
+  ## Connects to the hostname specified by the URL and performs a GET request.
+  ##
+  ## This procedure will follow redirects up to a maximum number of redirects
+  ## specified in ``newAsyncHttpClient``.
+  result = await client.request(url, httpGET)
+  var lastURL = url
+  for i in 1..client.maxRedirects:
+    if result.status.redirection():
+      let redirectTo = getNewLocation(lastURL, result.headers)
+      result = await client.request(redirectTo, httpGET)
+      lastUrl = redirectTo
+
 when isMainModule:
   when true:
     # Async
diff --git a/lib/pure/irc.nim b/lib/pure/irc.nim
index c1b519b0b..83fb231f6 100644
--- a/lib/pure/irc.nim
+++ b/lib/pure/irc.nim
@@ -346,6 +346,7 @@ proc poll*(irc: PIRC, ev: var TIRCEvent,
   var line = TaintedString""
   var socks = @[irc.sock]
   var ret = socks.select(timeout)
+  if ret == -1: osError(osLastError())
   if socks.len() != 0 and ret != 0:
     irc.sock.readLine(line)
     ev = irc.processLine(line.string)
diff --git a/lib/pure/math.nim b/lib/pure/math.nim
index 94570fc68..d258e9a7c 100644
--- a/lib/pure/math.nim
+++ b/lib/pure/math.nim
@@ -75,28 +75,30 @@ proc binom*(n, k: int): int {.noSideEffect.} =
     result = (result * (n + 1 - i)) div i
     
 proc fac*(n: int): int {.noSideEffect.} = 
-  ## computes the faculty function
+  ## computes the faculty/factorial function.
   result = 1
   for i in countup(2, n):
     result = result * i
 
 proc isPowerOfTwo*(x: int): bool {.noSideEffect.} =
-  ## returns true, if x is a power of two, false otherwise.
-  ## Negative numbers are not a power of two.
-  return (x and -x) == x
-
-proc nextPowerOfTwo*(x: int): int =
-  ## returns the nearest power of two, so that
-  ## result**2 >= x > (result-1)**2.
-  result = x - 1
+  ## returns true, if `x` is a power of two, false otherwise.
+  ## Zero and negative numbers are not a power of two.
+  return (x != 0) and ((x and (x - 1)) == 0)
+
+proc nextPowerOfTwo*(x: int): int {.noSideEffect.} =
+  ## returns `x` rounded up to the nearest power of two.
+  ## Zero and negative numbers get rounded up to 1.
+  result = x - 1 
   when defined(cpu64):
     result = result or (result shr 32)
-  result = result or (result shr 16)
-  result = result or (result shr 8)
+  when sizeof(int) > 16:
+    result = result or (result shr 16)
+  when sizeof(int) > 8:
+    result = result or (result shr 8)
   result = result or (result shr 4)
   result = result or (result shr 2)
   result = result or (result shr 1)
-  inc(result)
+  result += 1 + ord(x<=0)
 
 proc countBits32*(n: int32): int {.noSideEffect.} =
   ## counts the set bits in `n`.
diff --git a/lib/pure/net.nim b/lib/pure/net.nim
index 4afb5c6ab..74739630b 100644
--- a/lib/pure/net.nim
+++ b/lib/pure/net.nim
@@ -12,6 +12,9 @@
 {.deadCodeElim: on.}
 import rawsockets, os, strutils, unsigned, parseutils, times
 export TPort
+
+const useWinVersion = defined(Windows) or defined(nimdoc)
+
 type
   IpAddressFamily* {.pure.} = enum ## Describes the type of an IP address
     IPv6, ## IPv6 address
@@ -499,7 +502,7 @@ proc socketError*(socket: PSocket, err: int = -1, async = false) =
   if err == -1 and not (when defined(ssl): socket.isSSL else: false):
     let lastError = osLastError()
     if async:
-      when defined(windows):
+      when useWinVersion:
         if lastError.int32 == WSAEWOULDBLOCK:
           return
         else: osError(lastError)
@@ -525,7 +528,7 @@ proc bindAddr*(socket: PSocket, port = TPort(0), address = "") {.
 
   if address == "":
     var name: TSockaddr_in
-    when defined(windows):
+    when useWinVersion:
       name.sin_family = toInt(AF_INET).int16
     else:
       name.sin_family = toInt(AF_INET)
@@ -1009,7 +1012,7 @@ proc send*(socket: PSocket, data: pointer, size: int): int {.
     if socket.isSSL:
       return SSLWrite(socket.sslHandle, cast[cstring](data), size)
   
-  when defined(windows) or defined(macosx):
+  when useWinVersion or defined(macosx):
     result = send(socket.fd, data, size.cint, 0'i32)
   else:
     when defined(solaris): 
@@ -1088,7 +1091,7 @@ proc connectAsync(socket: PSocket, name: string, port = TPort(0),
       break
     else:
       lastError = osLastError()
-      when defined(windows):
+      when useWinVersion:
         # Windows EINTR doesn't behave same as POSIX.
         if lastError.int32 == WSAEWOULDBLOCK:
           success = true
diff --git a/lib/pure/parseurl.nim b/lib/pure/parseurl.nim
index 937f26f6f..357d1df0f 100644
--- a/lib/pure/parseurl.nim
+++ b/lib/pure/parseurl.nim
@@ -1,13 +1,16 @@
 #
 #
 #            Nimrod's Runtime Library
-#        (c) Copyright 2010 Dominik Picheta
+#        (c) Copyright 2014 Dominik Picheta
 #
 #    See the file "copying.txt", included in this
 #    distribution, for details about the copyright.
 #
 
 ## Parses & constructs URLs.
+##
+## **Note**: This module will be deprecated in the future and merged into a
+## new ``url`` module.
 
 import strutils
 
diff --git a/lib/pure/rawsockets.nim b/lib/pure/rawsockets.nim
index aeaa7f3b5..07b647b68 100644
--- a/lib/pure/rawsockets.nim
+++ b/lib/pure/rawsockets.nim
@@ -17,7 +17,9 @@ import unsigned, os
 when hostos == "solaris":
   {.passl: "-lsocket -lnsl".}
 
-when defined(Windows):
+const useWinVersion = defined(Windows) or defined(nimdoc)
+
+when useWinVersion:
   import winlean
   export WSAEWOULDBLOCK
 else:
@@ -74,7 +76,7 @@ type
     length*: int
     addrList*: seq[string]
 
-when defined(windows):
+when useWinVersion:
   let
     osInvalidSocket* = winlean.INVALID_SOCKET
 
@@ -106,7 +108,7 @@ proc toInt*(typ: TType): cint
 proc toInt*(p: TProtocol): cint
   ## Converts the TProtocol enum to a platform-dependent ``cint``.
 
-when defined(posix):
+when not useWinVersion:
   proc toInt(domain: TDomain): cint =
     case domain
     of AF_UNIX:        result = posix.AF_UNIX
@@ -150,7 +152,7 @@ proc newRawSocket*(domain: TDomain = AF_INET, typ: TType = SOCK_STREAM,
 
 proc close*(socket: TSocketHandle) =
   ## closes a socket.
-  when defined(windows):
+  when useWinVersion:
     discard winlean.closeSocket(socket)
   else:
     discard posix.close(socket)
@@ -164,7 +166,7 @@ proc listen*(socket: TSocketHandle, backlog = SOMAXCONN): cint {.tags: [FReadIO]
   ## Marks ``socket`` as accepting connections. 
   ## ``Backlog`` specifies the maximum length of the 
   ## queue of pending connections.
-  when defined(windows):
+  when useWinVersion:
     result = winlean.listen(socket, cint(backlog))
   else:
     result = posix.listen(socket, cint(backlog))
@@ -181,8 +183,8 @@ proc getAddrInfo*(address: string, port: TPort, af: TDomain = AF_INET, typ: TTyp
   hints.ai_protocol = toInt(prot)
   var gaiResult = getAddrInfo(address, $port, addr(hints), result)
   if gaiResult != 0'i32:
-    when defined(windows):
-      OSError(OSLastError())
+    when useWinVersion:
+      osError(osLastError())
     else:
       raise newException(EOS, $gai_strerror(gaiResult))
 
@@ -224,7 +226,7 @@ proc getServByName*(name, proto: string): TServent {.tags: [FReadIO].} =
   ## and the protocol name specified by ``proto`` matches the s_proto member.
   ##
   ## On posix this will search through the ``/etc/services`` file.
-  when defined(Windows):
+  when useWinVersion:
     var s = winlean.getservbyname(name, proto)
   else:
     var s = posix.getservbyname(name, proto)
@@ -240,7 +242,7 @@ proc getServByPort*(port: TPort, proto: string): TServent {.tags: [FReadIO].} =
   ## protocol name specified by ``proto`` matches the s_proto member.
   ##
   ## On posix this will search through the ``/etc/services`` file.
-  when defined(Windows):
+  when useWinVersion:
     var s = winlean.getservbyport(ze(int16(port)).cint, proto)
   else:
     var s = posix.getservbyport(ze(int16(port)).cint, proto)
@@ -255,7 +257,7 @@ proc getHostByAddr*(ip: string): Thostent {.tags: [FReadIO].} =
   var myaddr: TInAddr
   myaddr.s_addr = inet_addr(ip)
   
-  when defined(windows):
+  when useWinVersion:
     var s = winlean.gethostbyaddr(addr(myaddr), sizeof(myaddr).cuint,
                                   cint(rawsockets.AF_INET))
     if s == nil: osError(osLastError())
@@ -267,7 +269,7 @@ proc getHostByAddr*(ip: string): Thostent {.tags: [FReadIO].} =
   
   result.name = $s.h_name
   result.aliases = cstringArrayToSeq(s.h_aliases)
-  when defined(windows): 
+  when useWinVersion: 
     result.addrtype = TDomain(s.h_addrtype)
   else:
     if s.h_addrtype == posix.AF_INET:
@@ -281,14 +283,14 @@ proc getHostByAddr*(ip: string): Thostent {.tags: [FReadIO].} =
 
 proc getHostByName*(name: string): Thostent {.tags: [FReadIO].} = 
   ## This function will lookup the IP address of a hostname.
-  when defined(Windows):
+  when useWinVersion:
     var s = winlean.gethostbyname(name)
   else:
     var s = posix.gethostbyname(name)
   if s == nil: osError(osLastError())
   result.name = $s.h_name
   result.aliases = cstringArrayToSeq(s.h_aliases)
-  when defined(windows): 
+  when useWinVersion: 
     result.addrtype = TDomain(s.h_addrtype)
   else:
     if s.h_addrtype == posix.AF_INET:
@@ -303,7 +305,7 @@ proc getHostByName*(name: string): Thostent {.tags: [FReadIO].} =
 proc getSockName*(socket: TSocketHandle): TPort = 
   ## returns the socket's associated port number.
   var name: Tsockaddr_in
-  when defined(Windows):
+  when useWinVersion:
     name.sin_family = int16(ord(AF_INET))
   else:
     name.sin_family = posix.AF_INET
@@ -337,7 +339,7 @@ proc setBlocking*(s: TSocketHandle, blocking: bool) =
   ## Sets blocking mode on socket.
   ##
   ## Raises EOS on error.
-  when defined(Windows):
+  when useWinVersion:
     var mode = clong(ord(not blocking)) # 1 for non-blocking, 0 for blocking
     if ioctlsocket(s, FIONBIO, addr(mode)) == -1:
       osError(osLastError())
@@ -418,4 +420,4 @@ proc selectWrite*(writefds: var seq[TSocketHandle],
 
 when defined(Windows):
   var wsa: TWSADATA
-  if WSAStartup(0x0101'i16, addr wsa) != 0: OSError(OSLastError())
+  if WSAStartup(0x0101'i16, addr wsa) != 0: osError(osLastError())
diff --git a/lib/pure/redis.nim b/lib/pure/redis.nim
index 8171dc12b..f4c45b99c 100644
--- a/lib/pure/redis.nim
+++ b/lib/pure/redis.nim
@@ -45,7 +45,7 @@ proc raiseInvalidReply(expected, got: char) =
           [$expected, $got])
 
 proc raiseNoOK(status: string) =
-  if status != "OK":
+  if status != "QUEUED" and status != "OK":
     raise newException(EInvalidReply, "Expected \"OK\" got \"$1\"" % status)
 
 proc parseStatus(r: TRedis): TRedisStatus =
@@ -64,6 +64,10 @@ proc parseStatus(r: TRedis): TRedisStatus =
 proc parseInteger(r: TRedis): TRedisInteger =
   var line = ""
   r.socket.readLine(line)
+
+  if line == "+QUEUED":  # inside of multi
+    return -1
+
   if line == "":
     raise newException(ERedis, "Server closed connection prematurely")
 
@@ -81,10 +85,7 @@ proc recv(sock: TSocket, size: int): TaintedString =
   if sock.recv(cstring(result), size) != size:
     raise newException(EInvalidReply, "recv failed")
 
-proc parseBulk(r: TRedis, allowMBNil = False): TRedisString =
-  var line = ""
-  r.socket.readLine(line.TaintedString)
-  
+proc parseSingle(r: TRedis, line:string, allowMBNil = False): TRedisString =
   # Error.
   if line[0] == '-':
     raise newException(ERedis, strip(line))
@@ -94,6 +95,9 @@ proc parseBulk(r: TRedis, allowMBNil = False): TRedisString =
     if line == "*-1":
        return RedisNil
   
+  if line == "+QUEUED" or line == "+OK" : # inside of a transaction (multi)
+    return nil
+
   if line[0] != '$':
     raiseInvalidReply('$', line[0])
   
@@ -104,18 +108,41 @@ proc parseBulk(r: TRedis, allowMBNil = False): TRedisString =
   var s = r.socket.recv(numBytes+2)
   result = strip(s.string)
 
+proc parseMultiLines(r: TRedis, countLine:string): TRedisList =
+  if countLine.string[0] != '*':
+    raiseInvalidReply('*', countLine.string[0])
+
+  var numElems = parseInt(countLine.string.substr(1))
+  if numElems == -1: return nil
+  result = @[]
+  for i in 1..numElems:
+    var line = ""
+    r.socket.readLine(line.TaintedString)
+    if line[0] == '*':  # after exec() may contain more multi-bulk replies
+      var parsed = r.parseMultiLines(line)
+      for item in parsed:
+        result.add(item)
+    else:
+     result.add(r.parseSingle(line))
+
+proc parseBulk(r: TRedis, allowMBNil = False): TRedisString =
+  var line = ""
+  r.socket.readLine(line.TaintedString)
+
+  if line == "+QUEUED" or line == "+OK": # inside of a transaction (multi)
+    return nil
+
+  return r.parseSingle(line, allowMBNil)
+
 proc parseMultiBulk(r: TRedis): TRedisList =
   var line = TaintedString""
   r.socket.readLine(line)
+
+  if line == "+QUEUED": # inside of a transaction (multi)
+    return nil
     
-  if line.string[0] != '*':
-    raiseInvalidReply('*', line.string[0])
-  
-  var numElems = parseInt(line.string.substr(1))
-  if numElems == -1: return nil
-  result = @[]
-  for i in 1..numElems:
-    result.add(r.parseBulk())
+  return r.parseMultiLines(line)
+
 
 proc sendCommand(r: TRedis, cmd: string, args: varargs[string]) =
   var request = "*" & $(1 + args.len()) & "\c\L"
@@ -722,6 +749,7 @@ proc discardMulti*(r: TRedis) =
 proc exec*(r: TRedis): TRedisList =
   ## Execute all commands issued after MULTI
   r.sendCommand("EXEC")
+
   return r.parseMultiBulk()
 
 proc multi*(r: TRedis) =
diff --git a/lib/pure/selectors.nim b/lib/pure/selectors.nim
index 085344e3e..a4a7b5afd 100644
--- a/lib/pure/selectors.nim
+++ b/lib/pure/selectors.nim
@@ -13,6 +13,7 @@ import tables, os, unsigned, hashes
 
 when defined(linux): import posix, epoll
 elif defined(windows): import winlean
+else: import posix
 
 proc hash*(x: TSocketHandle): THash {.borrow.}
 proc `$`*(x: TSocketHandle): string {.borrow.}
@@ -126,19 +127,12 @@ when defined(linux) or defined(nimdoc):
     else:
       return false
 
-  proc contains*(s: PSelector, key: PSelectorKey): bool =
-    ## Determines whether selector contains this selector key. More accurate
-    ## than checking if the file descriptor is in the selector because it
-    ## ensures that the keys are equal. File descriptors may not always be
-    ## unique especially when an fd is closed and then a new one is opened,
-    ## the new one may have the same value.
-    return key.fd in s and s.fds[key.fd] == key
-
   proc `[]`*(s: PSelector, fd: TSocketHandle): PSelectorKey =
     ## Retrieves the selector key for ``fd``.
     return s.fds[fd]
 
-elif defined(windows):
+else:
+  # TODO: kqueue for bsd/mac os x.
   type
     PSelector* = ref object
       fds: TTable[TSocketHandle, PSelectorKey]
@@ -204,9 +198,9 @@ elif defined(windows):
     
     var retCode = 0
     if timeout != -1:
-      retCode = int(select(TSocketHandle(m+1), addr(rd), addr(wr), nil, addr(tv)))
+      retCode = int(select(cint(m+1), addr(rd), addr(wr), nil, addr(tv)))
     else:
-      retCode = int(select(TSocketHandle(m+1), addr(rd), addr(wr), nil, nil))
+      retCode = int(select(cint(m+1), addr(rd), addr(wr), nil, nil))
     
     if retCode < 0:
       OSError(OSLastError())
@@ -228,11 +222,13 @@ elif defined(windows):
   proc `[]`*(s: PSelector, fd: TSocketHandle): PSelectorKey =
     return s.fds[fd]
 
-elif defined(bsd) or defined(macosx):
-  # TODO: kqueue
-  {.error: "Sorry your platform is not supported yet.".}
-else:
-  {.error: "Sorry your platform is not supported.".}
+proc contains*(s: PSelector, key: PSelectorKey): bool =
+  ## Determines whether selector contains this selector key. More accurate
+  ## than checking if the file descriptor is in the selector because it
+  ## ensures that the keys are equal. File descriptors may not always be
+  ## unique especially when an fd is closed and then a new one is opened,
+  ## the new one may have the same value.
+  return key.fd in s and s.fds[key.fd] == key
 
 when isMainModule:
   # Select()
@@ -242,7 +238,7 @@ when isMainModule:
       sock: TSocket
   
   var sock = socket()
-  sock.setBlocking(false)
+  #sock.setBlocking(false)
   sock.connect("irc.freenode.net", TPort(6667))
   
   var selector = newSelector()
@@ -258,12 +254,3 @@ when isMainModule:
       assert selector.unregister(sock.getFD).fd == sock.getFD
       selector.close()
       break
-  
-  
-  
-  
-  
-  
-  
-  
-  
diff --git a/lib/pure/sockets.nim b/lib/pure/sockets.nim
index 76d37879b..b6acc329f 100644
--- a/lib/pure/sockets.nim
+++ b/lib/pure/sockets.nim
@@ -925,11 +925,12 @@ proc createFdSet(fd: var TFdSet, s: seq[TSocket], m: var int) =
     m = max(m, int(i.fd))
     FD_SET(i.fd, fd)
    
-proc pruneSocketSet(s: var seq[TSocket], fd: var TFdSet) = 
+proc pruneSocketSet(s: var seq[TSocket], fd: var TFdSet) =
   var i = 0
   var L = s.len
   while i < L:
     if FD_ISSET(s[i].fd, fd) == 0'i32:
+      # not set.
       s[i] = s[L-1]
       dec(L)
     else:
@@ -954,9 +955,9 @@ proc checkBuffer(readfds: var seq[TSocket]): int =
   for s in readfds:
     if hasDataBuffered(s):
       inc(result)
-    else:
       res.add(s)
-  readfds = res
+  if result > 0:
+    readfds = res
 
 proc select*(readfds, writefds, exceptfds: var seq[TSocket], 
              timeout = 500): int {.tags: [FReadIO].} = 
@@ -965,8 +966,9 @@ proc select*(readfds, writefds, exceptfds: var seq[TSocket],
   ## If there are none; 0 is returned. 
   ## ``Timeout`` is in miliseconds and -1 can be specified for no timeout.
   ## 
-  ## A socket is removed from the specific ``seq`` when it has data waiting to
-  ## be read/written to or has errors (``exceptfds``).
+  ## Sockets which are **not** ready for reading, writing or which don't have
+  ## errors waiting on them are removed from the ``readfds``, ``writefds``,
+  ## ``exceptfds`` sequences respectively.
   let buffersFilled = checkBuffer(readfds)
   if buffersFilled > 0:
     return buffersFilled
@@ -1013,7 +1015,7 @@ proc selectWrite*(writefds: var seq[TSocket],
                   timeout = 500): int {.tags: [FReadIO].} =
   ## When a socket in ``writefds`` is ready to be written to then a non-zero
   ## value will be returned specifying the count of the sockets which can be
-  ## written to. The sockets which can be written to will also be removed
+  ## written to. The sockets which **cannot** be written to will also be removed
   ## from ``writefds``.
   ##
   ## ``timeout`` is specified in miliseconds and ``-1`` can be specified for
diff --git a/lib/pure/uri.nim b/lib/pure/uri.nim
index 18afd4af6..ee1226a35 100644
--- a/lib/pure/uri.nim
+++ b/lib/pure/uri.nim
@@ -1,11 +1,15 @@
 #
 #
 #            Nimrod's Runtime Library
-#        (c) Copyright 2012 Dominik Picheta
+#        (c) Copyright 2014 Dominik Picheta
 #
 #    See the file "copying.txt", included in this
 #    distribution, for details about the copyright.
 #
+
+## **Note**: This module will be deprecated in the future and merged into a
+## new ``url`` module.
+
 import strutils
 type
   TUrl* = distinct string
@@ -30,4 +34,4 @@ proc add*(url: var TUrl, a: TUrl) =
   url = url / a
 
 when isMainModule:
-  assert($("http://".TUrl / "localhost:5000".TUrl) == "http://localhost:5000")
\ No newline at end of file
+  assert($("http://".TUrl / "localhost:5000".TUrl) == "http://localhost:5000")
diff --git a/lib/system/sysio.nim b/lib/system/sysio.nim
index 56e6a9e5f..02c17b92b 100644
--- a/lib/system/sysio.nim
+++ b/lib/system/sysio.nim
@@ -176,9 +176,10 @@ proc rawEchoNL() {.inline, compilerproc.} = write(stdout, "\n")
 
 # interface to the C procs:
 
-when defined(windows) and not defined(useWinAnsi):
+when (defined(windows) and not defined(useWinAnsi)) or defined(nimdoc):
   include "system/widestrs"
-  
+
+when defined(windows) and not defined(useWinAnsi):  
   proc wfopen(filename, mode: WideCString): pointer {.
     importc: "_wfopen", nodecl.}
   proc wfreopen(filename, mode: WideCString, stream: TFile): TFile {.
diff --git a/lib/windows/winlean.nim b/lib/windows/winlean.nim
index 4d87cf4b2..69a3c5c81 100644
--- a/lib/windows/winlean.nim
+++ b/lib/windows/winlean.nim
@@ -657,7 +657,12 @@ type
     D4*: array [0..7, int8]
 
 const
-  ERROR_IO_PENDING* = 997
+  ERROR_IO_PENDING* = 997 # a.k.a WSA_IO_PENDING
+  WSAECONNABORTED* = 10053
+  WSAECONNRESET* = 10054
+  WSAEDISCON* = 10101
+  WSAENETRESET* = 10052
+  WSAETIMEDOUT* = 10060
 
 proc CreateIoCompletionPort*(FileHandle: THANDLE, ExistingCompletionPort: THANDLE,
                              CompletionKey: DWORD,
diff --git a/tests/assert/tfailedassert.nim b/tests/assert/tfailedassert.nim
index 263893767..4994e13c8 100644
--- a/tests/assert/tfailedassert.nim
+++ b/tests/assert/tfailedassert.nim
@@ -3,7 +3,7 @@ discard """
 WARNING: false first asseertion from bar
 ERROR: false second assertion from bar
 -1
-tests/assert/tfailedassert.nim:27 false assertion from foo
+tfailedassert.nim:27 false assertion from foo
 '''
 """
 
diff --git a/tests/patterns/targlist.nim b/tests/trmacros/targlist.nim
index e416edf0a..e416edf0a 100644
--- a/tests/patterns/targlist.nim
+++ b/tests/trmacros/targlist.nim
diff --git a/tests/patterns/tcse.nim b/tests/trmacros/tcse.nim
index ff04f7d83..ff04f7d83 100644
--- a/tests/patterns/tcse.nim
+++ b/tests/trmacros/tcse.nim
diff --git a/tests/patterns/thoist.nim b/tests/trmacros/thoist.nim
index 7d14c0abf..7d14c0abf 100644
--- a/tests/patterns/thoist.nim
+++ b/tests/trmacros/thoist.nim
diff --git a/tests/patterns/tmatrix.nim b/tests/trmacros/tmatrix.nim
index c825a7792..c825a7792 100644
--- a/tests/patterns/tmatrix.nim
+++ b/tests/trmacros/tmatrix.nim
diff --git a/tests/patterns/tnoalias.nim b/tests/trmacros/tnoalias.nim
index 1d5671362..1d5671362 100644
--- a/tests/patterns/tnoalias.nim
+++ b/tests/trmacros/tnoalias.nim
diff --git a/tests/patterns/tnoendlessrec.nim b/tests/trmacros/tnoendlessrec.nim
index 53891bcc0..53891bcc0 100644
--- a/tests/patterns/tnoendlessrec.nim
+++ b/tests/trmacros/tnoendlessrec.nim
diff --git a/tests/patterns/tor.nim b/tests/trmacros/tor.nim
index 833418919..dc72a96cd 100644
--- a/tests/patterns/tor.nim
+++ b/tests/trmacros/tor.nim
@@ -1,6 +1,7 @@
 discard """
   output: '''3060
-true'''
+true
+3'''
 """
 
 template arithOps: expr = (`+` | `-` | `*`)
@@ -19,3 +20,9 @@ var
   c = false
 a = b and a
 echo a
+
+# bug #798
+template t012{(0|1|2){x}}(x: expr): expr = x+1
+let z = 1
+# outputs 3 thanks to fixpoint iteration:
+echo z
diff --git a/tests/patterns/tpartial.nim b/tests/trmacros/tpartial.nim
index fdaa3414a..fdaa3414a 100644
--- a/tests/patterns/tpartial.nim
+++ b/tests/trmacros/tpartial.nim
diff --git a/tests/patterns/tpatterns.nim b/tests/trmacros/tpatterns.nim
index 6bc8772e3..6bc8772e3 100644
--- a/tests/patterns/tpatterns.nim
+++ b/tests/trmacros/tpatterns.nim
diff --git a/tests/patterns/tstar.nim b/tests/trmacros/tstar.nim
index 8443268f4..8443268f4 100644
--- a/tests/patterns/tstar.nim
+++ b/tests/trmacros/tstar.nim
diff --git a/tests/patterns/tstmtlist.nim b/tests/trmacros/tstmtlist.nim
index 20cb5d688..20cb5d688 100644
--- a/tests/patterns/tstmtlist.nim
+++ b/tests/trmacros/tstmtlist.nim
diff --git a/tests/typerel/texplicitcmp.nim b/tests/typerel/texplicitcmp.nim
new file mode 100644
index 000000000..8aec9885a
--- /dev/null
+++ b/tests/typerel/texplicitcmp.nim
@@ -0,0 +1,32 @@
+discard """
+  output: '''[1 2 3 ]
+[1 2 3 ]
+[1 2 3 ]'''
+"""
+
+# bug #297
+
+import json, tables, algorithm
+
+proc outp(a: openarray[int]) =
+  stdout.write "["
+  for i in a: stdout.write($i & " ")
+  stdout.write "]\n"
+
+proc works() =
+  var f = @[3, 2, 1]
+  sort(f, system.cmp[int])
+  outp(f)
+
+proc weird(json_params: TTable) =
+  var f = @[3, 2, 1]
+  # The following line doesn't compile: type mismatch. Why?
+  sort(f, system.cmp[int])
+  outp(f)
+
+when isMainModule:
+  var t = @[3, 2, 1]
+  sort(t, system.cmp[int])
+  outp(t)
+  works()
+  weird(initTable[string, TJsonNode]())
diff --git a/tests/typerel/tvarargsexpr.nim b/tests/typerel/tvarargsexpr.nim
new file mode 100644
index 000000000..fcb49af61
--- /dev/null
+++ b/tests/typerel/tvarargsexpr.nim
@@ -0,0 +1,18 @@
+discard """
+  output: '''success'''
+"""
+
+#bug #913
+
+import macros
+
+macro thirteen(args: varargs[expr]): expr = 
+  result = newIntLitNode(13)
+
+doAssert(13==thirteen([1,2])) # works
+doAssert(13==thirteen(1,2)) # works
+
+doAssert(13==thirteen(1,[2])) # does not work
+doAssert(13==thirteen([1], 2)) # does not work
+
+echo "success"
diff --git a/tests/vm/tarrayboundeval.nim b/tests/vm/tarrayboundeval.nim
new file mode 100644
index 000000000..9b33a2415
--- /dev/null
+++ b/tests/vm/tarrayboundeval.nim
@@ -0,0 +1,23 @@
+discard """
+  output: '''7
+8 8'''
+"""
+
+#bug 1063
+
+const
+  KeyMax = 227
+  myconst = int((KeyMax + 31) / 32)
+
+type
+  FU = array[int((KeyMax + 31) / 32), cuint]
+
+echo FU.high
+
+type 
+  PKeyboard* = ptr object
+  TKeyboardState* = object
+    display*: pointer
+    internal: array[int((KeyMax + 31)/32), cuint]
+    
+echo myconst, " ", int((KeyMax + 31) / 32)
diff --git a/web/news.txt b/web/news.txt
index 9c84b5490..4aaf10992 100644
--- a/web/news.txt
+++ b/web/news.txt
@@ -3,95 +3,155 @@ News
 ====
 
 
-..
-    2014-XX-XX Version 0.9.4 released
-    =================================
-
-
-    Bugfixes
-    --------
-
-
-    Library Additions
-    -----------------
-
-    - Added ``macros.genSym`` builtin for AST generation.
-    - Added ``macros.newLit`` procs for easier AST generation.
-
-
-    Changes affecting backwards compatibility
-    -----------------------------------------
-
-    - The scoping rules for the ``if`` statement changed for better interaction 
-      with the new syntactic construct ``(;)``.
-    - ``OSError`` family of procedures has been deprecated. Procedures with the same
-      name but which take different parameters have been introduced. These procs now
-      require an error code to be passed to them. This error code can be retrieved
-      using the new ``OSLastError`` proc.
-    - ``os.parentDir`` now returns "" if there is no parent dir.
-    - In CGI scripts stacktraces are shown to the user only 
-      if ``cgi.setStackTraceStdout`` is used.
-    - The symbol binding rules for clean templates changed: ``bind`` for any
-      symbol that's not a parameter is now the default. ``mixin`` can be used
-      to require instantiation scope for a symbol.
-    - ``quoteIfContainsWhite`` now escapes argument in such way that it can be safely
-      passed to shell, instead of just adding double quotes.
-    - ``macros.dumpTree`` and ``macros.dumpLisp`` have been made ``immediate``,
-      ``dumpTreeImm`` and ``dumpLispImm`` are now deprecated.
-    - The ``nil`` statement has been deprecated, use an empty ``discard`` instead.
-    - ``sockets.select`` now prunes sockets that are **not** ready from the list
-      of sockets given to it.
-    - The ``noStackFrame`` pragma has been renamed to ``asmNoStackFrame`` to
-      ensure you only use it when you know what you're doing.
-
-
-    Compiler Additions
-    ------------------
-
-    - The compiler can now warn about "uninitialized" variables. (There are no
-      real uninitialized variables in Nimrod as they are initialized to binary
-      zero). Activate via ``{.warning[Uninit]:on.}``.
-    - The compiler now enforces the ``not nil`` constraint.
-    - The compiler now supports a ``codegenDecl`` pragma for even more control
-      over the generated code.
-    - The compiler now supports a ``computedGoto`` pragma to support very fast
-      dispatching for interpreters and the like.
-    - The old evaluation engine has been replaced by a proper register based
-      virtual machine. This fixes numerous bugs for ``nimrod i`` and for macro
-      evaluation.
-    - ``--gc:none`` produces warnings when code uses the GC.
-    - A ``union`` pragma for better C interoperability is now supported.
-    - A ``packed`` pragma to control the memory packing/alignment of fields in 
-      an object.
-    - Arrays can be annotated to be ``unchecked`` for easier low level
-      manipulations of memory.
-
-
-    Language Additions
-    ------------------
-
-    - Arrays can now be declared with a single integer literal ``N`` instead of a
-      range; the range is then ``0..N-1``.
-    - Added ``requiresInit`` pragma to enforce explicit initialization.
-    - Exported templates are allowed to access hidden fields.
-    - The ``using statement`` enables you to more easily author domain-specific
-      languages and libraries providing OOP-like syntactic sugar.
-    - Added the possibility to override various dot operators in order to handle
-      calls to missing procs and reads from undeclared fields at compile-time.
-    - The overload resolution now supports ``static[T]`` params that must be
-      evaluable at compile-time.
-    - Support for user-defined type classes has been added.
-    - The *command syntax* is supported in a lot more contexts.
-    - Anonymous iterators are now supported and iterators can capture variables
-      of an outer proc.
-    - The experimental ``strongSpaces`` parsing mode has been implemented.
-
-
-    Tools improvements
-    ------------------
-
-    - c2nim can deal with a subset of C++. Use the ``--cpp`` command line option
-      to activate.
+
+2014-XX-XX Version 0.9.4 released
+=================================
+
+The Nimrod development community is proud to announce the release of version
+0.9.4 of the Nimrod compiler and tools.
+
+This release includes about 1300 changes in total including various bug
+fixes, new languages features and standard library additions and improvements.
+This release brings with it support for user-defined type classes, a brand
+new VM for executing Nimrod code at compile-time and new symbol binding
+rules for clean templates.
+It also introduces support for the brand new
+`Babel package manager <https://github.com/nimrod-code/babel>`_ which
+has itself seen its first release recently. Many of the wrappers that were
+present in the standard library have been moved to separate repositories
+and should now be installed using Babel.
+
+Apart from that a new **experimental** Asynchronous IO API has been added via
+the ``asyncdispatch`` and ``asyncnet`` modules. The ``net`` and ``rawsockets``
+modules have also been added and they will likely replace the sockets
+module in the next release. The Asynchronous IO API has been designed to
+take advantage of Linux's epoll and Windows' IOCP APIs, support for BSD's
+kqueue has not been implemented yet but will be in the future.
+The Asynchronous IO API provides both
+a callback interface and an interface which allows you to write code as you
+would if you were writing synchronous code. The latter is done through
+the use of an ``await`` macro which behaves similar to C#'s await. The
+following is a very simple chat server demonstrating Nimrod's new async
+capabilities.
+
+.. code-block::nimrod
+  import asyncnet, asyncdispatch
+
+  var clients: seq[PAsyncSocket] = @[]
+
+  proc processClient(client: PAsyncSocket) {.async.} =
+    while true:
+      let line = await client.recvLine()
+      for c in clients:
+        await c.send(line & "\c\L")
+
+  proc serve() {.async.} =
+    var server = newAsyncSocket()
+    server.bindAddr(TPort(12345))
+    server.listen()
+
+    while true:
+      let client = await server.accept()
+      clients.add client
+
+      processClient(client)
+
+  serve()
+  runForever()
+
+
+Note that this feature has been implemented with Nimrod's macro system and so
+``await`` and ``async`` are no keywords.
+
+
+Library Additions
+-----------------
+
+- Added ``macros.genSym`` builtin for AST generation.
+- Added ``macros.newLit`` procs for easier AST generation.
+- Added module ``logging``.
+- Added module ``asyncdispatch``.
+- Added module ``asyncnet``.
+- Added module ``net``.
+- Added module ``rawsockets``.
+- Added module ``selectors``.
+- Added module ``asynchttpserver``.
+- Added support for the new asynchronous IO in the ``httpclient`` module.
+
+Changes affecting backwards compatibility
+-----------------------------------------
+
+- The scoping rules for the ``if`` statement changed for better interaction 
+  with the new syntactic construct ``(;)``.
+- ``OSError`` family of procedures has been deprecated. Procedures with the same
+  name but which take different parameters have been introduced. These procs now
+  require an error code to be passed to them. This error code can be retrieved
+  using the new ``OSLastError`` proc.
+- ``os.parentDir`` now returns "" if there is no parent dir.
+- In CGI scripts stacktraces are shown to the user only 
+  if ``cgi.setStackTraceStdout`` is used.
+- The symbol binding rules for clean templates changed: ``bind`` for any
+  symbol that's not a parameter is now the default. ``mixin`` can be used
+  to require instantiation scope for a symbol.
+- ``quoteIfContainsWhite`` now escapes argument in such way that it can be safely
+  passed to shell, instead of just adding double quotes.
+- ``macros.dumpTree`` and ``macros.dumpLisp`` have been made ``immediate``,
+  ``dumpTreeImm`` and ``dumpLispImm`` are now deprecated.
+- The ``nil`` statement has been deprecated, use an empty ``discard`` instead.
+- ``sockets.select`` now prunes sockets that are **not** ready from the list
+  of sockets given to it.
+- The ``noStackFrame`` pragma has been renamed to ``asmNoStackFrame`` to
+  ensure you only use it when you know what you're doing.
+
+
+Compiler Additions
+------------------
+
+- The compiler can now warn about "uninitialized" variables. (There are no
+  real uninitialized variables in Nimrod as they are initialized to binary
+  zero). Activate via ``{.warning[Uninit]:on.}``.
+- The compiler now enforces the ``not nil`` constraint.
+- The compiler now supports a ``codegenDecl`` pragma for even more control
+  over the generated code.
+- The compiler now supports a ``computedGoto`` pragma to support very fast
+  dispatching for interpreters and the like.
+- The old evaluation engine has been replaced by a proper register based
+  virtual machine. This fixes numerous bugs for ``nimrod i`` and for macro
+  evaluation.
+- ``--gc:none`` produces warnings when code uses the GC.
+- A ``union`` pragma for better C interoperability is now supported.
+- A ``packed`` pragma to control the memory packing/alignment of fields in 
+  an object.
+- Arrays can be annotated to be ``unchecked`` for easier low level
+  manipulations of memory.
+- Support for the new Babel package manager.
+
+
+Language Additions
+------------------
+
+- Arrays can now be declared with a single integer literal ``N`` instead of a
+  range; the range is then ``0..N-1``.
+- Added ``requiresInit`` pragma to enforce explicit initialization.
+- Exported templates are allowed to access hidden fields.
+- The ``using statement`` enables you to more easily author domain-specific
+  languages and libraries providing OOP-like syntactic sugar.
+- Added the possibility to override various dot operators in order to handle
+  calls to missing procs and reads from undeclared fields at compile-time.
+- The overload resolution now supports ``static[T]`` params that must be
+  evaluable at compile-time.
+- Support for user-defined type classes has been added.
+- The *command syntax* is supported in a lot more contexts.
+- Anonymous iterators are now supported and iterators can capture variables
+  of an outer proc.
+- The experimental ``strongSpaces`` parsing mode has been implemented.
+
+
+Tools improvements
+------------------
+
+- c2nim can deal with a subset of C++. Use the ``--cpp`` command line option
+  to activate.
 
 
 2014-02-11 Nimrod Featured in Dr. Dobb's Journal
diff --git a/web/nimrod.ini b/web/nimrod.ini
index 0ebc4b089..b29bcff30 100644
--- a/web/nimrod.ini
+++ b/web/nimrod.ini
@@ -62,7 +62,8 @@ srcdoc2: "pure/ftpclient;pure/memfiles;pure/subexes;pure/collections/critbits"
 srcdoc2: "pure/asyncio;pure/actors;core/locks;pure/oids;pure/endians;pure/uri"
 srcdoc2: "pure/nimprof;pure/unittest;packages/docutils/highlite"
 srcdoc2: "packages/docutils/rst;packages/docutils/rstast"
-srcdoc2: "packages/docutils/rstgen;pure/logging"
+srcdoc2: "packages/docutils/rstgen;pure/logging;pure/asyncdispatch;pure/asyncnet"
+srcdoc2: "pure/rawsockets;pure/asynchttpserver;pure/net;pure/selectors"
 
 webdoc: "wrappers/libcurl;pure/md5;wrappers/mysql;wrappers/iup"
 webdoc: "wrappers/sqlite3;wrappers/postgres;wrappers/tinyc"