summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--compiler/ccgexprs.nim7
-rw-r--r--compiler/ccgstmts.nim32
-rw-r--r--compiler/ccgtypes.nim21
-rw-r--r--compiler/ccgutils.nim2
-rw-r--r--compiler/guards.nim4
-rw-r--r--compiler/installer.ini114
-rw-r--r--compiler/nimfix/nimfix.nim.cfg2
-rw-r--r--compiler/nimsuggest/nimsuggest.nim11
-rw-r--r--compiler/nimsuggest/nimsuggest.nim.cfg2
-rw-r--r--compiler/options.nim2
-rw-r--r--compiler/sem.nim4
-rw-r--r--compiler/semexprs.nim83
-rw-r--r--compiler/semfold.nim12
-rw-r--r--compiler/seminst.nim4
-rw-r--r--compiler/semmacrosanity.nim8
-rw-r--r--compiler/sempass2.nim12
-rw-r--r--compiler/semtypes.nim2
-rw-r--r--compiler/sigmatch.nim31
-rw-r--r--compiler/transf.nim6
-rw-r--r--compiler/types.nim42
-rw-r--r--compiler/vm.nim21
-rw-r--r--compiler/vmdef.nim9
-rw-r--r--compiler/vmgen.nim46
-rw-r--r--compiler/vmmarshal.nim283
-rw-r--r--config/nim.cfg2
-rw-r--r--doc/lib.txt47
-rw-r--r--doc/nimsuggest.txt174
-rw-r--r--doc/tools.txt5
-rw-r--r--doc/tut1.txt72
-rw-r--r--koch.nim27
-rw-r--r--lib/impure/rdstdin.nim2
-rw-r--r--lib/impure/re.nim4
-rw-r--r--lib/impure/zipfiles.nim86
-rw-r--r--lib/js/dom.nim2
-rw-r--r--lib/nimbase.h10
-rw-r--r--lib/posix/termios.nim15
-rw-r--r--lib/pure/asyncdispatch.nim111
-rw-r--r--lib/pure/asynchttpserver.nim90
-rw-r--r--lib/pure/asyncnet.nim118
-rw-r--r--lib/pure/basic3d.nim256
-rw-r--r--lib/pure/collections/tables.nim11
-rw-r--r--lib/pure/ftpclient.nim2
-rw-r--r--lib/pure/gentabs.nim64
-rw-r--r--lib/pure/marshal.nim53
-rw-r--r--lib/pure/math.nim19
-rw-r--r--lib/pure/pegs.nimfix1770
-rw-r--r--lib/pure/strtabs.nim8
-rw-r--r--lib/pure/strutils.nim3
-rw-r--r--lib/pure/terminal.nim13
-rw-r--r--lib/pure/times.nim46
-rw-r--r--lib/pure/unicode.nim25
-rw-r--r--lib/pure/uri.nim33
-rw-r--r--lib/system.nim4
-rw-r--r--lib/system/excpt.nim86
-rw-r--r--lib/windows/winlean.nim116
-rw-r--r--tests/ccgbugs/tpartialcs.nim20
-rw-r--r--tests/collections/tcounttable.nim19
-rw-r--r--tests/cpp/tcppraise.nim17
-rw-r--r--tests/distinct/tdistinct_consts.nim20
-rw-r--r--tests/exception/texceptionbreak.nim20
-rw-r--r--tests/exception/texcsub.nim8
-rw-r--r--tests/exception/tfinally4.nim8
-rw-r--r--tests/exception/tnestedreturn.nim4
-rw-r--r--tests/exception/tonraise.nim8
-rw-r--r--tests/macros/treturnsempty.nim12
-rw-r--r--tests/overload/tspec.nim39
-rw-r--r--tests/sets/tsets.nim170
-rw-r--r--tests/stdlib/tdialogs.nim17
-rw-r--r--tests/template/tdefault_nil.nim14
-rw-r--r--tests/testament/categories.nim2
-rw-r--r--tests/testament/specs.nim16
-rw-r--r--tests/testament/tester.nim9
-rw-r--r--tests/tuples/tuple_with_nil.nim766
-rw-r--r--tests/tuples/tuple_with_seq.nim46
-rw-r--r--tests/types/temptyseqs.nim66
-rw-r--r--todo.txt22
-rw-r--r--tools/niminst/niminst.nim68
-rw-r--r--tools/niminst/nsis.tmpl18
-rw-r--r--web/assets/style.css4
-rw-r--r--web/documentation.txt21
-rw-r--r--web/download.txt12
-rw-r--r--web/learn.txt6
-rw-r--r--web/news.txt703
-rw-r--r--web/question.txt29
-rw-r--r--web/ticker.txt10
-rw-r--r--web/website.ini6
86 files changed, 3308 insertions, 2906 deletions
diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim
index 93a9dd65d..05a3602d1 100644
--- a/compiler/ccgexprs.nim
+++ b/compiler/ccgexprs.nim
@@ -964,8 +964,11 @@ proc genEcho(p: BProc, n: PNode) =
   var args: Rope = nil
   var a: TLoc
   for i in countup(0, n.len-1):
-    initLocExpr(p, n.sons[i], a)
-    addf(args, ", $1? ($1)->data:\"nil\"", [rdLoc(a)])
+    if n.sons[i].skipConv.kind == nkNilLit:
+      add(args, ", \"nil\"")
+    else:
+      initLocExpr(p, n.sons[i], a)
+      addf(args, ", $1? ($1)->data:\"nil\"", [rdLoc(a)])
   linefmt(p, cpsStmts, "printf($1$2);$n",
           makeCString(repeat("%s", n.len) & tnl), args)
 
diff --git a/compiler/ccgstmts.nim b/compiler/ccgstmts.nim
index b6572d960..6d29b1684 100644
--- a/compiler/ccgstmts.nim
+++ b/compiler/ccgstmts.nim
@@ -551,12 +551,7 @@ proc genBreakStmt(p: BProc, t: PNode) =
   lineF(p, cpsStmts, "goto $1;$n", [label])
 
 proc getRaiseFrmt(p: BProc): string =
-  if p.module.compileToCpp:
-    result = "throw NimException($1, $2);$n"
-  elif getCompilerProc("Exception") != nil:
-    result = "#raiseException((#Exception*)$1, $2);$n"
-  else:
-    result = "#raiseException((#E_Base*)$1, $2);$n"
+  result = "#raiseException((#Exception*)$1, $2);$n"
 
 proc genRaiseStmt(p: BProc, t: PNode) =
   if p.inExceptBlock > 0:
@@ -797,11 +792,8 @@ proc genTryCpp(p: BProc, t: PNode, d: var TLoc) =
   #  finallyPart();
   if not isEmptyType(t.typ) and d.k == locNone:
     getTemp(p, t.typ, d)
-  var
-    exc: Rope
-    i, length, blen: int
   genLineDir(p, t)
-  exc = getTempName()
+  let exc = getTempName()
   if getCompilerProc("Exception") != nil:
     discard cgsym(p.module, "Exception")
   else:
@@ -809,20 +801,23 @@ proc genTryCpp(p: BProc, t: PNode, d: var TLoc) =
   add(p.nestedTryStmts, t)
   startBlock(p, "try {$n")
   expr(p, t.sons[0], d)
-  length = sonsLen(t)
+  let length = sonsLen(t)
   endBlock(p, ropecg(p.module, "} catch (NimException& $1) {$n", [exc]))
   if optStackTrace in p.options:
-    linefmt(p, cpsStmts, "#setFrame((TFrame*)&F);$n")
+    linefmt(p, cpsStmts, "#setFrame((TFrame*)&FR);$n")
   inc p.inExceptBlock
-  i = 1
+  var i = 1
   var catchAllPresent = false
   while (i < length) and (t.sons[i].kind == nkExceptBranch):
-    blen = sonsLen(t.sons[i])
+    let blen = sonsLen(t.sons[i])
     if i > 1: addf(p.s(cpsStmts), "else ", [])
     if blen == 1:
       # general except section:
       catchAllPresent = true
-      exprBlock(p, t.sons[i].sons[0], d)
+      startBlock(p)
+      expr(p, t.sons[i].sons[0], d)
+      linefmt(p, cpsStmts, "#popCurrentException();$n")
+      endBlock(p)
     else:
       var orExpr: Rope = nil
       for j in countup(0, blen - 2):
@@ -832,7 +827,10 @@ proc genTryCpp(p: BProc, t: PNode, d: var TLoc) =
               "#isObj($1.exp->m_type, $2)",
               [exc, genTypeInfo(p.module, t.sons[i].sons[j].typ)])
       lineF(p, cpsStmts, "if ($1) ", [orExpr])
-      exprBlock(p, t.sons[i].sons[blen-1], d)
+      startBlock(p)
+      expr(p, t.sons[i].sons[blen-1], d)
+      linefmt(p, cpsStmts, "#popCurrentException();$n")
+      endBlock(p)
     inc(i)
 
   # reraise the exception if there was no catch all
@@ -912,7 +910,7 @@ proc genTry(p: BProc, t: PNode, d: var TLoc) =
   startBlock(p, "else {$n")
   linefmt(p, cpsStmts, "#popSafePoint();$n")
   if optStackTrace in p.options:
-    linefmt(p, cpsStmts, "#setFrame((TFrame*)&F);$n")
+    linefmt(p, cpsStmts, "#setFrame((TFrame*)&FR);$n")
   inc p.inExceptBlock
   var i = 1
   while (i < length) and (t.sons[i].kind == nkExceptBranch):
diff --git a/compiler/ccgtypes.nim b/compiler/ccgtypes.nim
index 60ebf591b..3742fd2fd 100644
--- a/compiler/ccgtypes.nim
+++ b/compiler/ccgtypes.nim
@@ -11,20 +11,21 @@
 
 # ------------------------- Name Mangling --------------------------------
 
-proc mangleField(name: string): string =
-  result = mangle(name)
-  result[0] = result[0].toUpper # Mangling makes everything lowercase,
-                                # but some identifiers are C keywords
-
 proc isKeyword(w: PIdent): bool =
-  # nimrod and C++ share some keywords
-  # it's more efficient to test the whole nimrod keywords range
+  # Nim and C++ share some keywords
+  # it's more efficient to test the whole Nim keywords range
   case w.id
   of ccgKeywordsLow..ccgKeywordsHigh,
      nimKeywordsLow..nimKeywordsHigh,
      ord(wInline): return true
   else: return false
 
+proc mangleField(name: PIdent): string =
+  result = mangle(name.s)
+  if isKeyword(name):
+    result[0] = result[0].toUpper # Mangling makes everything lowercase,
+                                  # but some identifiers are C keywords
+
 proc mangleName(s: PSym): Rope =
   result = s.loc.r
   if result == nil:
@@ -110,7 +111,7 @@ proc mapSetType(typ: PType): TCTypeKind =
   else: result = ctArray
 
 proc mapType(typ: PType): TCTypeKind =
-  ## Maps a nimrod type to a C type
+  ## Maps a Nim type to a C type
   case typ.kind
   of tyNone, tyStmt: result = ctVoid
   of tyBool: result = ctBool
@@ -379,7 +380,7 @@ proc mangleRecFieldName(field: PSym, rectype: PType): Rope =
       ({sfImportc, sfExportc} * rectype.sym.flags != {}):
     result = field.loc.r
   else:
-    result = rope(mangleField(field.name.s))
+    result = rope(mangleField(field.name))
   if result == nil: internalError(field.info, "mangleRecFieldName")
 
 proc genRecordFieldsAux(m: BModule, n: PNode,
@@ -642,7 +643,7 @@ proc getTypeDescAux(m: BModule, typ: PType, check: var IntSet): Rope =
               result.add getTypeDescAux(m, typeInSlot, check)
         else:
           inc i
-      
+
       if chunkStart != 0:
         result.add cppName.data.substr(chunkStart)
       else:
diff --git a/compiler/ccgutils.nim b/compiler/ccgutils.nim
index 4e94c1867..4ba6643ec 100644
--- a/compiler/ccgutils.nim
+++ b/compiler/ccgutils.nim
@@ -176,7 +176,7 @@ proc mangle*(name: string): string =
   result = newStringOfCap(name.len)
   case name[0]
   of Letters:
-    result.add(name[0].toLower)
+    result.add(name[0])
   of Digits:
     result.add("N" & name[0])
   else:
diff --git a/compiler/guards.nim b/compiler/guards.nim
index dc2b24add..df2c1dd75 100644
--- a/compiler/guards.nim
+++ b/compiler/guards.nim
@@ -123,7 +123,7 @@ proc neg(n: PNode): PNode =
         let eAsNode = newIntNode(nkIntLit, e.sym.position)
         if not inSet(n.sons[1], eAsNode): s.add eAsNode
       result.sons[1] = s
-    elif lengthOrd(t) < 1000:
+    elif t.kind notin {tyString, tySequence} and lengthOrd(t) < 1000:
       result.sons[1] = complement(n.sons[1])
     else:
       # not ({2, 3, 4}.contains(x))   x != 2 and x != 3 and x != 4
@@ -908,5 +908,5 @@ proc buildProperFieldCheck(access, check: PNode): PNode =
 proc checkFieldAccess*(m: TModel, n: PNode) =
   for i in 1..n.len-1:
     let check = buildProperFieldCheck(n.sons[0], n.sons[i])
-    if m.doesImply(check) != impYes:
+    if check != nil and m.doesImply(check) != impYes:
       message(n.info, warnProveField, renderTree(n.sons[0])); break
diff --git a/compiler/installer.ini b/compiler/installer.ini
index 12a8e702d..fff82cb5b 100644
--- a/compiler/installer.ini
+++ b/compiler/installer.ini
@@ -47,7 +47,7 @@ Start: "doc/overview.html"
 
 [Other]
 Files: "readme.txt;install.txt;contributors.txt;copying.txt"
-Files: "configure;makefile"
+Files: "makefile"
 Files: "*.ini"
 Files: "koch.nim"
 
@@ -70,6 +70,10 @@ Files: "doc/*.nim"
 Files: "doc/*.cfg"
 Files: "compiler/nimfix/*.nim"
 Files: "compiler/nimfix/*.cfg"
+Files: "compiler/nimsuggest/*.nim"
+Files: "compiler/nimsuggest/*.cfg"
+Files: "compiler/plugins/locals/*.nim"
+Files: "compiler/plugins/active.nim"
 Files: "tools/*.nim"
 Files: "tools/*.cfg"
 Files: "tools/*.tmpl"
@@ -97,13 +101,8 @@ Files: "lib/pure/concurrency/*.cfg"
 Files: "lib/impure/*.nim"
 Files: "lib/wrappers/*.nim"
 
-Files: "lib/wrappers/cairo/*.nim"
-Files: "lib/wrappers/gtk/*.nim"
-Files: "lib/wrappers/lua/*.nim"
-Files: "lib/wrappers/opengl/*.nim"
 Files: "lib/wrappers/readline/*.nim"
 Files: "lib/wrappers/sdl/*.nim"
-Files: "lib/wrappers/x11/*.nim"
 Files: "lib/wrappers/zip/*.nim"
 Files: "lib/wrappers/zip/libzip_all.c"
 
@@ -115,8 +114,6 @@ Files: "lib/packages/docutils/*.nim"
 
 [Other]
 Files: "examples/*.nim"
-Files: "examples/gtk/*.nim"
-Files: "examples/0mq/*.nim"
 Files: "examples/c++iface/*.nim"
 Files: "examples/objciface/*.nim"
 Files: "examples/cross_calculator/"
@@ -126,12 +123,109 @@ Files: "examples/*.txt"
 Files: "examples/*.cfg"
 Files: "examples/*.tmpl"
 
+Files: "tests/actiontable/*.nim"
+Files: "tests/alias/*.nim"
+Files: "tests/ambsym/*.nim"
+Files: "tests/array/*.nim"
+Files: "tests/assign/*.nim"
+Files: "tests/astoverload/*.nim"
+Files: "tests/async/*.nim"
+Files: "tests/benchmarks/*.nim"
+Files: "tests/bind/*.nim"
+Files: "tests/borrow/*.nim"
+Files: "tests/casestmt/*.nim"
+Files: "tests/ccgbugs/*.nim"
+Files: "tests/clearmsg/*.nim"
+Files: "tests/closure/*.nim"
+Files: "tests/cnstseq/*.nim"
+Files: "tests/collections/*.nim"
+Files: "tests/compiles/*.nim"
+Files: "tests/concat/*.nim"
+Files: "tests/concepts/*.nim"
+Files: "tests/constr/*.nim"
+Files: "tests/constraints/*.nim"
+Files: "tests/controlflow/*.nim"
+Files: "tests/converter/*.nim"
+Files: "tests/cpp/*.nim"
+Files: "tests/defaultprocparam/*.nim"
+Files: "tests/deprecated/*.nim"
+Files: "tests/destructor/*.nim"
+Files: "tests/dir with space/*.nim"
+Files: "tests/discard/*.nim"
+Files: "tests/distinct/*.nim"
+Files: "tests/dll/*.nim"
+Files: "tests/effects/*.nim"
+Files: "tests/enum/*.nim"
+Files: "tests/exception/*.nim"
+Files: "tests/exprs/*.nim"
+Files: "tests/fields/*.nim"
+Files: "tests/float/*.nim"
+Files: "tests/friends/*.nim"
+Files: "tests/gc/*.nim"
+Files: "tests/generics/*.nim"
+Files: "tests/gensym/*.nim"
+Files: "tests/global/*.nim"
+Files: "tests/implicit/*.nim"
+Files: "tests/init/*.nim"
+Files: "tests/iter/*.nim"
+Files: "tests/js/*.nim"
+Files: "tests/js/*.cfg"
+Files: "tests/let/*.nim"
+Files: "tests/lexer/*.nim"
+Files: "tests/lookups/*.nim"
+Files: "tests/macros/*.nim"
+Files: "tests/magics/*.nim"
+Files: "tests/metatype/*.nim"
+Files: "tests/method/*.nim"
+Files: "tests/misc/*.nim"
+Files: "tests/modules/*.nim"
+Files: "tests/namedparams/*.nim"
+Files: "tests/notnil/*.nim"
+Files: "tests/objects/*.nim"
+Files: "tests/objvariant/*.nim"
+Files: "tests/openarray/*.nim"
+Files: "tests/osproc/*.nim"
+Files: "tests/overflw/*.nim"
+Files: "tests/overload/*.nim"
+Files: "tests/parallel/*.nim"
+Files: "tests/parallel/*.cfg"
+Files: "tests/parser/*.nim"
+Files: "tests/pragmas/*.nim"
+Files: "tests/proc/*.nim"
+Files: "tests/procvar/*.nim"
+Files: "tests/range/*.nim"
+Files: "tests/rodfiles/*.nim"
+Files: "tests/seq/*.nim"
+Files: "tests/sets/*.nim"
+Files: "tests/showoff/*.nim"
+Files: "tests/specialops/*.nim"
+Files: "tests/stdlib/*.nim"
+Files: "tests/system/*.nim"
+Files: "tests/template/*.nim"
+Files: "tests/testament/*.nim"
+Files: "tests/testdata/*.nim"
+Files: "tests/threads/*.nim"
+Files: "tests/threads/*.cfg"
+Files: "tests/trmacros/*.nim"
+Files: "tests/tuples/*.nim"
+Files: "tests/typerel/*.nim"
+Files: "tests/types/*.nim"
+Files: "tests/usingstmt/*.nim"
+Files: "tests/varres/*.nim"
+Files: "tests/varstmt/*.nim"
+Files: "tests/vm/*.nim"
+Files: "tests/readme.txt"
+Files: "tests/testament/css/*.css"
+Files: "tests/testament/*.cfg"
+Files: "lib/pure/unidecode/unidecode.dat"
 
 [Windows]
 Files: "bin/nim.exe"
-Files: "bin/nim_debug.exe"
 Files: "bin/c2nim.exe"
 Files: "bin/nimgrep.exe"
+Files: "bin/nimsuggest.exe"
+Files: "bin/nimble.exe"
+Files: "bin/*.dll"
 
 Files: "dist/*.dll"
 Files: "koch.exe"
@@ -142,7 +236,7 @@ BinPath: r"bin;dist\mingw\bin;dist"
 ;           Section | dir | zipFile | size hint (in KB) | url | exe start menu entry
 Download: r"Documentation|doc|docs.zip|13824|http://nim-lang.org/download/docs-${version}.zip|overview.html"
 Download: r"C Compiler (MingW)|dist|mingw.zip|82944|http://nim-lang.org/download/${mingw}.zip"
-Download: r"Aporia IDE|dist|aporia.zip|97997|http://nim-lang.org/download/aporia-0.1.3.zip|aporia\bin\aporia.exe"
+Download: r"Aporia IDE|dist|aporia.zip|97997|http://nim-lang.org/download/aporia-0.3.0.zip|aporia-0.3.0\bin\aporia.exe"
 ; for now only NSIS supports optional downloads
 
 [UnixBin]
diff --git a/compiler/nimfix/nimfix.nim.cfg b/compiler/nimfix/nimfix.nim.cfg
index 533563a98..73219d6f8 100644
--- a/compiler/nimfix/nimfix.nim.cfg
+++ b/compiler/nimfix/nimfix.nim.cfg
@@ -5,7 +5,7 @@ hint[XDeclaredButNotUsed]:off
 path:"$projectPath/.."
 
 path:"$lib/packages/docutils"
-path:"$nim/compiler"
+path:"../../compiler"
 
 define:useStdoutAsStdmsg
 symbol:nimfix
diff --git a/compiler/nimsuggest/nimsuggest.nim b/compiler/nimsuggest/nimsuggest.nim
index b45ca475c..8285d81d9 100644
--- a/compiler/nimsuggest/nimsuggest.nim
+++ b/compiler/nimsuggest/nimsuggest.nim
@@ -82,7 +82,8 @@ proc action(cmd: string) =
   if cmd[i] == ';':
     i = parseQuoted(cmd, dirtyfile, i+1)
   i += skipWhile(cmd, seps, i)
-  var line, col = -1
+  var line = -1
+  var col = 0
   i += parseInt(cmd, line, i)
   i += skipWhile(cmd, seps, i)
   i += parseInt(cmd, col, i)
@@ -97,7 +98,7 @@ proc action(cmd: string) =
   resetModule dirtyIdx
   if dirtyIdx != gProjectMainIdx:
     resetModule gProjectMainIdx
-  gTrackPos = newLineInfo(dirtyIdx, line, col)
+  gTrackPos = newLineInfo(dirtyIdx, line, col-1)
   #echo dirtyfile, gDirtyBufferIdx, " project ", gProjectMainIdx
   gErrorCounter = 0
   if not isKnownFile:
@@ -150,11 +151,11 @@ proc mainCommand =
 
 proc processCmdLine*(pass: TCmdLinePass, cmd: string) =
   var p = parseopt.initOptParser(cmd)
-  while true: 
+  while true:
     parseopt.next(p)
     case p.kind
-    of cmdEnd: break 
-    of cmdLongoption, cmdShortOption: 
+    of cmdEnd: break
+    of cmdLongoption, cmdShortOption:
       case p.key.normalize
       of "port": gPort = parseInt(p.val).Port
       of "address": gAddress = p.val
diff --git a/compiler/nimsuggest/nimsuggest.nim.cfg b/compiler/nimsuggest/nimsuggest.nim.cfg
index 062092f16..acca17396 100644
--- a/compiler/nimsuggest/nimsuggest.nim.cfg
+++ b/compiler/nimsuggest/nimsuggest.nim.cfg
@@ -6,7 +6,7 @@ hint[XDeclaredButNotUsed]:off
 path:"$projectPath/../.."
 
 path:"$lib/packages/docutils"
-path:"$nim/compiler"
+path:"../../compiler"
 
 define:useStdoutAsStdmsg
 define:nimsuggest
diff --git a/compiler/options.nim b/compiler/options.nim
index 65250f519..998ab7781 100644
--- a/compiler/options.nim
+++ b/compiler/options.nim
@@ -1,7 +1,7 @@
 #
 #
 #           The Nim Compiler
-#        (c) Copyright 2013 Andreas Rumpf
+#        (c) Copyright 2015 Andreas Rumpf
 #
 #    See the file "copying.txt", included in this
 #    distribution, for details about the copyright.
diff --git a/compiler/sem.nim b/compiler/sem.nim
index 2e13c88c3..346a17df1 100644
--- a/compiler/sem.nim
+++ b/compiler/sem.nim
@@ -89,6 +89,10 @@ proc fitNode(c: PContext, formal: PType, arg: PNode): PNode =
       let x = result.skipConv
       if x.kind == nkPar and formal.kind != tyExpr:
         changeType(x, formal, check=true)
+      else:
+        result = skipHiddenSubConv(result)
+        #result.typ = takeType(formal, arg.typ)
+        #echo arg.info, " picked ", result.typ.typeToString
 
 proc inferWithMetatype(c: PContext, formal: PType,
                        arg: PNode, coerceDistincts = false): PNode
diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim
index eb8d0c561..cd6ba3753 100644
--- a/compiler/semexprs.nim
+++ b/compiler/semexprs.nim
@@ -24,7 +24,7 @@ proc semFieldAccess(c: PContext, n: PNode, flags: TExprFlags = {}): PNode
 proc semOperand(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
   # same as 'semExprWithType' but doesn't check for proc vars
   result = semExpr(c, n, flags + {efOperand})
-  if result.kind == nkEmpty:
+  if result.kind == nkEmpty and result.typ.isNil:
     # do not produce another redundant error message:
     #raiseRecoverableError("")
     result = errorNode(c, n)
@@ -447,6 +447,7 @@ proc changeType(n: PNode, newType: PType, check: bool) =
   of nkPar:
     let tup = newType.skipTypes({tyGenericInst})
     if tup.kind != tyTuple:
+      if tup.kind == tyObject: return
       internalError(n.info, "changeType: no tuple type for constructor")
     elif sonsLen(n) > 0 and n.sons[0].kind == nkExprColonExpr:
       # named tuple?
@@ -535,43 +536,55 @@ proc semArrayConstr(c: PContext, n: PNode, flags: TExprFlags): PNode =
   result.typ.sons[0] = makeRangeType(c, 0, sonsLen(result) - 1, n.info)
 
 proc fixAbstractType(c: PContext, n: PNode) =
-  # XXX finally rewrite that crap!
-  for i in countup(1, sonsLen(n) - 1):
-    var it = n.sons[i]
-    case it.kind
-    of nkHiddenStdConv, nkHiddenSubConv:
-      if it.sons[1].kind == nkBracket:
-        it.sons[1].typ = arrayConstrType(c, it.sons[1])
-        #it.sons[1] = semArrayConstr(c, it.sons[1])
-      if skipTypes(it.typ, abstractVar).kind in {tyOpenArray, tyVarargs}:
-        #if n.sons[0].kind == nkSym and IdentEq(n.sons[0].sym.name, "[]="):
-        #  debug(n)
-
-        var s = skipTypes(it.sons[1].typ, abstractVar)
-        if s.kind == tyArrayConstr and s.sons[1].kind == tyEmpty:
-          s = copyType(s, getCurrOwner(), false)
-          skipTypes(s, abstractVar).sons[1] = elemType(
-              skipTypes(it.typ, abstractVar))
-          it.sons[1].typ = s
-        elif s.kind == tySequence and s.sons[0].kind == tyEmpty:
-          s = copyType(s, getCurrOwner(), false)
-          skipTypes(s, abstractVar).sons[0] = elemType(
-              skipTypes(it.typ, abstractVar))
-          it.sons[1].typ = s
-
-      elif skipTypes(it.sons[1].typ, abstractVar).kind in
-          {tyNil, tyArrayConstr, tyTuple, tySet}:
+  for i in 1 .. < n.len:
+    let it = n.sons[i]
+    # do not get rid of nkHiddenSubConv for OpenArrays, the codegen needs it:
+    if it.kind == nkHiddenSubConv and
+        skipTypes(it.typ, abstractVar).kind notin {tyOpenArray, tyVarargs}:
+      if skipTypes(it.sons[1].typ, abstractVar).kind in
+            {tyNil, tyArrayConstr, tyTuple, tySet}:
         var s = skipTypes(it.typ, abstractVar)
         if s.kind != tyExpr:
           changeType(it.sons[1], s, check=true)
         n.sons[i] = it.sons[1]
-    of nkBracket:
-      # an implicitly constructed array (passed to an open array):
-      n.sons[i] = semArrayConstr(c, it, {})
-    else:
-      discard
-      #if (it.typ == nil):
-      #  InternalError(it.info, "fixAbstractType: " & renderTree(it))
+  when false:
+    # XXX finally rewrite that crap!
+    for i in countup(1, sonsLen(n) - 1):
+      var it = n.sons[i]
+      case it.kind
+      of nkHiddenStdConv, nkHiddenSubConv:
+        if it.sons[1].kind == nkBracket:
+          it.sons[1].typ = arrayConstrType(c, it.sons[1])
+          #it.sons[1] = semArrayConstr(c, it.sons[1])
+        if skipTypes(it.typ, abstractVar).kind in {tyOpenArray, tyVarargs}:
+          #if n.sons[0].kind == nkSym and IdentEq(n.sons[0].sym.name, "[]="):
+          #  debug(n)
+
+          var s = skipTypes(it.sons[1].typ, abstractVar)
+          if s.kind == tyArrayConstr and s.sons[1].kind == tyEmpty:
+            s = copyType(s, getCurrOwner(), false)
+            skipTypes(s, abstractVar).sons[1] = elemType(
+                skipTypes(it.typ, abstractVar))
+            it.sons[1].typ = s
+          elif s.kind == tySequence and s.sons[0].kind == tyEmpty:
+            s = copyType(s, getCurrOwner(), false)
+            skipTypes(s, abstractVar).sons[0] = elemType(
+                skipTypes(it.typ, abstractVar))
+            it.sons[1].typ = s
+
+        elif skipTypes(it.sons[1].typ, abstractVar).kind in
+            {tyNil, tyArrayConstr, tyTuple, tySet}:
+          var s = skipTypes(it.typ, abstractVar)
+          if s.kind != tyExpr:
+            changeType(it.sons[1], s, check=true)
+          n.sons[i] = it.sons[1]
+      of nkBracket:
+        # an implicitly constructed array (passed to an open array):
+        n.sons[i] = semArrayConstr(c, it, {})
+      else:
+        discard
+        #if (it.typ == nil):
+        #  InternalError(it.info, "fixAbstractType: " & renderTree(it))
 
 proc skipObjConv(n: PNode): PNode =
   case n.kind
@@ -2040,7 +2053,7 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
   of nkEmpty, nkNone, nkCommentStmt:
     discard
   of nkNilLit:
-    result.typ = getSysType(tyNil)
+    if result.typ == nil: result.typ = getSysType(tyNil)
   of nkIntLit:
     if result.typ == nil: setIntLitType(result)
   of nkInt8Lit:
diff --git a/compiler/semfold.nim b/compiler/semfold.nim
index 796dde9a6..da24005c2 100644
--- a/compiler/semfold.nim
+++ b/compiler/semfold.nim
@@ -286,10 +286,13 @@ proc evalOp(m: TMagic, n, a, b, c: PNode): PNode =
   of mNot: result = newIntNodeT(1 - getInt(a), n)
   of mCard: result = newIntNodeT(nimsets.cardSet(a), n)
   of mBitnotI, mBitnotI64: result = newIntNodeT(not getInt(a), n)
-  of mLengthStr, mXLenStr: result = newIntNodeT(len(getStr(a)), n)
+  of mLengthStr, mXLenStr:
+    if a.kind == nkNilLit: result = newIntNodeT(0, n)
+    else: result = newIntNodeT(len(getStr(a)), n)
   of mLengthArray: result = newIntNodeT(lengthOrd(a.typ), n)
   of mLengthSeq, mLengthOpenArray, mXLenSeq:
-    result = newIntNodeT(sonsLen(a), n) # BUGFIX
+    if a.kind == nkNilLit: result = newIntNodeT(0, n)
+    else: result = newIntNodeT(sonsLen(a), n) # BUGFIX
   of mUnaryPlusI, mUnaryPlusF64: result = a # throw `+` away
   of mToFloat, mToBiggestFloat:
     result = newFloatNodeT(toFloat(int(getInt(a))), n)
@@ -431,7 +434,8 @@ proc evalOp(m: TMagic, n, a, b, c: PNode): PNode =
      mExit, mInc, ast.mDec, mEcho, mSwap, mAppendStrCh,
      mAppendStrStr, mAppendSeqElem, mSetLengthStr, mSetLengthSeq,
      mParseExprToAst, mParseStmtToAst, mExpandToAst, mTypeTrait, mDotDot,
-     mNLen..mNError, mEqRef, mSlurp, mStaticExec, mNGenSym, mSpawn, mParallel:
+     mNLen..mNError, mEqRef, mSlurp, mStaticExec, mNGenSym, mSpawn,
+     mParallel, mPlugin:
     discard
   else: internalError(a.info, "evalOp(" & $m & ')')
 
@@ -651,7 +655,7 @@ proc getConstExpr(m: PSym, n: PNode): PNode =
     result = copyNode(n)
   of nkIfExpr:
     result = getConstIfExpr(m, n)
-  of nkCall, nkCommand, nkCallStrLit, nkPrefix, nkInfix:
+  of nkCallKinds:
     if n.sons[0].kind != nkSym: return
     var s = n.sons[0].sym
     if s.kind != skProc: return
diff --git a/compiler/seminst.nim b/compiler/seminst.nim
index f72e2dc5b..b2aef63a8 100644
--- a/compiler/seminst.nim
+++ b/compiler/seminst.nim
@@ -187,7 +187,9 @@ proc instantiateProcType(c: PContext, pt: TIdTable,
       let param = copySym(oldParam)
       param.owner = prc
       param.typ = result.sons[i]
-      param.ast = oldParam.ast.copyTree
+      if oldParam.ast != nil:
+        param.ast = fitNode(c, param.typ, oldParam.ast)
+
       # don't be lazy here and call replaceTypeVarsN(cl, originalParams[i])!
       result.n.sons[i] = newSymNode(param)
       addDecl(c, param)
diff --git a/compiler/semmacrosanity.nim b/compiler/semmacrosanity.nim
index 2ef7a54e7..bb9814a16 100644
--- a/compiler/semmacrosanity.nim
+++ b/compiler/semmacrosanity.nim
@@ -16,9 +16,9 @@ proc ithField(n: PNode, field: int): PSym =
   result = nil
   case n.kind
   of nkRecList:
-    for i in countup(0, sonsLen(n) - 1): 
+    for i in countup(0, sonsLen(n) - 1):
       result = ithField(n.sons[i], field-i)
-      if result != nil: return 
+      if result != nil: return
   of nkRecCase:
     if n.sons[0].kind != nkSym: internalError(n.info, "ithField")
     result = ithField(n.sons[0], field-1)
@@ -34,7 +34,7 @@ proc ithField(n: PNode, field: int): PSym =
   else: discard
 
 proc annotateType*(n: PNode, t: PType) =
-  let x = t.skipTypes(abstractInst)
+  let x = t.skipTypes(abstractInst+{tyRange})
   # Note: x can be unequal to t and we need to be careful to use 't'
   # to not to skip tyGenericInst
   case n.kind
@@ -80,7 +80,7 @@ proc annotateType*(n: PNode, t: PType) =
     if x.kind in {tyString, tyCString}:
       n.typ = t
     else:
-      globalError(n.info, "string literal must be of some string type")    
+      globalError(n.info, "string literal must be of some string type")
   of nkNilLit:
     if x.kind in NilableTypes:
       n.typ = t
diff --git a/compiler/sempass2.nim b/compiler/sempass2.nim
index 6bc0fa32c..adf03be64 100644
--- a/compiler/sempass2.nim
+++ b/compiler/sempass2.nim
@@ -560,7 +560,10 @@ proc trackCase(tracked: PEffects, n: PNode) =
   track(tracked, n.sons[0])
   let oldState = tracked.init.len
   let oldFacts = tracked.guards.len
-  let interesting = interestingCaseExpr(n.sons[0]) and warnProveField in gNotes
+  let stringCase = skipTypes(n.sons[0].typ,
+        abstractVarRange-{tyTypeDesc}).kind in {tyFloat..tyFloat128, tyString}
+  let interesting = not stringCase and interestingCaseExpr(n.sons[0]) and
+        warnProveField in gNotes
   var inter: TIntersection = @[]
   var toCover = 0
   for i in 1.. <n.len:
@@ -575,13 +578,8 @@ proc trackCase(tracked: PEffects, n: PNode) =
     for i in oldState.. <tracked.init.len:
       addToIntersection(inter, tracked.init[i])
 
-  let exh = case skipTypes(n.sons[0].typ, abstractVarRange-{tyTypeDesc}).kind
-            of tyFloat..tyFloat128, tyString:
-              lastSon(n).kind == nkElse
-            else:
-              true
   setLen(tracked.init, oldState)
-  if exh:
+  if not stringCase or lastSon(n).kind == nkElse:
     for id, count in items(inter):
       if count >= toCover: tracked.init.add id
     # else we can't merge
diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim
index 304fe6d14..8c7bd7243 100644
--- a/compiler/semtypes.nim
+++ b/compiler/semtypes.nim
@@ -629,7 +629,7 @@ proc skipGenericInvocation(t: PType): PType {.inline.} =
   result = t
   if result.kind == tyGenericInvocation:
     result = result.sons[0]
-  if result.kind == tyGenericBody:
+  while result.kind in {tyGenericInst, tyGenericBody}:
     result = lastSon(result)
 
 proc addInheritedFields(c: PContext, check: var IntSet, pos: var int,
diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim
index 5c8a3bc58..2a9d15b5a 100644
--- a/compiler/sigmatch.nim
+++ b/compiler/sigmatch.nim
@@ -147,6 +147,7 @@ proc copyCandidate(a: var TCandidate, b: TCandidate) =
 
 proc sumGeneric(t: PType): int =
   var t = t
+  var isvar = 1
   while true:
     case t.kind
     of tyGenericInst, tyArray, tyRef, tyPtr, tyDistinct, tyArrayConstr,
@@ -154,18 +155,20 @@ proc sumGeneric(t: PType): int =
       t = t.lastSon
       inc result
     of tyVar:
-      # but do not make 'var T' more specific than 'T'!
       t = t.sons[0]
+      inc result
+      inc isvar
     of tyGenericInvocation, tyTuple:
-      result = ord(t.kind == tyGenericInvocation)
+      result += ord(t.kind == tyGenericInvocation)
       for i in 0 .. <t.len: result += t.sons[i].sumGeneric
       break
     of tyGenericParam, tyExpr, tyStatic, tyStmt, tyTypeDesc: break
     of tyBool, tyChar, tyEnum, tyObject, tyProc, tyPointer,
         tyString, tyCString, tyInt..tyInt64, tyFloat..tyFloat128,
         tyUInt..tyUInt64:
-      return 1
-    else: return 0
+      return isvar
+    else:
+      return 0
 
 #var ggDebug: bool
 
@@ -919,6 +922,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
 
   of tyAnd:
     considerPreviousT:
+      result = isEqual
       for branch in f.sons:
         let x = typeRel(c, branch, aOrig)
         if x < isSubtype: return isNone
@@ -1196,15 +1200,6 @@ proc isInlineIterator*(t: PType): bool =
   result = t.kind == tyIter or
           (t.kind == tyBuiltInTypeClass and t.base.kind == tyIter)
 
-proc isEmptyContainer*(t: PType): bool =
-  case t.kind
-  of tyExpr, tyNil: result = true
-  of tyArray, tyArrayConstr: result = t.sons[1].kind == tyEmpty
-  of tySet, tySequence, tyOpenArray, tyVarargs:
-    result = t.sons[0].kind == tyEmpty
-  of tyGenericInst: result = isEmptyContainer(t.lastSon)
-  else: result = false
-
 proc incMatches(m: var TCandidate; r: TTypeRelation; convMatch = 1) =
   case r
   of isConvertible, isIntConv: inc(m.convMatches, convMatch)
@@ -1309,7 +1304,7 @@ proc paramTypesMatchAux(m: var TCandidate, f, argType: PType,
     if arg.typ == nil:
       result = arg
     elif skipTypes(arg.typ, abstractVar-{tyTypeDesc}).kind == tyTuple:
-      result = implicitConv(nkHiddenStdConv, f, copyTree(arg), m, c)
+      result = implicitConv(nkHiddenSubConv, f, arg, m, c)
     elif arg.typ.isEmptyContainer:
       result = arg.copyTree
       result.typ = getInstantiatedType(c, arg, m, f)
@@ -1324,7 +1319,7 @@ proc paramTypesMatchAux(m: var TCandidate, f, argType: PType,
     inc(m.exactMatches)
     result = arg
     if skipTypes(f, abstractVar-{tyTypeDesc}).kind in {tyTuple}:
-      result = implicitConv(nkHiddenStdConv, f, arg, m, c)
+      result = implicitConv(nkHiddenSubConv, f, arg, m, c)
   of isNone:
     # do not do this in ``typeRel`` as it then can't infere T in ``ref T``:
     if a.kind in {tyProxy, tyUnknown}:
@@ -1470,9 +1465,7 @@ proc matchesAux(c: PContext, n, nOrig: PNode,
         m.state = csNoMatch
         return
     if formal.typ.kind == tyVar:
-      if n.isLValue:
-        inc(m.genericMatches, 100)
-      else:
+      if not n.isLValue:
         m.state = csNoMatch
         return
 
@@ -1578,6 +1571,8 @@ proc matchesAux(c: PContext, n, nOrig: PNode,
           #assert(container == nil)
           if container.isNil:
             container = newNodeIT(nkBracket, n.sons[a].info, arrayConstr(c, arg))
+          else:
+            incrIndexType(container.typ)
           addSon(container, arg)
           setSon(m.call, formal.position + 1,
                  implicitConv(nkHiddenStdConv, formal.typ, container, m, c))
diff --git a/compiler/transf.nim b/compiler/transf.nim
index 2143b6bec..57547b682 100644
--- a/compiler/transf.nim
+++ b/compiler/transf.nim
@@ -379,6 +379,9 @@ proc transformConv(c: PTransf, n: PNode): PTransNode =
       result = transformSons(c, n)
   of tyOpenArray, tyVarargs:
     result = transform(c, n.sons[1])
+    PNode(result).typ = takeType(n.typ, n.sons[1].typ)
+    #echo n.info, " came here and produced ", typeToString(PNode(result).typ),
+    #   " from ", typeToString(n.typ), " and ", typeToString(n.sons[1].typ)
   of tyCString:
     if source.kind == tyString:
       result = newTransNode(nkStringToCString, n, 1)
@@ -713,8 +716,7 @@ proc transform(c: PTransf, n: PNode): PTransNode =
     add(result, PTransNode(newSymNode(labl)))
   of nkBreakStmt: result = transformBreak(c, n)
   of nkWhileStmt: result = transformWhile(c, n)
-  of nkCall, nkHiddenCallConv, nkCommand, nkInfix, nkPrefix, nkPostfix,
-     nkCallStrLit:
+  of nkCallKinds:
     result = transformCall(c, n)
   of nkAddr, nkHiddenAddr:
     result = transformAddrDeref(c, n, nkDerefExpr, nkHiddenDeref)
diff --git a/compiler/types.nim b/compiler/types.nim
index 7f05e7051..e205f5722 100644
--- a/compiler/types.nim
+++ b/compiler/types.nim
@@ -1439,3 +1439,45 @@ proc skipConv*(n: PNode): PNode =
 proc skipConvTakeType*(n: PNode): PNode =
   result = n.skipConv
   result.typ = n.typ
+
+proc isEmptyContainer*(t: PType): bool =
+  case t.kind
+  of tyExpr, tyNil: result = true
+  of tyArray, tyArrayConstr: result = t.sons[1].kind == tyEmpty
+  of tySet, tySequence, tyOpenArray, tyVarargs:
+    result = t.sons[0].kind == tyEmpty
+  of tyGenericInst: result = isEmptyContainer(t.lastSon)
+  else: result = false
+
+proc takeType*(formal, arg: PType): PType =
+  # param: openArray[string] = []
+  # [] is an array constructor of length 0 of type string!
+  if arg.kind == tyNil:
+    # and not (formal.kind == tyProc and formal.callConv == ccClosure):
+    result = formal
+  elif formal.kind in {tyOpenArray, tyVarargs, tySequence} and
+      arg.isEmptyContainer:
+    let a = copyType(arg.skipTypes({tyGenericInst}), arg.owner, keepId=false)
+    a.sons[ord(arg.kind in {tyArray, tyArrayConstr})] = formal.sons[0]
+    result = a
+  elif formal.kind in {tyTuple, tySet} and arg.kind == formal.kind:
+    result = formal
+  else:
+    result = arg
+
+proc skipHiddenSubConv*(n: PNode): PNode =
+  if n.kind == nkHiddenSubConv:
+    # param: openArray[string] = []
+    # [] is an array constructor of length 0 of type string!
+    let formal = n.typ
+    result = n.sons[1]
+    let arg = result.typ
+    let dest = takeType(formal, arg)
+    if dest == arg and formal.kind != tyExpr:
+      #echo n.info, " came here for ", formal.typeToString
+      result = n
+    else:
+      result = copyTree(result)
+      result.typ = dest
+  else:
+    result = n
diff --git a/compiler/vm.nim b/compiler/vm.nim
index 6fae5a8b7..1c6c9a30b 100644
--- a/compiler/vm.nim
+++ b/compiler/vm.nim
@@ -16,7 +16,8 @@ import ast except getstr
 
 import
   strutils, astalgo, msgs, vmdef, vmgen, nimsets, types, passes, unsigned,
-  parser, vmdeps, idents, trees, renderer, options, transf, parseutils
+  parser, vmdeps, idents, trees, renderer, options, transf, parseutils,
+  vmmarshal
 
 from semfold import leValueConv, ordinalValToString
 from evaltempl import evalTemplate
@@ -371,11 +372,6 @@ template handleJmpBack() {.dirty.} =
       globalError(c.debug[pc], errTooManyIterations)
   dec(c.loopIterations)
 
-proc skipColon(n: PNode): PNode =
-  result = n
-  if n.kind == nkExprColonExpr:
-    result = n.sons[1]
-
 proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
   var pc = start
   var tos = tos
@@ -1369,6 +1365,19 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
       while typ.kind == tyTypeDesc and typ.len > 0: typ = typ.sons[0]
       createStr regs[ra]
       regs[ra].node.strVal = typ.typeToString(preferExported)
+    of opcMarshalLoad:
+      let ra = instr.regA
+      let rb = instr.regB
+      inc pc
+      let typ = c.types[c.code[pc].regBx - wordExcess]
+      putIntoReg(regs[ra], loadAny(regs[rb].node.strVal, typ))
+    of opcMarshalStore:
+      decodeB(rkNode)
+      inc pc
+      let typ = c.types[c.code[pc].regBx - wordExcess]
+      createStrKeepNode(regs[ra])
+      if regs[ra].node.strVal.isNil: regs[ra].node.strVal = newStringOfCap(1000)
+      storeAny(regs[ra].node.strVal, typ, regs[rb].regToNode)
     inc pc
 
 proc execute(c: PCtx, start: int): PNode =
diff --git a/compiler/vmdef.nim b/compiler/vmdef.nim
index b4892d010..047009f01 100644
--- a/compiler/vmdef.nim
+++ b/compiler/vmdef.nim
@@ -66,7 +66,8 @@ type
     opcMulSet, opcPlusSet, opcMinusSet, opcSymdiffSet, opcConcatStr,
     opcContainsSet, opcRepr, opcSetLenStr, opcSetLenSeq,
     opcSwap, opcIsNil, opcOf, opcIs,
-    opcSubStr, opcParseFloat, opcConv, opcCast, opcQuit, opcReset,
+    opcSubStr, opcParseFloat, opcConv, opcCast,
+    opcQuit, opcReset,
     opcNarrowS, opcNarrowU,
 
     opcAddStrCh,
@@ -132,7 +133,8 @@ type
     opcLdImmInt,  # dest = immediate value
     opcNBindSym,
     opcSetType,   # dest.typ = types[Bx]
-    opcTypeTrait
+    opcTypeTrait,
+    opcMarshalLoad, opcMarshalStore
 
   TBlock* = object
     label*: PSym
@@ -221,7 +223,8 @@ proc registerCallback*(c: PCtx; name: string; callback: VmCallback) =
 const
   firstABxInstr* = opcTJmp
   largeInstrs* = { # instructions which use 2 int32s instead of 1:
-    opcSubStr, opcConv, opcCast, opcNewSeq, opcOf}
+    opcSubStr, opcConv, opcCast, opcNewSeq, opcOf,
+    opcMarshalLoad, opcMarshalStore}
   slotSomeTemp* = slotTempUnknown
   relativeJumps* = {opcTJmp, opcFJmp, opcJmp, opcJmpBack}
 
diff --git a/compiler/vmgen.nim b/compiler/vmgen.nim
index b354061a9..0743a4502 100644
--- a/compiler/vmgen.nim
+++ b/compiler/vmgen.nim
@@ -76,6 +76,11 @@ proc codeListing(c: PCtx, result: var string, start=0; last = -1) =
     elif opc in {opcLdConst, opcAsgnConst}:
       result.addf("\t$#\tr$#, $#", ($opc).substr(3), x.regA,
         c.constants[x.regBx-wordExcess].renderTree)
+    elif opc in {opcMarshalLoad, opcMarshalStore}:
+      let y = c.code[i+1]
+      result.addf("\t$#\tr$#, r$#, $#", ($opc).substr(3), x.regA, x.regB,
+        c.types[y.regBx-wordExcess].typeToString)
+      inc i
     else:
       result.addf("\t$#\tr$#, $#", ($opc).substr(3), x.regA, x.regBx-wordExcess)
     result.add("\t#")
@@ -696,8 +701,7 @@ proc genCard(c: PCtx; n: PNode; dest: var TDest) =
   c.gABC(n, opcCard, dest, tmp)
   c.freeTemp(tmp)
 
-proc genMagic(c: PCtx; n: PNode; dest: var TDest) =
-  let m = n.sons[0].sym.magic
+proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) =
   case m
   of mAnd: c.genAndOr(n, opcFJmp, dest)
   of mOr:  c.genAndOr(n, opcTJmp, dest)
@@ -1028,6 +1032,22 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest) =
     # mGCref, mGCunref,
     internalError(n.info, "cannot generate code for: " & $m)
 
+proc genMarshalLoad(c: PCtx, n: PNode, dest: var TDest) =
+  ## Signature: proc to*[T](data: string): T
+  if dest < 0: dest = c.getTemp(n.typ)
+  var tmp = c.genx(n.sons[1])
+  c.gABC(n, opcMarshalLoad, dest, tmp)
+  c.gABx(n, opcMarshalLoad, 0, c.genType(n.typ))
+  c.freeTemp(tmp)
+
+proc genMarshalStore(c: PCtx, n: PNode, dest: var TDest) =
+  ## Signature: proc `$$`*[T](x: T): string
+  if dest < 0: dest = c.getTemp(n.typ)
+  var tmp = c.genx(n.sons[1])
+  c.gABC(n, opcMarshalStore, dest, tmp)
+  c.gABx(n, opcMarshalStore, 0, c.genType(n.sons[1].typ))
+  c.freeTemp(tmp)
+
 const
   atomicTypes = {tyBool, tyChar,
     tyExpr, tyStmt, tyTypeDesc, tyStatic,
@@ -1533,6 +1553,15 @@ proc matches(s: PSym; x: string): bool =
     dec L
   result = true
 
+proc matches(s: PSym; y: varargs[string]): bool =
+  var s = s
+  var L = y.len-1
+  while L >= 0:
+    if s == nil or y[L].cmpIgnoreStyle(s.name.s) != 0: return false
+    s = if sfFromGeneric in s.flags: s.owner.owner else: s.owner
+    dec L
+  result = true
+
 proc procIsCallback(c: PCtx; s: PSym): bool =
   if s.offset < -1: return true
   var i = -2
@@ -1570,8 +1599,17 @@ proc gen(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags = {}) =
     else:
       internalError(n.info, "cannot generate code for: " & s.name.s)
   of nkCallKinds:
-    if n.sons[0].kind == nkSym and n.sons[0].sym.magic != mNone:
-      genMagic(c, n, dest)
+    if n.sons[0].kind == nkSym:
+      let s = n.sons[0].sym
+      if s.magic != mNone:
+        genMagic(c, n, dest, s.magic)
+      elif matches(s, "stdlib", "marshal", "to"):
+        genMarshalLoad(c, n, dest)
+      elif matches(s, "stdlib", "marshal", "$$"):
+        genMarshalStore(c, n, dest)
+      else:
+        genCall(c, n, dest)
+        clearDest(c, n, dest)
     else:
       genCall(c, n, dest)
       clearDest(c, n, dest)
diff --git a/compiler/vmmarshal.nim b/compiler/vmmarshal.nim
new file mode 100644
index 000000000..293d0d949
--- /dev/null
+++ b/compiler/vmmarshal.nim
@@ -0,0 +1,283 @@
+#
+#
+#           The Nim Compiler
+#        (c) Copyright 2015 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+## Implements marshaling for the VM.
+
+import streams, json, intsets, tables, ast, astalgo, idents, types, msgs
+
+proc ptrToInt(x: PNode): int {.inline.} =
+  result = cast[int](x) # don't skip alignment
+
+proc getField(n: PNode; position: int): PSym =
+  case n.kind
+  of nkRecList:
+    for i in countup(0, sonsLen(n) - 1):
+      result = getField(n.sons[i], position)
+      if result != nil: return
+  of nkRecCase:
+    result = getField(n.sons[0], position)
+    if result != nil: return
+    for i in countup(1, sonsLen(n) - 1):
+      case n.sons[i].kind
+      of nkOfBranch, nkElse:
+        result = getField(lastSon(n.sons[i]), position)
+        if result != nil: return
+      else: internalError(n.info, "getField(record case branch)")
+  of nkSym:
+    if n.sym.position == position: result = n.sym
+  else: discard
+
+proc storeAny(s: var string; t: PType; a: PNode; stored: var IntSet)
+
+proc storeObj(s: var string; typ: PType; x: PNode; stored: var IntSet) =
+  internalAssert x.kind in {nkObjConstr, nkPar}
+  let start = ord(x.kind == nkObjConstr)
+  for i in countup(start, sonsLen(x) - 1):
+    if i > start: s.add(", ")
+    var it = x.sons[i]
+    if it.kind == nkExprColonExpr:
+      internalAssert it.sons[0].kind == nkSym
+      let field = it.sons[0].sym
+      s.add(escapeJson(field.name.s))
+      s.add(": ")
+      storeAny(s, field.typ, it.sons[1], stored)
+    elif typ.n != nil:
+      let field = getField(typ.n, i)
+      s.add(escapeJson(field.name.s))
+      s.add(": ")
+      storeAny(s, field.typ, it, stored)
+
+proc skipColon*(n: PNode): PNode =
+  result = n
+  if n.kind == nkExprColonExpr:
+    result = n.sons[1]
+
+proc storeAny(s: var string; t: PType; a: PNode; stored: var IntSet) =
+  case t.kind
+  of tyNone: assert false
+  of tyBool: s.add($(a.intVal != 0))
+  of tyChar:
+    let ch = char(a.intVal)
+    if ch < '\128':
+      s.add(escapeJson($ch))
+    else:
+      s.add($int(ch))
+  of tyArray, tySequence:
+    if t.kind == tySequence and a.kind == nkNilLit: s.add("null")
+    else:
+      s.add("[")
+      for i in 0 .. a.len-1:
+        if i > 0: s.add(", ")
+        storeAny(s, t.elemType, a[i], stored)
+      s.add("]")
+  of tyTuple:
+    s.add("{")
+    for i in 0.. <t.len:
+      if i > 0: s.add(", ")
+      s.add("\"Field" & $i)
+      s.add("\": ")
+      storeAny(s, t.sons[i], a[i].skipColon, stored)
+    s.add("}")
+  of tyObject:
+    s.add("{")
+    storeObj(s, t, a, stored)
+    s.add("}")
+  of tySet:
+    s.add("[")
+    for i in 0.. <a.len:
+      if i > 0: s.add(", ")
+      if a[i].kind == nkRange:
+        var x = copyNode(a[i][0])
+        storeAny(s, t.lastSon, x, stored)
+        while x.intVal+1 <= a[i][1].intVal:
+          s.add(", ")
+          storeAny(s, t.lastSon, x, stored)
+          inc x.intVal
+      else:
+        storeAny(s, t.lastSon, a[i], stored)
+    s.add("]")
+  of tyRange, tyGenericInst: storeAny(s, t.lastSon, a, stored)
+  of tyEnum:
+    # we need a slow linear search because of enums with holes:
+    for e in items(t.n):
+      if e.sym.position == a.intVal:
+        s.add e.sym.name.s.escapeJson
+        break
+  of tyPtr, tyRef:
+    var x = a
+    if isNil(x) or x.kind == nkNilLit: s.add("null")
+    elif stored.containsOrIncl(x.ptrToInt):
+      # already stored, so we simply write out the pointer as an int:
+      s.add($x.ptrToInt)
+    else:
+      # else as a [value, key] pair:
+      # (reversed order for convenient x[0] access!)
+      s.add("[")
+      s.add($x.ptrToInt)
+      s.add(", ")
+      storeAny(s, t.lastSon, a, stored)
+      s.add("]")
+  of tyString, tyCString:
+    if a.kind == nkNilLit or a.strVal.isNil: s.add("null")
+    else: s.add(escapeJson(a.strVal))
+  of tyInt..tyInt64, tyUInt..tyUInt64: s.add($a.intVal)
+  of tyFloat..tyFloat128: s.add($a.floatVal)
+  else:
+    internalError a.info, "cannot marshal at compile-time " & t.typeToString
+
+proc storeAny*(s: var string; t: PType; a: PNode) =
+  var stored = initIntSet()
+  storeAny(s, t, a, stored)
+
+proc loadAny(p: var JsonParser, t: PType,
+             tab: var Table[BiggestInt, PNode]): PNode =
+  case t.kind
+  of tyNone: assert false
+  of tyBool:
+    case p.kind
+    of jsonFalse: result = newIntNode(nkIntLit, 0)
+    of jsonTrue: result = newIntNode(nkIntLit, 1)
+    else: raiseParseErr(p, "'true' or 'false' expected for a bool")
+    next(p)
+  of tyChar:
+    if p.kind == jsonString:
+      var x = p.str
+      if x.len == 1:
+        result = newIntNode(nkIntLit, ord(x[0]))
+        next(p)
+        return
+    elif p.kind == jsonInt:
+      result = newIntNode(nkIntLit, getInt(p))
+      next(p)
+      return
+    raiseParseErr(p, "string of length 1 expected for a char")
+  of tyEnum:
+    if p.kind == jsonString:
+      for e in items(t.n):
+        if e.sym.name.s == p.str:
+          result = newIntNode(nkIntLit, e.sym.position)
+          next(p)
+          return
+    raiseParseErr(p, "string expected for an enum")
+  of tyArray:
+    if p.kind != jsonArrayStart: raiseParseErr(p, "'[' expected for an array")
+    next(p)
+    result = newNode(nkBracket)
+    while p.kind != jsonArrayEnd and p.kind != jsonEof:
+      result.add loadAny(p, t.elemType, tab)
+    if p.kind == jsonArrayEnd: next(p)
+    else: raiseParseErr(p, "']' end of array expected")
+  of tySequence:
+    case p.kind
+    of jsonNull:
+      result = newNode(nkNilLit)
+      next(p)
+    of jsonArrayStart:
+      next(p)
+      result = newNode(nkBracket)
+      while p.kind != jsonArrayEnd and p.kind != jsonEof:
+        result.add loadAny(p, t.elemType, tab)
+      if p.kind == jsonArrayEnd: next(p)
+      else: raiseParseErr(p, "")
+    else:
+      raiseParseErr(p, "'[' expected for a seq")
+  of tyTuple:
+    if p.kind != jsonObjectStart: raiseParseErr(p, "'{' expected for an object")
+    next(p)
+    result = newNode(nkPar)
+    var i = 0
+    while p.kind != jsonObjectEnd and p.kind != jsonEof:
+      if p.kind != jsonString:
+        raiseParseErr(p, "string expected for a field name")
+      next(p)
+      if i >= t.len:
+        raiseParseErr(p, "too many fields to tuple type " & typeToString(t))
+      result.add loadAny(p, t.sons[i], tab)
+      inc i
+    if p.kind == jsonObjectEnd: next(p)
+    else: raiseParseErr(p, "'}' end of object expected")
+  of tyObject:
+    if p.kind != jsonObjectStart: raiseParseErr(p, "'{' expected for an object")
+    next(p)
+    result = newNode(nkPar)
+    result.sons = @[]
+    while p.kind != jsonObjectEnd and p.kind != jsonEof:
+      if p.kind != jsonString:
+        raiseParseErr(p, "string expected for a field name")
+      let field = lookupInRecord(t.n, getIdent(p.str))
+      if field.isNil:
+        raiseParseErr(p, "unknown field for object of type " & typeToString(t))
+      next(p)
+      if field.position >= result.sons.len:
+        setLen(result.sons, field.position+1)
+      result.sons[field.position] = loadAny(p, field.typ, tab)
+    if p.kind == jsonObjectEnd: next(p)
+    else: raiseParseErr(p, "'}' end of object expected")
+  of tySet:
+    if p.kind != jsonArrayStart: raiseParseErr(p, "'[' expected for a set")
+    next(p)
+    result = newNode(nkCurly)
+    while p.kind != jsonArrayEnd and p.kind != jsonEof:
+      result.add loadAny(p, t.lastSon, tab)
+      next(p)
+    if p.kind == jsonArrayEnd: next(p)
+    else: raiseParseErr(p, "']' end of array expected")
+  of tyPtr, tyRef:
+    case p.kind
+    of jsonNull:
+      result = newNode(nkNilLit)
+      next(p)
+    of jsonInt:
+      result = tab[p.getInt]
+      if result.isNil:
+        raiseParseErr(p, "cannot load object with address " & $p.getInt)
+      next(p)
+    of jsonArrayStart:
+      next(p)
+      if p.kind == jsonInt:
+        let idx = p.getInt
+        next(p)
+        result = loadAny(p, t.lastSon, tab)
+        tab[idx] = result
+      else: raiseParseErr(p, "index for ref type expected")
+      if p.kind == jsonArrayEnd: next(p)
+      else: raiseParseErr(p, "']' end of ref-address pair expected")
+    else: raiseParseErr(p, "int for pointer type expected")
+  of tyString, tyCString:
+    case p.kind
+    of jsonNull:
+      result = newNode(nkNilLit)
+      next(p)
+    of jsonString:
+      result = newStrNode(nkStrLit, p.str)
+      next(p)
+    else: raiseParseErr(p, "string expected")
+  of tyInt..tyInt64, tyUInt..tyUInt64:
+    if p.kind == jsonInt:
+      result = newIntNode(nkIntLit, getInt(p))
+      next(p)
+      return
+    raiseParseErr(p, "int expected")
+  of tyFloat..tyFloat128:
+    if p.kind == jsonFloat:
+      result = newFloatNode(nkFloatLit, getFloat(p))
+      next(p)
+      return
+    raiseParseErr(p, "float expected")
+  of tyRange, tyGenericInst: result = loadAny(p, t.lastSon, tab)
+  else:
+    internalError "cannot marshal at compile-time " & t.typeToString
+
+proc loadAny*(s: string; t: PType): PNode =
+  var tab = initTable[BiggestInt, PNode]()
+  var p: JsonParser
+  open(p, newStringStream(s), "unknown file")
+  next(p)
+  result = loadAny(p, t, tab)
+  close(p)
diff --git a/config/nim.cfg b/config/nim.cfg
index ccb9977db..fef7df79e 100644
--- a/config/nim.cfg
+++ b/config/nim.cfg
@@ -96,7 +96,7 @@ path="$lib/pure/unidecode"
 
 # Configuration for the GNU C/C++ compiler:
 @if windows:
-  #gcc.path = r"$nimrod\dist\mingw\bin"
+  #gcc.path = r"$nim\dist\mingw\bin"
   @if gcc:
     tlsEmulation:on
   @end
diff --git a/doc/lib.txt b/doc/lib.txt
index 385e7a91a..1c0278068 100644
--- a/doc/lib.txt
+++ b/doc/lib.txt
@@ -37,7 +37,7 @@ Core
 
 * `unsigned <unsigned.html>`_
   This module implements basic arithmetic operators for unsigned integers.
-  To discourage users from using unsigned integers, it's not part 
+  To discourage users from using unsigned integers, it's not part
   of ``system``, but an extra import.
 
 * `threads <threads.html>`_
@@ -45,7 +45,7 @@ Core
   import it explicitly.
 
 * `channels <channels.html>`_
-  Nim message passing support for threads. **Note**: This is part of the 
+  Nim message passing support for threads. **Note**: This is part of the
   system module. Do not import it explicitly.
 
 * `locks <locks.html>`_
@@ -55,7 +55,7 @@ Core
   Contains the AST API and documentation of Nim for writing macros.
 
 * `typeinfo <typeinfo.html>`_
-  Provides (unsafe) access to Nim's run time type information. 
+  Provides (unsafe) access to Nim's run time type information.
 
 * `typetraits <typetraits.html>`_
   This module defines compile-time reflection procs for working with types.
@@ -110,9 +110,9 @@ String handling
 
 * `unicode <unicode.html>`_
   This module provides support to handle the Unicode UTF-8 encoding.
-  
+
 * `encodings <encodings.html>`_
-  Converts between different character encodings. On UNIX, this uses 
+  Converts between different character encodings. On UNIX, this uses
   the ``iconv`` library, on Windows the Windows API.
 
 * `pegs <pegs.html>`_
@@ -159,7 +159,7 @@ Generic Operating System Services
   may provide other implementations for this standard stream interface.
 
 * `marshal <marshal.html>`_
-  Contains procs for serialization and deseralization of arbitrary Nim 
+  Contains procs for serialization and deseralization of arbitrary Nim
   data structures.
 
 * `terminal <terminal.html>`_
@@ -168,7 +168,7 @@ Generic Operating System Services
   sequences and does not depend on any other module.
 
 * `memfiles <memfiles.html>`_
-  This module provides support for memory mapped files (Posix's ``mmap``) 
+  This module provides support for memory mapped files (Posix's ``mmap``)
   on the different operating systems.
 
 * `fsmonitor <fsmonitor.html>`_
@@ -228,7 +228,7 @@ Internet Protocols and Support
   This module implements a simple HTTP client.
 
 * `smtp <smtp.html>`_
-  This module implement a simple SMTP client. 
+  This module implement a simple SMTP client.
 
 * `ftpclient <ftpclient.html>`_
   This module implements an FTP client.
@@ -346,7 +346,7 @@ XML Processing
   This module parses an HTML document and creates its XML tree representation.
 
 * `htmlgen <htmlgen.html>`_
-  This module implements a simple XML and HTML code 
+  This module implements a simple XML and HTML code
   generator. Each commonly used HTML tag has a corresponding macro
   that generates a string with its HTML representation.
 
@@ -381,7 +381,7 @@ Miscellaneous
 
 * `oids <oids.html>`_
   An OID is a global ID that consists of a timestamp,
-  a unique counter and a random value. This combination should suffice to 
+  a unique counter and a random value. This combination should suffice to
   produce a globally distributed unique ID. This implementation was extracted
   from the Mongodb interface and it thus binary compatible with a Mongo OID.
 
@@ -453,12 +453,8 @@ Other
 * `zipfiles <zipfiles.html>`_
   This module implements a zip archive creator/reader/modifier.
 
-* `web <web.html>`_
-  This module contains simple high-level procedures for dealing with the
-  Web like loading the contents of a Web page from an URL.
-
 * `ssl <ssl.html>`_
-  This module provides an easy to use sockets-style 
+  This module provides an easy to use sockets-style
   Nim interface to the OpenSSL library.
 
 * `rdstdin <rdstdin.html>`_
@@ -513,25 +509,6 @@ Regular expressions
   Wrapper for the TRE library.
 
 
-Graphics libraries
-------------------
-
-* `sdl <sdl.html>`_
-  Part of the wrapper for SDL.
-* `sdl_gfx <sdl_gfx.html>`_
-  Part of the wrapper for SDL.
-* `sdl_image <sdl_image.html>`_
-  Part of the wrapper for SDL.
-* `sdl_mixer <sdl_mixer.html>`_
-  Part of the wrapper for SDL.
-* `sdl_net <sdl_net.html>`_
-  Part of the wrapper for SDL.
-* `sdl_ttf <sdl_ttf.html>`_
-  Part of the wrapper for SDL.
-* `smpeg <smpeg.html>`_
-  Part of the wrapper for SDL.
-
-
 GUI libraries
 -------------
 
@@ -591,7 +568,7 @@ Data Compression and Archiving
 Scientific computing
 --------------------
 
-* `libsvm <libsvm.html>`_ 
+* `libsvm <libsvm.html>`_
   Low level wrapper for `lib svm <http://www.csie.ntu.edu.tw/~cjlin/libsvm/>`_.
 
 Nimble
diff --git a/doc/nimsuggest.txt b/doc/nimsuggest.txt
new file mode 100644
index 000000000..2b52196b9
--- /dev/null
+++ b/doc/nimsuggest.txt
@@ -0,0 +1,174 @@
+================================
+  Nim IDE Integration Guide
+================================
+
+:Author: Unknown
+:Version: |nimversion|
+
+.. contents::
+
+
+Nim differs from many other compilers in that it is really fast,
+and being so fast makes it suited to provide external queries for
+text editors about the source code being written. Through the
+``nimsuggest`` tool, any IDE
+can query a ``.nim`` source file and obtain useful information like
+definition of symbols or suggestions for completion.
+
+This document will guide you through the available options. If you
+want to look at practical examples of nimsuggest support you can look
+at the
+`various editor integrations <https://github.com/Araq/Nim/wiki/Editor-Support>`_
+already available.
+
+
+Installation
+============
+
+Nimsuggest is available as a Nimble package but currently does not install
+properly via Nimble. As nimsuggest is part of the compiler it also doesn't make
+too much sense as a Nimble package. Instead we will do the building manually::
+
+  cd compiler/nimsuggest
+  nim c -d:release nimsuggest
+  cp nimsuggest ../../bin
+  # OR: copy the nimsuggest binary to where your 'nim' binary is
+  cd ../..
+
+
+
+Nimsuggest invocation
+=====================
+
+Run it via ``nimsuggest --stdin myproject.nim``. Nimsuggest is a server that
+takes queries that are related to ``myproject``. There is some support so that
+you can throw random ``.nim`` files which are not part of ``myproject`` at
+Nimsuggest too, but usually the query refer to modules/files that are part of
+``myproject``.
+
+``--stdin`` means that Nimsuggest reads the query from ``stdin``. This is great
+for testing things out and playing with it but for an editor communication
+via sockets is more reasonable so that is the default. It listens to port 6000
+by default.
+
+
+Specifying the location of the query
+------------------------------------
+
+Nimsuggest than waits for queries to process. A query consists of a
+cryptic 3 letter "command" ``def`` or ``con`` or ``sug`` or ``use`` followed by
+a location. A query location consists of:
+
+
+``file.nim``
+    This is the name of the module or include file the query refers to.
+
+``dirtyfile.nim``
+    This is optional.
+
+    The ``file`` paramater is enough for static analysis, but IDEs
+    tend to have *unsaved buffers* where the user may still be in
+    the middle of typing a line. In such situations the IDE can
+    save the current contents to a temporary file and then use the
+    ``dirtyfile.nim`` option to tell Nimsuggest that ``foobar.nim`` should
+    be taken from ``temporary/foobar.nim``.
+
+
+``line``
+    An integer with the line you are going to query. For the compiler
+    lines start at **1**.
+
+``col``
+    An integer with the column you are going to query. For the
+    compiler columns start at **1**.
+
+
+Definitions
+-----------
+
+The ``def`` Nimsuggest command performs a query about the definition
+of a specific symbol. If available, Nimsuggest will answer with the
+type, source file, line/column information and other accessory data
+if available like a docstring. With this information an IDE can
+provide the typical *Jump to definition* where a user puts the
+cursor on a symbol or uses the mouse to select it and is redirected
+to the place where the symbol is located.
+
+Since Nim is implemented in Nim, one of the nice things of
+this feature is that any user with an IDE supporting it can quickly
+jump around the standard library implementation and see exactly
+what a proc does, learning about the language and seeing real life
+examples of how to write/implement specific features.
+
+Nimsuggest will always answer with a single definition or none if it
+can't find any valid symbol matching the position of the query.
+
+
+Suggestions
+-----------
+
+The ``sug`` Nimsuggest command performs a query about possible
+completion symbols at some point in the file.
+
+The typical usage scenario for this option is to call it after the
+user has typed the dot character for `the object oriented call
+syntax <tut2.html#method-call-syntax>`_. Nimsuggest will try to return
+the suggestions sorted first by scope (from innermost to outermost)
+and then by item name.
+
+
+Invocation context
+------------------
+
+The ``con`` Nimsuggest command is very similar to the suggestions
+command, but instead of being used after the user has typed a dot
+character, this one is meant to be used after the user has typed
+an opening brace to start typing parameters.
+
+
+Symbol usages
+-------------
+
+The ``use`` Nimsuggest command lists all usages of the symbol at
+a position. IDEs can use this to find all the places in the file
+where the symbol is used and offer the user to rename it in all
+places at the same time.
+
+For this kind of query the IDE will most likely ignore all the
+type/signature info provided by Nimsuggest and concentrate on the
+filename, line and column position of the multiple returned answers.
+
+
+
+Parsing nimsuggest output
+=========================
+
+Nimsuggest output is always returned on single lines separated by
+tab characters (``\t``). The values of each column are:
+
+1. Three characters indicating the type of returned answer (e.g.
+   ``def`` for definition, ``sug`` for suggestion, etc).
+2. Type of the symbol. This can be ``skProc``, ``skLet``, and just
+   about any of the enums defined in the module ``compiler/ast.nim``.
+3. Full qualitifed path of the symbol. If you are querying a symbol
+   defined in the ``proj.nim`` file, this would have the form
+   ``proj.symbolName``.
+4. Type/signature. For variables and enums this will contain the
+   type of the symbol, for procs, methods and templates this will
+   contain the full unique signature (e.g. ``proc (File)``).
+5. Full path to the file containing the symbol.
+6. Line where the symbol is located in the file. Lines start to
+   count at **1**.
+7. Column where the symbol is located in the file. Columns start
+   to count at **1**.
+8. Docstring for the symbol if available or the empty string. To
+   differentiate the docstring from end of answer,
+   the docstring is always provided enclosed in double quotes, and
+   if the docstring spans multiple lines, all following lines of the
+   docstring will start with a blank space to align visually with
+   the starting quote.
+
+   Also, you won't find raw ``\n`` characters breaking the one
+   answer per line format. Instead you will need to parse sequences
+   in the form ``\xHH``, where *HH* is a hexadecimal value (e.g.
+   newlines generate the sequence ``\x0A``).
diff --git a/doc/tools.txt b/doc/tools.txt
index 7f2830879..b0a45c575 100644
--- a/doc/tools.txt
+++ b/doc/tools.txt
@@ -4,6 +4,11 @@ Tools available with Nim
 
 The standard distribution ships with the following tools:
 
+- | `Nimsuggest for IDE support <nimsuggest.html>`_
+  | Through the ``nimsuggest`` tool, any IDE can query a ``.nim`` source file
+    and obtain useful information like definition of symbols or suggestions for
+    completion.
+
 - | `Nim Installation Generator <niminst.html>`_
   | How to generate a nice installer for your Nim program.
 
diff --git a/doc/tut1.txt b/doc/tut1.txt
index cb5a0c8dd..58ace1dbe 100644
--- a/doc/tut1.txt
+++ b/doc/tut1.txt
@@ -16,7 +16,7 @@ Introduction
   </p></blockquote>
 
 
-This document is a tutorial for the programming language *Nim*. 
+This document is a tutorial for the programming language *Nim*.
 This tutorial assumes that you are familiar with basic programming concepts
 like variables, types or statements but is kept very basic. The `manual
 <manual.html>`_ contains many more examples of the advanced language features.
@@ -50,7 +50,7 @@ Commonly used commands and switches have abbreviations, so you can also use::
   nim c -r greetings.nim
 
 To compile a release version use::
-  
+
   nim c -d:release greetings.nim
 
 By default the Nim compiler generates a large amount of runtime checks
@@ -116,7 +116,7 @@ hash character ``#``. Documentation comments start with ``##``:
 
 .. code-block:: nim
   # A comment.
- 
+
   var myVariable: int ## a documentation comment
 
 
@@ -200,7 +200,7 @@ constant declaration at compile time:
 
 .. code-block:: nim
   const x = "abc" # the constant x contains the string "abc"
-  
+
 Indentation can be used after the ``const`` keyword to list a whole section of
 constants:
 
@@ -214,7 +214,7 @@ constants:
 
 The let statement
 =================
-The ``let`` statement works like the ``var`` statement but the declared 
+The ``let`` statement works like the ``var`` statement but the declared
 symbols are *single assignment* variables: After the initialization their
 value cannot change:
 
@@ -228,7 +228,7 @@ and put it into a data section":
 
 .. code-block::
   const input = readLine(stdin) # Error: constant expression expected
-  
+
 .. code-block::
   let input = readLine(stdin)   # works
 
@@ -310,8 +310,8 @@ the compiler that for every other value nothing should be done:
   else: discard
 
 The empty `discard statement`_ is a *do nothing* statement. The compiler knows
-that a case statement with an else part cannot fail and thus the error 
-disappears. Note that it is impossible to cover all possible string values: 
+that a case statement with an else part cannot fail and thus the error
+disappears. Note that it is impossible to cover all possible string values:
 that is why string cases always need an ``else`` branch.
 
 In general the case statement is used for subrange types or enumerations where
@@ -406,7 +406,7 @@ The block's *label* (``myblock`` in the example) is optional.
 Break statement
 ---------------
 A block can be left prematurely with a ``break`` statement. The break statement
-can leave a ``while``, ``for``, or a ``block`` statement. It leaves the 
+can leave a ``while``, ``for``, or a ``block`` statement. It leaves the
 innermost construct, unless a label of a block is given:
 
 .. code-block:: nim
@@ -461,7 +461,7 @@ differences:
 * The statements within a branch do not open a new scope.
 * The compiler checks the semantics and produces code *only* for the statements
   that belong to the first condition that evaluates to ``true``.
-  
+
 The ``when`` statement is useful for writing platform specific code, similar to
 the ``#ifdef`` construct in the C programming language.
 
@@ -486,14 +486,14 @@ to be indented, but single simple statements do not:
 .. code-block:: nim
   # no indentation needed for single assignment statement:
   if x: x = false
-  
+
   # indentation needed for nested if statement:
   if x:
     if y:
       y = false
     else:
       y = true
-  
+
   # indentation needed, because two statements follow the condition:
   if x:
     x = false
@@ -514,7 +514,7 @@ contain indentation at certain places for better readability:
 As a rule of thumb, indentation within expressions is allowed after operators,
 an open parenthesis and after commas.
 
-With parenthesis and semicolons ``(;)`` you can use statements where only 
+With parenthesis and semicolons ``(;)`` you can use statements where only
 an expression is allowed:
 
 .. code-block:: nim
@@ -560,45 +560,45 @@ Some terminology: in the example ``question`` is called a (formal) *parameter*,
 
 Result variable
 ---------------
-A procedure that returns a value has an implicit ``result`` variable declared 
+A procedure that returns a value has an implicit ``result`` variable declared
 that represents the return value. A ``return`` statement with no expression is a
-shorthand for ``return result``. The ``result`` value is always returned 
+shorthand for ``return result``. The ``result`` value is always returned
 automatically at the end a procedure if there is no ``return`` statement at
 the exit.
 
 .. code-block:: nim
-  proc sumTillNegative(x: varargs[int]): int = 
+  proc sumTillNegative(x: varargs[int]): int =
     for i in x:
       if i < 0:
         return
-      result = result + i  
-      
+      result = result + i
+
   echo sumTillNegative() # echos 0
   echo sumTillNegative(3, 4, 5) # echos 12
   echo sumTillNegative(3, 4 , -1 , 6) # echos 7
 
-The ``result`` variable is already implicitly declared at the start of the 
+The ``result`` variable is already implicitly declared at the start of the
 function, so declaring it again with 'var result', for example, would shadow it
 with a normal variable of the same name. The result variable is also already
 initialised with the type's default value. Note that referential data types will
 be ``nil`` at the start of the procedure, and thus may require manual
 initialisation.
 
-      
+
 Parameters
 ----------
 Parameters are constant in the procedure body. By default, their value cannot be
-changed because this allows the compiler to implement parameter passing in the 
+changed because this allows the compiler to implement parameter passing in the
 most efficient way. If a mutable variable is needed inside the procedure, it has
 to be declared with ``var`` in the procedure body. Shadowing the parameter name
-is possible, and actually an idiom: 
+is possible, and actually an idiom:
 
 .. code-block:: nim
   proc printSeq(s: seq, nprinted: int = -1) =
     var nprinted = if nprinted == -1: s.len else: min(nprinted, s.len)
     for i in 0 .. <nprinted:
       echo s[i]
-    
+
 If the procedure needs to modify the argument for the
 caller, a ``var`` parameter can be used:
 
@@ -630,12 +630,12 @@ allow to silently throw away a return value:
 
 
 The return value can be ignored implicitly if the called proc/iterator has
-been declared with the ``discardable`` pragma: 
+been declared with the ``discardable`` pragma:
 
 .. code-block:: nim
-  proc p(x, y: int): int {.discardable.} = 
+  proc p(x, y: int): int {.discardable.} =
     return x + y
-    
+
   p(3, 4) # now valid
 
 The ``discard`` statement can also be used to create block comments as
@@ -899,7 +899,7 @@ object on the heap, so there is a trade-off to be made here.
 
 Integers
 --------
-Nim has these integer types built-in: 
+Nim has these integer types built-in:
 ``int int8 int16 int32 int64 uint uint8 uint16 uint32 uint64``.
 
 The default integer type is ``int``. Integer literals can have a *type suffix*
@@ -1114,7 +1114,7 @@ Arrays
 An array is a simple fixed length container. Each element in
 the array has the same type. The array's index type can be any ordinal type.
 
-Arrays can be constructed via ``[]``: 
+Arrays can be constructed via ``[]``:
 
 .. code-block:: nim
 
@@ -1370,12 +1370,12 @@ integer.
   var building: tuple[street: string, number: int]
   building = ("Rue del Percebe", 13)
   echo(building.street)
-  
+
   # The following line does not compile, they are different tuples!
   #person = building
   # --> Error: type mismatch: got (tuple[street: string, number: int])
   #     but expected 'Person'
-  
+
   # The following works because the field names and types are the same.
   var teacher: tuple[name: string, age: int] = ("Mark", 42)
   person = teacher
@@ -1450,13 +1450,13 @@ operators perform implicit dereferencing operations for reference types:
 
   type
     Node = ref NodeObj
-    NodeObj = object 
-      le, ri: PNode
+    NodeObj = object
+      le, ri: Node
       data: int
   var
     n: Node
   new(n)
-  n.data = 9 
+  n.data = 9
   # no need to write n[].data; in fact n[].data is highly discouraged!
 
 To allocate a new traced object, the built-in procedure ``new`` has to be used.
@@ -1559,9 +1559,9 @@ This is best illustrated by an example:
 
 
 A symbol of a module *can* be *qualified* with the ``module.symbol`` syntax. If
-the symbol is ambiguous, it even *has* to be qualified. A symbol is ambiguous 
-if it is defined in two (or more) different modules and both modules are 
-imported by a third one: 
+the symbol is ambiguous, it even *has* to be qualified. A symbol is ambiguous
+if it is defined in two (or more) different modules and both modules are
+imported by a third one:
 
 .. code-block:: nim
   # Module A
diff --git a/koch.nim b/koch.nim
index 3ebfb6655..55019b544 100644
--- a/koch.nim
+++ b/koch.nim
@@ -106,6 +106,12 @@ proc zip(args: string) =
   exec("$# --var:version=$# --var:mingw=none --main:compiler/nim.nim zip compiler/installer.ini" %
        ["tools/niminst/niminst".exe, VersionAsString])
 
+proc targz(args: string) =
+  exec("$3 cc -r $2 --var:version=$1 --var:mingw=none --main:compiler/nim.nim scripts compiler/installer.ini" %
+       [VersionAsString, compileNimInst, findNim()])
+  exec("$# --var:version=$# --var:mingw=none --main:compiler/nim.nim targz compiler/installer.ini" %
+       ["tools" / "niminst" / "niminst".exe, VersionAsString])
+
 proc buildTool(toolname, args: string) =
   exec("$# cc $# $#" % [findNim(), args, toolname])
   copyFile(dest="bin"/ splitFile(toolname).name.exe, source=toolname.exe)
@@ -113,12 +119,12 @@ proc buildTool(toolname, args: string) =
 proc nsis(args: string) =
   # make sure we have generated the niminst executables:
   buildTool("tools/niminst/niminst", args)
-  buildTool("tools/nimgrep", args)
+  #buildTool("tools/nimgrep", args)
   # produce 'nim_debug.exe':
-  exec "nim c compiler" / "nim.nim"
-  copyExe("compiler/nim".exe, "bin/nim_debug".exe)
+  #exec "nim c compiler" / "nim.nim"
+  #copyExe("compiler/nim".exe, "bin/nim_debug".exe)
   exec(("tools" / "niminst" / "niminst --var:version=$# --var:mingw=mingw$#" &
-        " nsis compiler/nim") % [VersionAsString, $(sizeof(pointer)*8)])
+        " nsis compiler/installer.ini") % [VersionAsString, $(sizeof(pointer)*8)])
 
 proc install(args: string) =
   exec("$# cc -r $# --var:version=$# --var:mingw=none --main:compiler/nim.nim scripts compiler/installer.ini" %
@@ -308,12 +314,14 @@ proc winRelease() =
   #buildTool("tools/niminst/niminst", " -d:release")
   buildTool("tools/nimgrep", " -d:release")
   buildTool("compiler/nimfix/nimfix", " -d:release")
+  buildTool("compiler/nimsuggest/nimsuggest", " -d:release")
+
+  #run7z("win32", "bin/nim.exe", "bin/c2nim.exe", "bin/nimgrep.exe",
+  #      "bin/nimfix.exe",
+  #      "bin/nimble.exe", "bin/*.dll",
+  #      "config", "dist/*.dll", "examples", "lib",
+  #      "readme.txt", "contributors.txt", "copying.txt")
 
-  run7z("win32", "bin/nim.exe", "bin/c2nim.exe", "bin/nimgrep.exe",
-        "bin/nimfix.exe",
-        "bin/nimble.exe", "bin/*.dll",
-        "config", "dist/*.dll", "examples", "lib",
-        "readme.txt", "contributors.txt", "copying.txt")
   # second step: XXX build 64 bit version
 
 # -------------- tests --------------------------------------------------------
@@ -357,6 +365,7 @@ of cmdArgument:
   of "pdf": pdf()
   of "csource", "csources": csource(op.cmdLineRest)
   of "zip": zip(op.cmdLineRest)
+  of "targz": targz(op.cmdLineRest)
   of "nsis": nsis(op.cmdLineRest)
   of "install": install(op.cmdLineRest)
   of "test", "tests": tests(op.cmdLineRest)
diff --git a/lib/impure/rdstdin.nim b/lib/impure/rdstdin.nim
index 55f8c5d32..f4d00979c 100644
--- a/lib/impure/rdstdin.nim
+++ b/lib/impure/rdstdin.nim
@@ -135,7 +135,7 @@ else:
     var cur, old: Termios
     discard fd.tcgetattr(cur.addr)
     old = cur
-    cur.lflag = cur.lflag and not Tcflag(ECHO)
+    cur.c_lflag = cur.c_lflag and not Tcflag(ECHO)
     discard fd.tcsetattr(TCSADRAIN, cur.addr)
     stdout.write prompt
     result = stdin.readLine(password)
diff --git a/lib/impure/re.nim b/lib/impure/re.nim
index fb95610f6..279f8aadd 100644
--- a/lib/impure/re.nim
+++ b/lib/impure/re.nim
@@ -146,8 +146,8 @@ proc findBounds*(s: string, pattern: Regex,
 
 proc findBounds*(s: string, pattern: Regex,
                  start = 0): tuple[first, last: int] =
-  ## returns the starting position of `pattern` in `s`. If it does not
-  ## match, ``(-1,0)`` is returned.
+  ## returns the starting position and end position of ``pattern`` in ``s``.
+  ## If it does not match, ``(-1,0)`` is returned.
   var
     rtarray = initRtArray[cint](3)
     rawMatches = rtarray.getRawData
diff --git a/lib/impure/zipfiles.nim b/lib/impure/zipfiles.nim
index c22294061..b41ca1e4b 100644
--- a/lib/impure/zipfiles.nim
+++ b/lib/impure/zipfiles.nim
@@ -9,8 +9,8 @@
 
 ## This module implements a zip archive creator/reader/modifier.
 
-import 
-  streams, libzip, times, os
+import
+  streams, libzip, times, os, strutils
 
 type
   TZipArchive* = object of RootObj ## represents a zip archive
@@ -18,14 +18,14 @@ type
     w: PZip
 
 
-proc zipError(z: var TZipArchive) = 
+proc zipError(z: var TZipArchive) =
   var e: ref IOError
   new(e)
   e.msg = $zip_strerror(z.w)
   raise e
-  
+
 proc open*(z: var TZipArchive, filename: string, mode: FileMode = fmRead): bool =
-  ## Opens a zip file for reading, writing or appending. All file modes are 
+  ## Opens a zip file for reading, writing or appending. All file modes are
   ## supported. Returns true iff successful, false otherwise.
   var err, flags: int32
   case mode
@@ -41,21 +41,21 @@ proc open*(z: var TZipArchive, filename: string, mode: FileMode = fmRead): bool
 proc close*(z: var TZipArchive) =
   ## Closes a zip file.
   zip_close(z.w)
- 
-proc createDir*(z: var TZipArchive, dir: string) = 
+
+proc createDir*(z: var TZipArchive, dir: string) =
   ## Creates a directory within the `z` archive. This does not fail if the
-  ## directory already exists. Note that for adding a file like 
+  ## directory already exists. Note that for adding a file like
   ## ``"path1/path2/filename"`` it is not necessary
-  ## to create the ``"path/path2"`` subdirectories - it will be done 
-  ## automatically by ``addFile``. 
-  assert(z.mode != fmRead) 
+  ## to create the ``"path/path2"`` subdirectories - it will be done
+  ## automatically by ``addFile``.
+  assert(z.mode != fmRead)
   discard zip_add_dir(z.w, dir)
   zip_error_clear(z.w)
 
-proc addFile*(z: var TZipArchive, dest, src: string) = 
+proc addFile*(z: var TZipArchive, dest, src: string) =
   ## Adds the file `src` to the archive `z` with the name `dest`. `dest`
-  ## may contain a path that will be created. 
-  assert(z.mode != fmRead) 
+  ## may contain a path that will be created.
+  assert(z.mode != fmRead)
   if not fileExists(src):
     raise newException(IOError, "File '" & src & "' does not exist")
   var zipsrc = zip_source_file(z.w, src, 0, -1)
@@ -67,21 +67,21 @@ proc addFile*(z: var TZipArchive, dest, src: string) =
     zip_source_free(zipsrc)
     zipError(z)
 
-proc addFile*(z: var TZipArchive, file: string) = 
+proc addFile*(z: var TZipArchive, file: string) =
   ## A shortcut for ``addFile(z, file, file)``, i.e. the name of the source is
   ## the name of the destination.
   addFile(z, file, file)
-  
-proc mySourceCallback(state, data: pointer, len: int, 
-                      cmd: TZipSourceCmd): int {.cdecl.} = 
+
+proc mySourceCallback(state, data: pointer, len: int,
+                      cmd: TZipSourceCmd): int {.cdecl.} =
   var src = cast[Stream](state)
   case cmd
-  of ZIP_SOURCE_OPEN: 
+  of ZIP_SOURCE_OPEN:
     if src.setPositionImpl != nil: setPosition(src, 0) # reset
   of ZIP_SOURCE_READ:
     result = readData(src, data, len)
   of ZIP_SOURCE_CLOSE: close(src)
-  of ZIP_SOURCE_STAT: 
+  of ZIP_SOURCE_STAT:
     var stat = cast[PZipStat](data)
     zip_stat_init(stat)
     stat.size = high(int32)-1 # we don't know the size
@@ -94,8 +94,8 @@ proc mySourceCallback(state, data: pointer, len: int,
     result = 2*sizeof(cint)
   of constZIP_SOURCE_FREE: GC_unref(src)
   else: assert(false)
-  
-proc addFile*(z: var TZipArchive, dest: string, src: Stream) = 
+
+proc addFile*(z: var TZipArchive, dest: string, src: Stream) =
   ## Adds a file named with `dest` to the archive `z`. `dest`
   ## may contain a path. The file's content is read from the `src` stream.
   assert(z.mode != fmRead)
@@ -105,39 +105,45 @@ proc addFile*(z: var TZipArchive, dest: string, src: Stream) =
   if zip_add(z.w, dest, zipsrc) < 0'i32:
     zip_source_free(zipsrc)
     zipError(z)
-  
+
 # -------------- zip file stream ---------------------------------------------
 
 type
   TZipFileStream = object of StreamObj
     f: PZipFile
+    atEnd: bool
 
-  PZipFileStream* = 
-    ref TZipFileStream ## a reader stream of a file within a zip archive 
+  PZipFileStream* =
+    ref TZipFileStream ## a reader stream of a file within a zip archive
 
 proc fsClose(s: Stream) = zip_fclose(PZipFileStream(s).f)
-proc fsReadData(s: Stream, buffer: pointer, bufLen: int): int = 
+proc fsAtEnd(s: Stream): bool = PZipFileStream(s).atEnd
+proc fsReadData(s: Stream, buffer: pointer, bufLen: int): int =
   result = zip_fread(PZipFileStream(s).f, buffer, bufLen)
+  if result == 0:
+    PZipFileStream(s).atEnd = true
 
-proc newZipFileStream(f: PZipFile): PZipFileStream = 
+proc newZipFileStream(f: PZipFile): PZipFileStream =
   new(result)
   result.f = f
+  result.atEnd = false
   result.closeImpl = fsClose
   result.readDataImpl = fsReadData
+  result.atEndImpl = fsAtEnd
   # other methods are nil!
 
 # ----------------------------------------------------------------------------
-  
-proc getStream*(z: var TZipArchive, filename: string): PZipFileStream = 
+
+proc getStream*(z: var TZipArchive, filename: string): PZipFileStream =
   ## returns a stream that can be used to read the file named `filename`
   ## from the archive `z`. Returns nil in case of an error.
-  ## The returned stream does not support the `setPosition`, `getPosition`, 
+  ## The returned stream does not support the `setPosition`, `getPosition`,
   ## `writeData` or `atEnd` methods.
   var x = zip_fopen(z.w, filename, 0'i32)
   if x != nil: result = newZipFileStream(x)
-  
-iterator walkFiles*(z: var TZipArchive): string = 
-  ## walks over all files in the archive `z` and returns the filename 
+
+iterator walkFiles*(z: var TZipArchive): string =
+  ## walks over all files in the archive `z` and returns the filename
   ## (including the path).
   var i = 0'i32
   var num = zip_get_num_files(z.w)
@@ -158,12 +164,20 @@ proc extractFile*(z: var TZipArchive, srcFile: string, dest: Stream) =
 
 proc extractFile*(z: var TZipArchive, srcFile: string, dest: string) =
   ## extracts a file from the zip archive `z` to the destination filename.
-  var file = newFileStream(dest, fmReadWrite)
+  var file = newFileStream(dest, fmWrite)
   extractFile(z, srcFile, file)
   file.close()
 
 proc extractAll*(z: var TZipArchive, dest: string) =
   ## extracts all files from archive `z` to the destination directory.
   for file in walkFiles(z):
-    extractFile(z, file, dest / extractFilename(file))
-
+    if file.endsWith("/"):
+      createDir(dest / file)
+    else:
+      extractFile(z, file, dest / file)
+
+when not defined(testing) and isMainModule:
+  var zip: TZipArchive
+  if not zip.open("nim-0.11.0.zip"):
+    raise newException(IOError, "opening zip failed")
+  zip.extractAll("test")
diff --git a/lib/js/dom.nim b/lib/js/dom.nim
index 94f4fa29c..b063fa838 100644
--- a/lib/js/dom.nim
+++ b/lib/js/dom.nim
@@ -152,10 +152,12 @@ type
   DocumentObj {.importc.} = object of NodeObj
     alinkColor*: cstring
     bgColor*: cstring
+    body*: Element
     charset*: cstring
     cookie*: cstring
     defaultCharset*: cstring
     fgColor*: cstring
+    head*: Element
     lastModified*: cstring
     linkColor*: cstring
     referrer*: cstring
diff --git a/lib/nimbase.h b/lib/nimbase.h
index e9dad0bb7..eea618bac 100644
--- a/lib/nimbase.h
+++ b/lib/nimbase.h
@@ -343,15 +343,15 @@ struct TFrame {
 };
 
 #define nimfr(proc, file) \
-  TFrame F; \
-  F.procname = proc; F.filename = file; F.line = 0; F.len = 0; nimFrame(&F);
+  TFrame FR; \
+  FR.procname = proc; FR.filename = file; FR.line = 0; FR.len = 0; nimFrame(&FR);
 
 #define nimfrs(proc, file, slots, length) \
-  struct {TFrame* prev;NCSTRING procname;NI line;NCSTRING filename; NI len; TVarSlot s[slots];} F; \
-  F.procname = proc; F.filename = file; F.line = 0; F.len = length; nimFrame((TFrame*)&F);
+  struct {TFrame* prev;NCSTRING procname;NI line;NCSTRING filename; NI len; TVarSlot s[slots];} FR; \
+  FR.procname = proc; FR.filename = file; FR.line = 0; FR.len = length; nimFrame((TFrame*)&FR);
 
 #define nimln(n, file) \
-  F.line = n; F.filename = file;
+  FR.line = n; FR.filename = file;
 
 #define NIM_POSIX_INIT  __attribute__((constructor))
 
diff --git a/lib/posix/termios.nim b/lib/posix/termios.nim
index 0917ab514..710b2fa6b 100644
--- a/lib/posix/termios.nim
+++ b/lib/posix/termios.nim
@@ -19,15 +19,12 @@ const
 
 type
   Termios* {.importc: "struct termios", header: "<termios.h>".} = object
-    iflag*: Tcflag        # input mode flags
-    oflag*: Tcflag        # output mode flags
-    cflag*: Tcflag        # control mode flags
-    lflag*: Tcflag        # local mode flags
-    line*: cuchar             # line discipline
-    cc*: array[NCCS, cuchar]  # control characters
-    ispeed*: Speed        # input speed
-    ospeed*: Speed        # output speed
-
+    c_iflag*: Tcflag        # input mode flags
+    c_oflag*: Tcflag        # output mode flags
+    c_cflag*: Tcflag        # control mode flags
+    c_lflag*: Tcflag        # local mode flags
+    c_line*: cuchar         # line discipline
+    c_cc*: array[NCCS, cuchar]  # control characters
 
 # cc characters
 
diff --git a/lib/pure/asyncdispatch.nim b/lib/pure/asyncdispatch.nim
index 27f77cef2..a4d7a1632 100644
--- a/lib/pure/asyncdispatch.nim
+++ b/lib/pure/asyncdispatch.nim
@@ -634,6 +634,93 @@ when defined(windows) or defined(nimdoc):
       # free ``ol``.
     return retFuture
 
+  proc recvInto*(socket: TAsyncFD, buf: cstring, size: int,
+                flags = {SocketFlag.SafeDisconn}): Future[int] =
+    ## Reads **up to** ``size`` bytes from ``socket`` into ``buf``, which must
+    ## at least be of that size. 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
+    ## ``0``.
+    ##
+    ## **Warning**: The ``Peek`` socket flag is not supported on Windows.
+
+
+    # Things to note:
+    #   * When WSARecv completes immediately then ``bytesReceived`` is very
+    #     unreliable.
+    #   * Still need to implement message-oriented socket disconnection,
+    #     '\0' in the message currently signifies a socket disconnect. Who
+    #     knows what will happen when someone sends that to our socket.
+    verifyPresence(socket)
+    assert SocketFlag.Peek notin flags, "Peek not supported on Windows."
+
+    var retFuture = newFuture[int]("recvInto")
+
+    #buf[] = '\0'
+    var dataBuf: TWSABuf
+    dataBuf.buf = buf
+    dataBuf.len = size
+
+    var bytesReceived: Dword
+    var flagsio = flags.toOSFlags().Dword
+    var ol = PCustomOverlapped()
+    GC_ref(ol)
+    ol.data = TCompletionData(fd: socket, cb:
+      proc (fd: TAsyncFD, bytesCount: Dword, errcode: OSErrorCode) =
+        if not retFuture.finished:
+          if errcode == OSErrorCode(-1):
+            if bytesCount == 0 and dataBuf.buf[0] == '\0':
+              retFuture.complete(0)
+            else:
+              retFuture.complete(bytesCount)
+          else:
+            if flags.isDisconnectionError(errcode):
+              retFuture.complete(0)
+            else:
+              retFuture.fail(newException(OSError, osErrorMsg(errcode)))
+        if dataBuf.buf != nil:
+          dataBuf.buf = nil
+    )
+
+    let ret = WSARecv(socket.SocketHandle, addr dataBuf, 1, addr bytesReceived,
+                      addr flagsio, cast[POVERLAPPED](ol), nil)
+    if ret == -1:
+      let err = osLastError()
+      if err.int32 != ERROR_IO_PENDING:
+        if dataBuf.buf != nil:
+          dataBuf.buf = nil
+        GC_unref(ol)
+        if flags.isDisconnectionError(err):
+          retFuture.complete(0)
+        else:
+          retFuture.fail(newException(OSError, osErrorMsg(err)))
+    elif ret == 0 and bytesReceived == 0 and dataBuf.buf[0] == '\0':
+      # We have to ensure that the buffer is empty because WSARecv will tell
+      # us immediately when it was disconnected, even when there is still
+      # data in the buffer.
+      # We want to give the user as much data as we can. So we only return
+      # the empty string (which signals a disconnection) when there is
+      # nothing left to read.
+      retFuture.complete(0)
+      # 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.
+      # From my tests bytesReceived isn't reliable.
+      let realSize =
+        if bytesReceived == 0:
+          size
+        else:
+          bytesReceived
+      assert realSize <= size
+      retFuture.complete(realSize)
+      # We don't deallocate ``ol`` here because even though this completed
+      # immediately poll will still be notified about its completion and it will
+      # free ``ol``.
+    return retFuture
+
   proc send*(socket: TAsyncFD, data: string,
              flags = {SocketFlag.SafeDisconn}): Future[void] =
     ## Sends ``data`` to ``socket``. The returned future will complete once all
@@ -983,6 +1070,30 @@ else:
     addRead(socket, cb)
     return retFuture
 
+  proc recvInto*(socket: TAsyncFD, buf: cstring, size: int,
+                  flags = {SocketFlag.SafeDisconn}): Future[int] =
+    var retFuture = newFuture[int]("recvInto")
+
+    proc cb(sock: TAsyncFD): bool =
+      result = true
+      let res = recv(sock.SocketHandle, buf, size.cint,
+                     flags.toOSFlags())
+      if res < 0:
+        let lastError = osLastError()
+        if lastError.int32 notin {EINTR, EWOULDBLOCK, EAGAIN}:
+          if flags.isDisconnectionError(lastError):
+            retFuture.complete(0)
+          else:
+            retFuture.fail(newException(OSError, osErrorMsg(lastError)))
+        else:
+          result = false # We still want this callback to be called.
+      else:
+        retFuture.complete(res)
+    # TODO: The following causes a massive slowdown.
+    #if not cb(socket):
+    addRead(socket, cb)
+    return retFuture
+
   proc send*(socket: TAsyncFD, data: string,
              flags = {SocketFlag.SafeDisconn}): Future[void] =
     var retFuture = newFuture[void]("send")
diff --git a/lib/pure/asynchttpserver.nim b/lib/pure/asynchttpserver.nim
index dc5a55dcc..279cedb5d 100644
--- a/lib/pure/asynchttpserver.nim
+++ b/lib/pure/asynchttpserver.nim
@@ -23,8 +23,7 @@
 ##    proc cb(req: Request) {.async.} =
 ##      await req.respond(Http200, "Hello World")
 ##
-##    asyncCheck server.serve(Port(8080), cb)
-##    runForever()
+##    waitFor server.serve(Port(8080), cb)
 
 import strtabs, asyncnet, asyncdispatch, parseutils, uri, strutils
 type
@@ -109,22 +108,19 @@ proc sendHeaders*(req: Request, headers: StringTableRef): Future[void] =
   addHeaders(msg, headers)
   return req.client.send(msg)
 
-proc respond*(req: Request, code: HttpCode,
-        content: string, headers = newStringTable()) {.async.} =
+proc respond*(req: Request, code: HttpCode, content: string,
+              headers: StringTableRef = nil): Future[void] =
   ## 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
   var msg = "HTTP/1.1 " & $code & "\c\L"
-  msg.addHeaders(customHeaders)
-  await req.client.send(msg & "\c\L" & content)
 
-proc newRequest(): Request =
-  result.headers = newStringTable(modeCaseInsensitive)
-  result.hostname = ""
-  result.body = ""
+  if headers != nil:
+    msg.addHeaders(headers)
+  msg.add("Content-Length: " & $content.len & "\c\L\c\L")
+  msg.add(content)
+  result = req.client.send(msg)
 
 proc parseHeader(line: string): tuple[key, value: string] =
   var i = 0
@@ -149,59 +145,65 @@ proc sendStatus(client: AsyncSocket, status: string): Future[void] =
 proc processClient(client: AsyncSocket, address: string,
                    callback: proc (request: Request):
                       Future[void] {.closure, gcsafe.}) {.async.} =
+  var request: Request
+  request.url = initUri()
+  request.headers = newStringTable(modeCaseInsensitive)
+  var line = newStringOfCap(80)
+  var key, value = ""
+
   while not client.isClosed:
     # GET /path HTTP/1.1
     # Header: val
     # \n
-    var request = newRequest()
-    request.hostname = address
+    request.headers.clear(modeCaseInsensitive)
+    request.hostname.shallowCopy(address)
     assert client != nil
     request.client = client
 
     # First line - GET /path HTTP/1.1
-    let line = await client.recvLine() # TODO: Timeouts.
+    line.setLen(0)
+    await client.recvLineInto(addr line) # TODO: Timeouts.
     if line == "":
       client.close()
       return
-    let lineParts = line.split(' ')
-    if lineParts.len != 3:
-      await request.respond(Http400, "Invalid request. Got: " & line)
-      continue
 
-    let reqMethod = lineParts[0]
-    let path = lineParts[1]
-    let protocol = lineParts[2]
+    var i = 0
+    for linePart in line.split(' '):
+      case i
+      of 0: request.reqMethod.shallowCopy(linePart.normalize)
+      of 1: parseUri(linePart, request.url)
+      of 2:
+        try:
+          request.protocol = parseProtocol(linePart)
+        except ValueError:
+          asyncCheck request.respond(Http400,
+            "Invalid request protocol. Got: " & linePart)
+          continue
+      else:
+        await request.respond(Http400, "Invalid request. Got: " & line)
+        continue
+      inc i
 
     # 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
+      line.setLen(0)
+      await client.recvLineInto(addr line)
 
-    request.reqMethod = reqMethod
-    request.url = parseUri(path)
-    try:
-      request.protocol = protocol.parseProtocol()
-    except ValueError:
-      asyncCheck request.respond(Http400, "Invalid request protocol. Got: " &
-          protocol)
-      continue
+      if line == "":
+        client.close(); return
+      if line == "\c\L": break
+      let (key, value) = parseHeader(line)
+      request.headers[key] = value
 
-    if reqMethod.normalize == "post":
+    if request.reqMethod == "post":
       # Check for Expect header
       if request.headers.hasKey("Expect"):
         if request.headers["Expect"].toLower == "100-continue":
           await client.sendStatus("100 Continue")
         else:
           await client.sendStatus("417 Expectation Failed")
-    
+
       # Read the body
       # - Check for Content-length header
       if request.headers.hasKey("Content-Length"):
@@ -215,11 +217,11 @@ proc processClient(client: AsyncSocket, address: string,
         await request.respond(Http400, "Bad Request. No Content-Length.")
         continue
 
-    case reqMethod.normalize
+    case request.reqMethod
     of "get", "post", "head", "put", "delete", "trace", "options", "connect", "patch":
       await callback(request)
     else:
-      await request.respond(Http400, "Invalid request method. Got: " & reqMethod)
+      await request.respond(Http400, "Invalid request method. Got: " & request.reqMethod)
 
     # Persistent connections
     if (request.protocol == HttpVer11 and
@@ -247,7 +249,7 @@ proc serve*(server: AsyncHttpServer, port: Port,
     server.socket.setSockOpt(OptReuseAddr, true)
   server.socket.bindAddr(port, address)
   server.socket.listen()
-  
+
   while true:
     # TODO: Causes compiler crash.
     #var (address, client) = await server.socket.acceptAddr()
diff --git a/lib/pure/asyncnet.nim b/lib/pure/asyncnet.nim
index 39d05d36b..aadbde824 100644
--- a/lib/pure/asyncnet.nim
+++ b/lib/pure/asyncnet.nim
@@ -24,7 +24,7 @@
 ##
 ## Chat server
 ## ^^^^^^^^^^^
-## 
+##
 ## The following example demonstrates a simple chat server.
 ##
 ## .. code-block::nim
@@ -182,26 +182,30 @@ proc connect*(socket: AsyncSocket, address: string, port: Port,
       sslSetConnectState(socket.sslHandle)
       sslLoop(socket, flags, sslDoHandshake(socket.sslHandle))
 
-proc readInto(buf: cstring, size: int, socket: AsyncSocket,
-              flags: set[SocketFlag]): Future[int] {.async.} =
+template readInto(buf: cstring, size: int, socket: AsyncSocket,
+                  flags: set[SocketFlag]): int =
+  ## Reads **up to** ``size`` bytes from ``socket`` into ``buf``. Note that
+  ## this is a template and not a proc.
+  var res = 0
   if socket.isSsl:
     when defined(ssl):
       # SSL mode.
       sslLoop(socket, flags,
         sslRead(socket.sslHandle, buf, size.cint))
-      result = opResult
+      res = opResult
   else:
-    var data = await recv(socket.fd.TAsyncFD, size, flags)
-    if data.len != 0:
-      copyMem(buf, addr data[0], data.len)
+    var recvIntoFut = recvInto(socket.fd.TAsyncFD, buf, size, flags)
+    yield recvIntoFut
     # Not in SSL mode.
-    result = data.len
+    res = recvIntoFut.read()
+  res
 
-proc readIntoBuf(socket: AsyncSocket,
-    flags: set[SocketFlag]): Future[int] {.async.} =
-  result = await readInto(addr socket.buffer[0], BufferSize, socket, flags)
+template readIntoBuf(socket: AsyncSocket,
+    flags: set[SocketFlag]): int =
+  var size = readInto(addr socket.buffer[0], BufferSize, socket, flags)
   socket.currPos = 0
-  socket.bufLen = result
+  socket.bufLen = size
+  size
 
 proc recv*(socket: AsyncSocket, size: int,
            flags = {SocketFlag.SafeDisconn}): Future[string] {.async.} =
@@ -222,10 +226,11 @@ proc recv*(socket: AsyncSocket, size: int,
   ## to be read then the future will complete with a value of ``""``.
   if socket.isBuffered:
     result = newString(size)
+    shallow(result)
     let originalBufPos = socket.currPos
 
     if socket.bufLen == 0:
-      let res = await socket.readIntoBuf(flags - {SocketFlag.Peek})
+      let res = socket.readIntoBuf(flags - {SocketFlag.Peek})
       if res == 0:
         result.setLen(0)
         return
@@ -236,7 +241,7 @@ proc recv*(socket: AsyncSocket, size: int,
         if SocketFlag.Peek in flags:
           # We don't want to get another buffer if we're peeking.
           break
-        let res = await socket.readIntoBuf(flags - {SocketFlag.Peek})
+        let res = socket.readIntoBuf(flags - {SocketFlag.Peek})
         if res == 0:
           break
 
@@ -251,7 +256,7 @@ proc recv*(socket: AsyncSocket, size: int,
     result.setLen(read)
   else:
     result = newString(size)
-    let read = await readInto(addr result[0], size, socket, flags)
+    let read = readInto(addr result[0], size, socket, flags)
     result.setLen(read)
 
 proc send*(socket: AsyncSocket, data: string,
@@ -302,15 +307,14 @@ proc accept*(socket: AsyncSocket,
         retFut.complete(future.read.client)
   return retFut
 
-proc recvLine*(socket: AsyncSocket,
-    flags = {SocketFlag.SafeDisconn}): Future[string] {.async.} =
-  ## Reads a line of data from ``socket``. Returned future will complete once
-  ## a full line is read or an error occurs.
+proc recvLineInto*(socket: AsyncSocket, resString: ptr string,
+    flags = {SocketFlag.SafeDisconn}) {.async.} =
+  ## Reads a line of data from ``socket`` into ``resString``.
   ##
   ## 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``
@@ -318,27 +322,32 @@ proc recvLine*(socket: AsyncSocket,
   ## The partial line **will be lost**.
   ##
   ## **Warning**: The ``Peek`` flag is not yet implemented.
-  ## 
-  ## **Warning**: ``recvLine`` on unbuffered sockets assumes that the protocol
-  ## uses ``\r\L`` to delimit a new line.
-  template addNLIfEmpty(): stmt =
-    if result.len == 0:
-      result.add("\c\L")
+  ##
+  ## **Warning**: ``recvLineInto`` on unbuffered sockets assumes that the
+  ## protocol uses ``\r\L`` to delimit a new line.
+  ##
+  ## **Warning**: ``recvLineInto`` currently uses a raw pointer to a string for
+  ## performance reasons. This will likely change soon to use FutureVars.
   assert SocketFlag.Peek notin flags ## TODO:
+  result = newFuture[void]("asyncnet.recvLineInto")
+
+  template addNLIfEmpty(): stmt =
+    if resString[].len == 0:
+      resString[].add("\c\L")
+
   if socket.isBuffered:
-    result = ""
     if socket.bufLen == 0:
-      let res = await socket.readIntoBuf(flags)
+      let res = socket.readIntoBuf(flags)
       if res == 0:
         return
 
     var lastR = false
     while true:
       if socket.currPos >= socket.bufLen:
-        let res = await socket.readIntoBuf(flags)
+        let res = socket.readIntoBuf(flags)
         if res == 0:
-          result = ""
-          break
+          resString[].setLen(0)
+          return
 
       case socket.buffer[socket.currPos]
       of '\r':
@@ -353,24 +362,53 @@ proc recvLine*(socket: AsyncSocket,
           socket.currPos.inc()
           return
         else:
-          result.add socket.buffer[socket.currPos]
+          resString[].add socket.buffer[socket.currPos]
       socket.currPos.inc()
   else:
-    result = ""
     var c = ""
     while true:
-      c = await recv(socket, 1, flags)
+      let recvFut = recv(socket, 1, flags)
+      c = recvFut.read()
       if c.len == 0:
-        return ""
+        resString[].setLen(0)
+        return
       if c == "\r":
-        c = await recv(socket, 1, flags) # Skip \L
+        let recvFut = recv(socket, 1, flags) # Skip \L
+        c = recvFut.read()
         assert c == "\L"
         addNLIfEmpty()
         return
       elif c == "\L":
         addNLIfEmpty()
         return
-      add(result.string, c)
+      resString[].add c
+
+proc recvLine*(socket: AsyncSocket,
+    flags = {SocketFlag.SafeDisconn}): Future[string] {.async.} =
+  ## Reads a line of data from ``socket``. Returned future will complete once
+  ## a full line is read or an error occurs.
+  ##
+  ## 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``
+  ## is read) then line will be set to ``""``.
+  ## The partial line **will be lost**.
+  ##
+  ## **Warning**: The ``Peek`` flag is not yet implemented.
+  ##
+  ## **Warning**: ``recvLine`` on unbuffered sockets assumes that the protocol
+  ## uses ``\r\L`` to delimit a new line.
+  template addNLIfEmpty(): stmt =
+    if result.len == 0:
+      result.add("\c\L")
+  assert SocketFlag.Peek notin flags ## TODO:
+
+  result = ""
+  await socket.recvLineInto(addr result, flags)
 
 proc listen*(socket: AsyncSocket, backlog = SOMAXCONN) {.tags: [ReadIOEffect].} =
   ## Marks ``socket`` as accepting connections.
@@ -500,11 +538,11 @@ when not defined(testing) and isMainModule:
         proc (future: Future[void]) =
           echo("Send")
           client.close()
-      
+
       var f = accept(sock)
       f.callback = onAccept
-      
+
     var f = accept(sock)
     f.callback = onAccept
   runForever()
-    
+
diff --git a/lib/pure/basic3d.nim b/lib/pure/basic3d.nim
index 18ebed67b..5a943dd05 100644
--- a/lib/pure/basic3d.nim
+++ b/lib/pure/basic3d.nim
@@ -16,33 +16,33 @@ import times
 ## Vectors are implemented as direction vectors, ie. when transformed with a matrix
 ## the translation part of matrix is ignored. The coordinate system used is
 ## right handed, because its compatible with 2d coordinate system (rotation around
-## zaxis equals 2d rotation). 
+## zaxis equals 2d rotation).
 ## Operators `+` , `-` , `*` , `/` , `+=` , `-=` , `*=` and `/=` are implemented
 ## for vectors and scalars.
 ##
 ##
 ## Quick start example:
-##   
+##
 ##   # Create a matrix which first rotates, then scales and at last translates
-##   
+##
 ##   var m:TMatrix3d=rotate(PI,vector3d(1,1,2.5)) & scale(2.0) & move(100.0,200.0,300.0)
-##   
+##
 ##   # Create a 3d point at (100,150,200) and a vector (5,2,3)
-##   
-##   var pt:TPoint3d=point3d(100.0,150.0,200.0) 
-##   
+##
+##   var pt:TPoint3d=point3d(100.0,150.0,200.0)
+##
 ##   var vec:TVector3d=vector3d(5.0,2.0,3.0)
-##   
-##   
+##
+##
 ##   pt &= m # transforms pt in place
-##   
+##
 ##   var pt2:TPoint3d=pt & m #concatenates pt with m and returns a new point
-##   
+##
 ##   var vec2:TVector3d=vec & m #concatenates vec with m and returns a new vector
 
 
 
-type 
+type
   TMatrix3d* =object
     ## Implements a row major 3d matrix, which means
     ## transformations are applied the order they are concatenated.
@@ -53,12 +53,12 @@ type
     ## [ tx ty tz tw ]
     ax*,ay*,az*,aw*,  bx*,by*,bz*,bw*,  cx*,cy*,cz*,cw*,  tx*,ty*,tz*,tw*:float
   TPoint3d* = object
-    ## Implements a non-homegeneous 2d point stored as 
+    ## Implements a non-homegeneous 2d point stored as
     ## an `x` , `y` and `z` coordinate.
     x*,y*,z*:float
-  TVector3d* = object 
-    ## Implements a 3d **direction vector** stored as 
-    ## an `x` , `y` and `z` coordinate. Direction vector means, 
+  TVector3d* = object
+    ## Implements a 3d **direction vector** stored as
+    ## an `x` , `y` and `z` coordinate. Direction vector means,
     ## that when transforming a vector with a matrix, the translational
     ## part of the matrix is ignored.
     x*,y*,z*:float
@@ -67,7 +67,7 @@ type
 
 # Some forward declarations
 proc matrix3d*(ax,ay,az,aw,bx,by,bz,bw,cx,cy,cz,cw,tx,ty,tz,tw:float):TMatrix3d {.noInit.}
-  ## Creates a new 4x4 3d transformation matrix. 
+  ## Creates a new 4x4 3d transformation matrix.
   ## `ax` , `ay` , `az` is the local x axis.
   ## `bx` , `by` , `bz` is the local y axis.
   ## `cx` , `cy` , `cz` is the local z axis.
@@ -76,7 +76,7 @@ proc vector3d*(x,y,z:float):TVector3d {.noInit,inline.}
   ## Returns a new 3d vector (`x`,`y`,`z`)
 proc point3d*(x,y,z:float):TPoint3d {.noInit,inline.}
   ## Returns a new 4d point (`x`,`y`,`z`)
-proc tryNormalize*(v:var TVector3d):bool 
+proc tryNormalize*(v:var TVector3d):bool
   ## Modifies `v` to have a length of 1.0, keeping its angle.
   ## If `v` has zero length (and thus no angle), it is left unmodified and false is
   ## returned, otherwise true is returned.
@@ -85,7 +85,7 @@ proc tryNormalize*(v:var TVector3d):bool
 
 let
   IDMATRIX*:TMatrix3d=matrix3d(
-    1.0,0.0,0.0,0.0, 
+    1.0,0.0,0.0,0.0,
     0.0,1.0,0.0,0.0,
     0.0,0.0,1.0,0.0,
     0.0,0.0,0.0,1.0)
@@ -114,20 +114,20 @@ proc safeArccos(v:float):float=
   ## due to rounding issues
   return arccos(clamp(v,-1.0,1.0))
 
-template makeBinOpVector(s:expr)= 
+template makeBinOpVector(s:expr)=
   ## implements binary operators + , - , * and / for vectors
-  proc s*(a,b:TVector3d):TVector3d {.inline,noInit.} = 
+  proc s*(a,b:TVector3d):TVector3d {.inline,noInit.} =
     vector3d(s(a.x,b.x),s(a.y,b.y),s(a.z,b.z))
-  proc s*(a:TVector3d,b:float):TVector3d {.inline,noInit.}  = 
+  proc s*(a:TVector3d,b:float):TVector3d {.inline,noInit.}  =
     vector3d(s(a.x,b),s(a.y,b),s(a.z,b))
-  proc s*(a:float,b:TVector3d):TVector3d {.inline,noInit.}  = 
+  proc s*(a:float,b:TVector3d):TVector3d {.inline,noInit.}  =
     vector3d(s(a,b.x),s(a,b.y),s(a,b.z))
-  
-template makeBinOpAssignVector(s:expr)= 
+
+template makeBinOpAssignVector(s:expr)=
   ## implements inplace binary operators += , -= , /= and *= for vectors
-  proc s*(a:var TVector3d,b:TVector3d) {.inline.} = 
+  proc s*(a:var TVector3d,b:TVector3d) {.inline.} =
     s(a.x,b.x) ; s(a.y,b.y) ; s(a.z,b.z)
-  proc s*(a:var TVector3d,b:float) {.inline.} = 
+  proc s*(a:var TVector3d,b:float) {.inline.} =
     s(a.x,b) ; s(a.y,b) ; s(a.z,b)
 
 
@@ -188,20 +188,20 @@ proc scale*(s:float):TMatrix3d {.noInit.} =
 
 proc scale*(s:float,org:TPoint3d):TMatrix3d {.noInit.} =
   ## Returns a new scaling matrix using, `org` as scale origin.
-  result.setElements(s,0,0,0, 0,s,0,0, 0,0,s,0, 
+  result.setElements(s,0,0,0, 0,s,0,0, 0,0,s,0,
     org.x-s*org.x,org.y-s*org.y,org.z-s*org.z,1.0)
 
 proc stretch*(sx,sy,sz:float):TMatrix3d {.noInit.} =
   ## Returns new a stretch matrix, which is a
   ## scale matrix with non uniform scale in x,y and z.
   result.setElements(sx,0,0,0, 0,sy,0,0, 0,0,sz,0, 0,0,0,1)
-    
+
 proc stretch*(sx,sy,sz:float,org:TPoint3d):TMatrix3d {.noInit.} =
   ## Returns a new stretch matrix, which is a
   ## scale matrix with non uniform scale in x,y and z.
   ## `org` is used as stretch origin.
   result.setElements(sx,0,0,0, 0,sy,0,0, 0,0,sz,0, org.x-sx*org.x,org.y-sy*org.y,org.z-sz*org.z,1)
-    
+
 proc move*(dx,dy,dz:float):TMatrix3d {.noInit.} =
   ## Returns a new translation matrix.
   result.setElements(1,0,0,0, 0,1,0,0, 0,0,1,0, dx,dy,dz,1)
@@ -235,7 +235,7 @@ proc rotate*(angle:float,axis:TVector3d):TMatrix3d {.noInit.}=
     uvomc=normax.x*normax.y*omc
     uwomc=normax.x*normax.z*omc
     vwomc=normax.y*normax.z*omc
-    
+
   result.setElements(
     u2+(1.0-u2)*cs, uvomc+wsi, uwomc-vsi, 0.0,
     uvomc-wsi, v2+(1.0-v2)*cs, vwomc+usi, 0.0,
@@ -248,11 +248,11 @@ proc rotate*(angle:float,org:TPoint3d,axis:TVector3d):TMatrix3d {.noInit.}=
 
   # see PDF document http://inside.mines.edu/~gmurray/ArbitraryAxisRotation/ArbitraryAxisRotation.pdf
   # for how this is computed
-  
+
   var normax=axis
   if not normax.tryNormalize: #simplifies matrix computation below a lot
     raise newException(DivByZeroError,"Cannot rotate around zero length axis")
-  
+
   let
     u=normax.x
     v=normax.y
@@ -272,7 +272,7 @@ proc rotate*(angle:float,org:TPoint3d,axis:TVector3d):TMatrix3d {.noInit.}=
     uvomc=normax.x*normax.y*omc
     uwomc=normax.x*normax.z*omc
     vwomc=normax.y*normax.z*omc
-    
+
   result.setElements(
     u2+(v2+w2)*cs, uvomc+wsi, uwomc-vsi, 0.0,
     uvomc-wsi, v2+(u2+w2)*cs, vwomc+usi, 0.0,
@@ -305,7 +305,7 @@ proc rotateY*(angle:float):TMatrix3d {.noInit.}=
     0,1,0,0,
     s,0,c,0,
     0,0,0,1)
-    
+
 proc rotateZ*(angle:float):TMatrix3d {.noInit.}=
   ## Creates a matrix that rotates around the z-axis with `angle` radians,
   ## which is also called a 'yaw' matrix.
@@ -317,19 +317,19 @@ proc rotateZ*(angle:float):TMatrix3d {.noInit.}=
     -s,c,0,0,
     0,0,1,0,
     0,0,0,1)
-    
+
 proc isUniform*(m:TMatrix3d,tol=1.0e-6):bool=
-  ## Checks if the transform is uniform, that is 
+  ## Checks if the transform is uniform, that is
   ## perpendicular axes of equal length, which means (for example)
   ## it cannot transform a sphere into an ellipsoid.
-  ## `tol` is used as tolerance for both equal length comparison 
+  ## `tol` is used as tolerance for both equal length comparison
   ## and perpendicular comparison.
-  
+
   #dot product=0 means perpendicular coord. system, check xaxis vs yaxis and  xaxis vs zaxis
   if abs(m.ax*m.bx+m.ay*m.by+m.az*m.bz)<=tol and # x vs y
     abs(m.ax*m.cx+m.ay*m.cy+m.az*m.cz)<=tol and #x vs z
     abs(m.bx*m.cx+m.by*m.cy+m.bz*m.cz)<=tol: #y vs z
-    
+
     #subtract squared lengths of axes to check if uniform scaling:
     let
       sqxlen=(m.ax*m.ax+m.ay*m.ay+m.az*m.az)
@@ -340,16 +340,16 @@ proc isUniform*(m:TMatrix3d,tol=1.0e-6):bool=
   return false
 
 
-    
+
 proc mirror*(planeperp:TVector3d):TMatrix3d {.noInit.}=
   ## Creates a matrix that mirrors over the plane that has `planeperp` as normal,
   ## and passes through origo. `planeperp` does not need to be normalized.
-  
+
   # https://en.wikipedia.org/wiki/Transformation_matrix
   var n=planeperp
   if not n.tryNormalize:
     raise newException(DivByZeroError,"Cannot mirror over a plane with a zero length normal")
-  
+
   let
     a=n.x
     b=n.y
@@ -357,7 +357,7 @@ proc mirror*(planeperp:TVector3d):TMatrix3d {.noInit.}=
     ab=a*b
     ac=a*c
     bc=b*c
-  
+
   result.setElements(
     1-2*a*a , -2*ab,-2*ac,0,
     -2*ab , 1-2*b*b, -2*bc, 0,
@@ -376,7 +376,7 @@ proc mirror*(org:TPoint3d,planeperp:TVector3d):TMatrix3d {.noInit.}=
   var n=planeperp
   if not n.tryNormalize:
     raise newException(DivByZeroError,"Cannot mirror over a plane with a zero length normal")
-  
+
   let
     a=n.x
     b=n.y
@@ -390,7 +390,7 @@ proc mirror*(org:TPoint3d,planeperp:TVector3d):TMatrix3d {.noInit.}=
     tx=org.x
     ty=org.y
     tz=org.z
-  
+
   result.setElements(
     1-2*aa , -2*ab,-2*ac,0,
     -2*ab , 1-2*bb, -2*bc, 0,
@@ -402,8 +402,8 @@ proc mirror*(org:TPoint3d,planeperp:TVector3d):TMatrix3d {.noInit.}=
 
 proc determinant*(m:TMatrix3d):float=
   ## Computes the determinant of matrix `m`.
-  
-  # This computation is gotten from ratsimp(optimize(determinant(m))) 
+
+  # This computation is gotten from ratsimp(optimize(determinant(m)))
   # in maxima CAS
   let
     O1=m.cx*m.tw-m.cw*m.tx
@@ -423,10 +423,10 @@ proc inverse*(m:TMatrix3d):TMatrix3d {.noInit.}=
   ## Computes the inverse of matrix `m`. If the matrix
   ## determinant is zero, thus not invertible, a EDivByZero
   ## will be raised.
-  
+
   # this computation comes from optimize(invert(m)) in maxima CAS
-  
-  let 
+
+  let
     det=m.determinant
     O2=m.cy*m.tw-m.cw*m.ty
     O3=m.cz*m.tw-m.cw*m.tz
@@ -464,7 +464,7 @@ proc inverse*(m:TMatrix3d):TMatrix3d {.noInit.}=
 proc equals*(m1:TMatrix3d,m2:TMatrix3d,tol=1.0e-6):bool=
   ## Checks if all elements of `m1`and `m2` is equal within
   ## a given tolerance `tol`.
-  return 
+  return
     abs(m1.ax-m2.ax)<=tol and
     abs(m1.ay-m2.ay)<=tol and
     abs(m1.az-m2.az)<=tol and
@@ -486,11 +486,11 @@ proc `=~`*(m1,m2:TMatrix3d):bool=
   ## Checks if `m1` and `m2` is approximately equal, using a
   ## tolerance of 1e-6.
   equals(m1,m2)
-  
+
 proc transpose*(m:TMatrix3d):TMatrix3d {.noInit.}=
   ## Returns the transpose of `m`
   result.setElements(m.ax,m.bx,m.cx,m.tx,m.ay,m.by,m.cy,m.ty,m.az,m.bz,m.cz,m.tz,m.aw,m.bw,m.cw,m.tw)
-  
+
 proc getXAxis*(m:TMatrix3d):TVector3d {.noInit.}=
   ## Gets the local x axis of `m`
   result.x=m.ax
@@ -509,26 +509,26 @@ proc getZAxis*(m:TMatrix3d):TVector3d {.noInit.}=
   result.y=m.cy
   result.z=m.cz
 
-    
+
 proc `$`*(m:TMatrix3d):string=
   ## String representation of `m`
-  return rtos(m.ax) & "," & rtos(m.ay) & "," &rtos(m.az) & "," & rtos(m.aw) &
-    "\n" & rtos(m.bx) & "," & rtos(m.by) & "," &rtos(m.bz) & "," & rtos(m.bw) &
-    "\n" & rtos(m.cx) & "," & rtos(m.cy) & "," &rtos(m.cz) & "," & rtos(m.cw) &
-    "\n" & rtos(m.tx) & "," & rtos(m.ty) & "," &rtos(m.tz) & "," & rtos(m.tw)
-    
+  return rtos(m.ax) & "," & rtos(m.ay) & "," & rtos(m.az) & "," & rtos(m.aw) &
+    "\n" & rtos(m.bx) & "," & rtos(m.by) & "," & rtos(m.bz) & "," & rtos(m.bw) &
+    "\n" & rtos(m.cx) & "," & rtos(m.cy) & "," & rtos(m.cz) & "," & rtos(m.cw) &
+    "\n" & rtos(m.tx) & "," & rtos(m.ty) & "," & rtos(m.tz) & "," & rtos(m.tw)
+
 proc apply*(m:TMatrix3d, x,y,z:var float, translate=false)=
   ## Applies transformation `m` onto `x` , `y` , `z` , optionally
   ## using the translation part of the matrix.
-  let 
+  let
     oldx=x
     oldy=y
     oldz=z
-    
+
   x=m.cx*oldz+m.bx*oldy+m.ax*oldx
   y=m.cy*oldz+m.by*oldy+m.ay*oldx
   z=m.cz*oldz+m.bz*oldy+m.az*oldx
-    
+
   if translate:
     x+=m.tx
     y+=m.ty
@@ -552,13 +552,13 @@ proc `len=`*(v:var TVector3d,newlen:float) {.noInit.} =
   ## an arbitrary vector of the requested length is returned.
 
   let fac=newlen/v.len
-  
+
   if newlen==0.0:
     v.x=0.0
     v.y=0.0
     v.z=0.0
     return
-  
+
   if fac==Inf or fac==NegInf:
     #to short for float accuracy
     #do as good as possible:
@@ -588,7 +588,7 @@ proc `&` *(v:TVector3d,m:TMatrix3d):TVector3d {.noInit.} =
   ## Concatenate vector `v` with a transformation matrix.
   ## Transforming a vector ignores the translational part
   ## of the matrix.
-  
+
   #               | AX AY AZ AW |
   # | X Y Z 1 | * | BX BY BZ BW |
   #               | CX CY CZ CW |
@@ -605,12 +605,12 @@ proc `&=` *(v:var TVector3d,m:TMatrix3d) {.noInit.} =
   ## Applies transformation `m` onto `v` in place.
   ## Transforming a vector ignores the translational part
   ## of the matrix.
-  
+
   #               | AX AY AZ AW |
   # | X Y Z 1 | * | BX BY BZ BW |
   #               | CX CY CZ CW |
   #               | 0  0  0  1  |
-  
+
   let
     newx=m.cx*v.z+m.bx*v.y+m.ax*v.x
     newy=m.cy*v.z+m.by*v.y+m.ay*v.x
@@ -620,38 +620,38 @@ proc `&=` *(v:var TVector3d,m:TMatrix3d) {.noInit.} =
 
 proc transformNorm*(v:var TVector3d,m:TMatrix3d)=
   ## Applies a normal direction transformation `m` onto `v` in place.
-  ## The resulting vector is *not* normalized.  Transforming a vector ignores the 
-  ## translational part of the matrix. If the matrix is not invertible 
+  ## The resulting vector is *not* normalized.  Transforming a vector ignores the
+  ## translational part of the matrix. If the matrix is not invertible
   ## (determinant=0), an EDivByZero will be raised.
 
   # transforming a normal is done by transforming
   # by the transpose of the inverse of the original matrix
-  
+
   # Major reason this simple function is here is that this function can be optimized in the future,
   # (possibly by hardware) as well as having a consistent API with the 2d version.
   v&=transpose(inverse(m))
-  
+
 proc transformInv*(v:var TVector3d,m:TMatrix3d)=
-  ## Applies the inverse of `m` on vector `v`. Transforming a vector ignores 
-  ## the translational part of the matrix.  Transforming a vector ignores the 
+  ## Applies the inverse of `m` on vector `v`. Transforming a vector ignores
+  ## the translational part of the matrix.  Transforming a vector ignores the
   ## translational part of the matrix.
   ## If the matrix is not invertible (determinant=0), an EDivByZero
   ## will be raised.
-  
+
   # Major reason this simple function is here is that this function can be optimized in the future,
   # (possibly by hardware) as well as having a consistent API with the 2d version.
   v&=m.inverse
- 
+
 proc transformNormInv*(vec:var TVector3d,m:TMatrix3d)=
   ## Applies an inverse normal direction transformation `m` onto `v` in place.
-  ## This is faster than creating an inverse 
-  ## matrix and transformNorm(...) it. Transforming a vector ignores the 
+  ## This is faster than creating an inverse
+  ## matrix and transformNorm(...) it. Transforming a vector ignores the
   ## translational part of the matrix.
-  
+
   # see vector2d:s equivalent for a deeper look how/why this works
   vec&=m.transpose
 
-proc tryNormalize*(v:var TVector3d):bool= 
+proc tryNormalize*(v:var TVector3d):bool=
   ## Modifies `v` to have a length of 1.0, keeping its angle.
   ## If `v` has zero length (and thus no angle), it is left unmodified and false is
   ## returned, otherwise true is returned.
@@ -663,26 +663,26 @@ proc tryNormalize*(v:var TVector3d):bool=
   v.x/=mag
   v.y/=mag
   v.z/=mag
-  
+
   return true
 
-proc normalize*(v:var TVector3d) {.inline.}= 
+proc normalize*(v:var TVector3d) {.inline.}=
   ## Modifies `v` to have a length of 1.0, keeping its angle.
   ## If  `v` has zero length, an EDivByZero will be raised.
   if not tryNormalize(v):
     raise newException(DivByZeroError,"Cannot normalize zero length vector")
 
 proc rotate*(vec:var TVector3d,angle:float,axis:TVector3d)=
-  ## Rotates `vec` in place, with `angle` radians over `axis`, which passes 
+  ## Rotates `vec` in place, with `angle` radians over `axis`, which passes
   ## through origo.
 
   # see PDF document http://inside.mines.edu/~gmurray/ArbitraryAxisRotation/ArbitraryAxisRotation.pdf
   # for how this is computed
-  
+
   var normax=axis
   if not normax.tryNormalize:
     raise newException(DivByZeroError,"Cannot rotate around zero length axis")
-  
+
   let
     cs=cos(angle)
     si=sin(angle)
@@ -694,11 +694,11 @@ proc rotate*(vec:var TVector3d,angle:float,axis:TVector3d)=
     y=vec.y
     z=vec.z
     uxyzomc=(u*x+v*y+w*z)*omc
-  
+
   vec.x=u*uxyzomc+x*cs+(v*z-w*y)*si
   vec.y=v*uxyzomc+y*cs+(w*x-u*z)*si
   vec.z=w*uxyzomc+z*cs+(u*y-v*x)*si
-  
+
 proc scale*(v:var TVector3d,s:float)=
   ## Scales the vector in place with factor `s`
   v.x*=s
@@ -713,12 +713,12 @@ proc stretch*(v:var TVector3d,sx,sy,sz:float)=
 
 proc mirror*(v:var TVector3d,planeperp:TVector3d)=
   ## Computes the mirrored vector of `v` over the plane
-  ## that has `planeperp` as normal direction. 
+  ## that has `planeperp` as normal direction.
   ## `planeperp` does not need to be normalized.
-  
+
   var n=planeperp
   n.normalize
-  
+
   let
     x=v.x
     y=v.y
@@ -729,7 +729,7 @@ proc mirror*(v:var TVector3d,planeperp:TVector3d)=
     ac=a*c
     ab=a*b
     bc=b*c
-  
+
   v.x= -2*(ac*z+ab*y+a*a*x)+x
   v.y= -2*(bc*z+b*b*y+ab*x)+y
   v.z= -2*(c*c*z+bc*y+ac*x)+z
@@ -740,7 +740,7 @@ proc `-` *(v:TVector3d):TVector3d=
   result.x= -v.x
   result.y= -v.y
   result.z= -v.z
-    
+
 # declare templated binary operators
 makeBinOpVector(`+`)
 makeBinOpVector(`-`)
@@ -752,7 +752,7 @@ makeBinOpAssignVector(`*=`)
 makeBinOpAssignVector(`/=`)
 
 proc dot*(v1,v2:TVector3d):float {.inline.}=
-  ## Computes the dot product of two vectors. 
+  ## Computes the dot product of two vectors.
   ## Returns 0.0 if the vectors are perpendicular.
   return v1.x*v2.x+v1.y*v2.y+v1.z*v2.z
 
@@ -769,12 +769,12 @@ proc cross*(v1,v2:TVector3d):TVector3d {.inline.}=
 proc equals*(v1,v2:TVector3d,tol=1.0e-6):bool=
   ## Checks if two vectors approximately equals with a tolerance.
   return abs(v2.x-v1.x)<=tol and abs(v2.y-v1.y)<=tol and abs(v2.z-v1.z)<=tol
-  
+
 proc `=~` *(v1,v2:TVector3d):bool=
-  ## Checks if two vectors approximately equals with a 
+  ## Checks if two vectors approximately equals with a
   ## hardcoded tolerance 1e-6
   equals(v1,v2)
-  
+
 proc angleTo*(v1,v2:TVector3d):float=
   ## Returns the smallest angle between v1 and v2,
   ## which is in range 0-PI
@@ -801,7 +801,7 @@ proc arbitraryAxis*(norm:TVector3d):TMatrix3d {.noInit.}=
   ay=cross(norm,ax)
   ay.normalize()
   az=cross(ax,ay)
-  
+
   result.setElements(
     ax.x,ax.y,ax.z,0.0,
     ay.x,ay.y,ay.z,0.0,
@@ -811,20 +811,20 @@ proc arbitraryAxis*(norm:TVector3d):TMatrix3d {.noInit.}=
 proc bisect*(v1,v2:TVector3d):TVector3d {.noInit.}=
   ## Computes the bisector between v1 and v2 as a normalized vector.
   ## If one of the input vectors has zero length, a normalized version
-  ## of the other is returned. If both input vectors has zero length, 
+  ## of the other is returned. If both input vectors has zero length,
   ## an arbitrary normalized vector `v1` is returned.
   var
     vmag1=v1.len
     vmag2=v2.len
-    
-  # zero length vector equals arbitrary vector, just change 
+
+  # zero length vector equals arbitrary vector, just change
   # magnitude to one to avoid zero division
-  if vmag1==0.0: 
+  if vmag1==0.0:
     if vmag2==0: #both are zero length return any normalized vector
       return XAXIS
     vmag1=1.0
-  if vmag2==0.0: vmag2=1.0    
-    
+  if vmag2==0.0: vmag2=1.0
+
   let
     x1=v1.x/vmag1
     y1=v1.y/vmag1
@@ -832,14 +832,14 @@ proc bisect*(v1,v2:TVector3d):TVector3d {.noInit.}=
     x2=v2.x/vmag2
     y2=v2.y/vmag2
     z2=v2.z/vmag2
-    
+
   result.x=(x1 + x2) * 0.5
   result.y=(y1 + y2) * 0.5
   result.z=(z1 + z2) * 0.5
-  
+
   if not result.tryNormalize():
     # This can happen if vectors are colinear. In this special case
-    # there are actually inifinitely many bisectors, we select just 
+    # there are actually inifinitely many bisectors, we select just
     # one of them.
     result=v1.cross(XAXIS)
     if result.sqrLen<1.0e-9:
@@ -857,14 +857,14 @@ proc point3d*(x,y,z:float):TPoint3d=
   result.x=x
   result.y=y
   result.z=z
- 
+
 proc sqrDist*(a,b:TPoint3d):float=
   ## Computes the squared distance between `a`and `b`
   let dx=b.x-a.x
   let dy=b.y-a.y
   let dz=b.z-a.z
   result=dx*dx+dy*dy+dz*dz
-  
+
 proc dist*(a,b:TPoint3d):float {.inline.}=
   ## Computes the absolute distance between `a`and `b`
   result=sqrt(sqrDist(a,b))
@@ -876,7 +876,7 @@ proc `$` *(p:TPoint3d):string=
   result.add(rtos(p.y))
   result.add(",")
   result.add(rtos(p.z))
-  
+
 proc `&`*(p:TPoint3d,m:TMatrix3d):TPoint3d=
   ## Concatenates a point `p` with a transform `m`,
   ## resulting in a new, transformed point.
@@ -893,18 +893,18 @@ proc `&=` *(p:var TPoint3d,m:TMatrix3d)=
   p.x=m.cx*z+m.bx*y+m.ax*x+m.tx
   p.y=m.cy*z+m.by*y+m.ay*x+m.ty
   p.z=m.cz*z+m.bz*y+m.az*x+m.tz
-    
+
 proc transformInv*(p:var TPoint3d,m:TMatrix3d)=
   ## Applies the inverse of transformation `m` onto `p` in place.
   ## If the matrix is not invertable (determinant=0) , EDivByZero will
   ## be raised.
-  
+
   # can possibly be more optimized in the future so use this function when possible
   p&=inverse(m)
 
 
 proc `+`*(p:TPoint3d,v:TVector3d):TPoint3d {.noInit,inline.} =
-  ## Adds a vector `v` to a point `p`, resulting 
+  ## Adds a vector `v` to a point `p`, resulting
   ## in a new point.
   result.x=p.x+v.x
   result.y=p.y+v.y
@@ -917,7 +917,7 @@ proc `+=`*(p:var TPoint3d,v:TVector3d) {.noInit,inline.} =
   p.z+=v.z
 
 proc `-`*(p:TPoint3d,v:TVector3d):TPoint3d {.noInit,inline.} =
-  ## Subtracts a vector `v` from a point `p`, resulting 
+  ## Subtracts a vector `v` from a point `p`, resulting
   ## in a new point.
   result.x=p.x-v.x
   result.y=p.y-v.y
@@ -933,37 +933,37 @@ proc `-=`*(p:var TPoint3d,v:TVector3d) {.noInit,inline.} =
   ## Subtracts a vector `v` from a point `p` in place.
   p.x-=v.x
   p.y-=v.y
-  p.z-=v.z  
+  p.z-=v.z
 
 proc equals(p1,p2:TPoint3d,tol=1.0e-6):bool {.inline.}=
   ## Checks if two points approximately equals with a tolerance.
   return abs(p2.x-p1.x)<=tol and abs(p2.y-p1.y)<=tol and abs(p2.z-p1.z)<=tol
 
 proc `=~`*(p1,p2:TPoint3d):bool {.inline.}=
-  ## Checks if two vectors approximately equals with a 
+  ## Checks if two vectors approximately equals with a
   ## hardcoded tolerance 1e-6
   equals(p1,p2)
 
 proc rotate*(p:var TPoint3d,rad:float,axis:TVector3d)=
-  ## Rotates point `p` in place `rad` radians about an axis 
+  ## Rotates point `p` in place `rad` radians about an axis
   ## passing through origo.
-  
+
   var v=vector3d(p.x,p.y,p.z)
   v.rotate(rad,axis) # reuse this code here since doing the same thing and quite complicated
   p.x=v.x
   p.y=v.y
   p.z=v.z
-    
+
 proc rotate*(p:var TPoint3d,angle:float,org:TPoint3d,axis:TVector3d)=
-  ## Rotates point `p` in place `rad` radians about an axis 
+  ## Rotates point `p` in place `rad` radians about an axis
   ## passing through `org`
-  
+
   # see PDF document http://inside.mines.edu/~gmurray/ArbitraryAxisRotation/ArbitraryAxisRotation.pdf
   # for how this is computed
-  
+
   var normax=axis
   normax.normalize
-  
+
   let
     cs=cos(angle)
     omc=1.0-cs
@@ -987,17 +987,17 @@ proc rotate*(p:var TPoint3d,angle:float,org:TPoint3d,axis:TVector3d)=
     bv=b*v
     cw=c*w
     uxmvymwz=ux-vy-wz
-    
+
   p.x=(a*(vv+ww)-u*(bv+cw-uxmvymwz))*omc + x*cs + (b*w+v*z-c*v-w*y)*si
   p.y=(b*(uu+ww)-v*(au+cw-uxmvymwz))*omc + y*cs + (c*u-a*w+w*x-u*z)*si
   p.z=(c*(uu+vv)-w*(au+bv-uxmvymwz))*omc + z*cs + (a*v+u*y-b*u-v*x)*si
-  
+
 proc scale*(p:var TPoint3d,fac:float) {.inline.}=
   ## Scales a point in place `fac` times with world origo as origin.
   p.x*=fac
   p.y*=fac
   p.z*=fac
-  
+
 proc scale*(p:var TPoint3d,fac:float,org:TPoint3d){.inline.}=
   ## Scales the point in place `fac` times with `org` as origin.
   p.x=(p.x - org.x) * fac + org.x
@@ -1005,7 +1005,7 @@ proc scale*(p:var TPoint3d,fac:float,org:TPoint3d){.inline.}=
   p.z=(p.z - org.z) * fac + org.z
 
 proc stretch*(p:var TPoint3d,facx,facy,facz:float){.inline.}=
-  ## Scales a point in place non uniformly `facx` , `facy` , `facz` times 
+  ## Scales a point in place non uniformly `facx` , `facy` , `facz` times
   ## with world origo as origin.
   p.x*=facx
   p.y*=facy
@@ -1017,7 +1017,7 @@ proc stretch*(p:var TPoint3d,facx,facy,facz:float,org:TPoint3d){.inline.}=
   p.x=(p.x - org.x) * facx + org.x
   p.y=(p.y - org.y) * facy + org.y
   p.z=(p.z - org.z) * facz + org.z
-  
+
 
 proc move*(p:var TPoint3d,dx,dy,dz:float){.inline.}=
   ## Translates a point `dx` , `dy` , `dz` in place.
@@ -1033,7 +1033,7 @@ proc move*(p:var TPoint3d,v:TVector3d){.inline.}=
 
 proc area*(a,b,c:TPoint3d):float {.inline.}=
   ## Computes the area of the triangle thru points `a` , `b` and `c`
-  
+
   # The area of a planar 3d quadliteral is the magnitude of the cross
   # product of two edge vectors. Taking this time 0.5 gives the triangle area.
   return cross(b-a,c-a).len*0.5
diff --git a/lib/pure/collections/tables.nim b/lib/pure/collections/tables.nim
index 232e52c89..a9357ce67 100644
--- a/lib/pure/collections/tables.nim
+++ b/lib/pure/collections/tables.nim
@@ -819,15 +819,18 @@ proc enlarge[A](t: var CountTable[A]) =
   swap(t.data, n)
 
 proc `[]=`*[A](t: var CountTable[A], key: A, val: int) =
-  ## puts a (key, value)-pair into `t`. `val` has to be positive.
+  ## puts a (key, value)-pair into `t`.
   assert val > 0
   var h = rawGet(t, key)
   if h >= 0:
     t.data[h].val = val
   else:
-    h = -1 - h
-    t.data[h].key = key
-    t.data[h].val = val
+    if mustRehash(len(t.data), t.counter): enlarge(t)
+    rawInsert(t, t.data, key, val)
+    inc(t.counter)
+    #h = -1 - h
+    #t.data[h].key = key
+    #t.data[h].val = val
 
 proc initCountTable*[A](initialSize=64): CountTable[A] =
   ## creates a new count table that is empty.
diff --git a/lib/pure/ftpclient.nim b/lib/pure/ftpclient.nim
index b46f8343c..dd141eb01 100644
--- a/lib/pure/ftpclient.nim
+++ b/lib/pure/ftpclient.nim
@@ -593,7 +593,7 @@ proc register*(d: Dispatcher, ftp: AsyncFTPClient): Delegate {.discardable.} =
   ftp.disp = d
   return ftp.disp.register(ftp.csock)
 
-when isMainModule:
+when not defined(testing) and isMainModule:
   proc main =
     var d = newDispatcher()
     let hev =
diff --git a/lib/pure/gentabs.nim b/lib/pure/gentabs.nim
index 8c89a0ac3..84d0a44de 100644
--- a/lib/pure/gentabs.nim
+++ b/lib/pure/gentabs.nim
@@ -9,7 +9,7 @@
 
 ## The ``gentabs`` module implements an efficient hash table that is a
 ## key-value mapping. The keys are required to be strings, but the values
-## may be any Nim or user defined type. This module supports matching 
+## may be any Nim or user defined type. This module supports matching
 ## of keys in case-sensitive, case-insensitive and style-insensitive modes.
 
 {.deprecated.}
@@ -22,7 +22,7 @@ type
     modeCaseSensitive,     ## case sensitive matching of keys
     modeCaseInsensitive,   ## case insensitive matching of keys
     modeStyleInsensitive   ## style sensitive matching of keys
-    
+
   TGenKeyValuePair[T] = tuple[key: string, val: T]
   TGenKeyValuePairSeq[T] = seq[TGenKeyValuePair[T]]
   TGenTable*[T] = object of RootObj
@@ -83,7 +83,7 @@ proc rawGet[T](tbl: PGenTable[T], key: string): int =
     h = nextTry(h, high(tbl.data))
   result = - 1
 
-proc rawInsert[T](tbl: PGenTable[T], data: var TGenKeyValuePairSeq[T], 
+proc rawInsert[T](tbl: PGenTable[T], data: var TGenKeyValuePairSeq[T],
                   key: string, val: T) =
   var h: THash
   h = myhash(tbl, key) and high(data)
@@ -96,7 +96,7 @@ proc enlarge[T](tbl: PGenTable[T]) =
   var n: TGenKeyValuePairSeq[T]
   newSeq(n, len(tbl.data) * growthFactor)
   for i in countup(0, high(tbl.data)):
-    if not isNil(tbl.data[i].key): 
+    if not isNil(tbl.data[i].key):
       rawInsert[T](tbl, n, tbl.data[i].key, tbl.data[i].val)
   swap(tbl.data, n)
 
@@ -141,20 +141,20 @@ when isMainModule:
   assert(not x.hasKey("NOPE"))    # ...but key "NOPE" is not in the table.
   for k,v in pairs(x):            # make sure the 'pairs' iterator works
     assert(x[k]==v)
-  
+
   #
   # Verify a table of user-defined types
   #
   type
     TMyType = tuple[first, second: string] # a pair of strings
-  
+
   var y = newGenTable[TMyType](modeCaseInsensitive) # hash table where each
                                                     # value is TMyType tuple
-  
+
   #var junk: TMyType = ("OK", "Here")
-  
+
   #echo junk.first, " ", junk.second
-  
+
   y["Hello"] = ("Hello", "World")
   y["Goodbye"] = ("Goodbye", "Everyone")
   #y["Hello"] = TMyType( ("Hello", "World") )
@@ -163,42 +163,44 @@ when isMainModule:
   assert( not isNil(y["Hello"].first) )
   assert( y["Hello"].first == "Hello" )
   assert( y["Hello"].second == "World" )
-    
+
   #
   # Verify table of tables
   #
-  var z: PGenTable[ PGenTable[int] ] # hash table where each value is 
+  var z: PGenTable[ PGenTable[int] ] # hash table where each value is
                                      # a hash table of ints
-  
+
   z = newGenTable[PGenTable[int]](modeCaseInsensitive)
   z["first"] = newGenTable[int](modeCaseInsensitive)
   z["first"]["one"] = 1
   z["first"]["two"] = 2
   z["first"]["three"] = 3
-  
+
   z["second"] = newGenTable[int](modeCaseInsensitive)
   z["second"]["red"] = 10
   z["second"]["blue"] = 20
-  
+
   assert(len(z) == 2)               # length of outer table
   assert(len(z["first"]) == 3)      # length of "first" table
   assert(len(z["second"]) == 2)     # length of "second" table
   assert( z["first"]["one"] == 1)   # retrieve from first inner table
   assert( z["second"]["red"] == 10) # retrieve from second inner table
-  
-  var output = ""
-  for k, v in pairs(z):
-    output.add( "$# ($#) ->\n" % [k,$len(v)] )
-    for k2,v2 in pairs(v):
-      output.add( "  $# <-> $#\n" % [k2,$v2] )
-
-  let expected = unindent """
-    first (3) ->
-      two <-> 2
-      three <-> 3
-      one <-> 1
-    second (2) ->
-      red <-> 10
-      blue <-> 20
-  """
-  assert output == expected
+
+  when false:
+    # disabled: depends on hash order:
+    var output = ""
+    for k, v in pairs(z):
+      output.add( "$# ($#) ->\L" % [k,$len(v)] )
+      for k2,v2 in pairs(v):
+        output.add( "  $# <-> $#\L" % [k2,$v2] )
+
+    let expected = unindent """
+      first (3) ->
+        two <-> 2
+        three <-> 3
+        one <-> 1
+      second (2) ->
+        red <-> 10
+        blue <-> 20
+    """
+    assert output == expected
diff --git a/lib/pure/marshal.nim b/lib/pure/marshal.nim
index bf9e33296..e0092f314 100644
--- a/lib/pure/marshal.nim
+++ b/lib/pure/marshal.nim
@@ -15,8 +15,8 @@
 ## type than its compiletime type:
 ##
 ## .. code-block:: nim
-## 
-##   type 
+##
+##   type
 ##     TA = object
 ##     TB = object of TA
 ##       f: int
@@ -28,6 +28,8 @@
 ##   new(b)
 ##   a = b
 ##   echo($$a[]) # produces "{}", not "{f: 0}"
+##
+## **Note**: The ``to`` and ``$$`` operations are available at compile-time!
 
 import streams, typeinfo, json, intsets, tables
 
@@ -38,7 +40,12 @@ proc storeAny(s: Stream, a: TAny, stored: var IntSet) =
   case a.kind
   of akNone: assert false
   of akBool: s.write($getBool(a))
-  of akChar: s.write(escapeJson($getChar(a)))
+  of akChar:
+    let ch = getChar(a)
+    if ch < '\128':
+      s.write(escapeJson($ch))
+    else:
+      s.write($int(ch))
   of akArray, akSequence:
     if a.kind == akSequence and isNil(a): s.write("null")
     else:
@@ -92,7 +99,7 @@ proc storeAny(s: Stream, a: TAny, stored: var IntSet) =
 proc loadAny(p: var JsonParser, a: TAny, t: var Table[BiggestInt, pointer]) =
   case a.kind
   of akNone: assert false
-  of akBool: 
+  of akBool:
     case p.kind
     of jsonFalse: setBiggestInt(a, 0)
     of jsonTrue: setBiggestInt(a, 1)
@@ -105,8 +112,12 @@ proc loadAny(p: var JsonParser, a: TAny, t: var Table[BiggestInt, pointer]) =
         setBiggestInt(a, ord(x[0]))
         next(p)
         return
+    elif p.kind == jsonInt:
+      setBiggestInt(a, getInt(p))
+      next(p)
+      return
     raiseParseErr(p, "string of length 1 expected for a char")
-  of akEnum: 
+  of akEnum:
     if p.kind == jsonString:
       setBiggestInt(a, getEnumOrdinal(a, p.str))
       next(p)
@@ -122,7 +133,7 @@ proc loadAny(p: var JsonParser, a: TAny, t: var Table[BiggestInt, pointer]) =
     if p.kind == jsonArrayEnd: next(p)
     else: raiseParseErr(p, "']' end of array expected")
   of akSequence:
-    case p.kind 
+    case p.kind
     of jsonNull:
       setPointer(a, nil)
       next(p)
@@ -143,7 +154,7 @@ proc loadAny(p: var JsonParser, a: TAny, t: var Table[BiggestInt, pointer]) =
     if p.kind != jsonObjectStart: raiseParseErr(p, "'{' expected for an object")
     next(p)
     while p.kind != jsonObjectEnd and p.kind != jsonEof:
-      if p.kind != jsonString: 
+      if p.kind != jsonString:
         raiseParseErr(p, "string expected for a field name")
       var fieldName = p.str
       next(p)
@@ -160,7 +171,7 @@ proc loadAny(p: var JsonParser, a: TAny, t: var Table[BiggestInt, pointer]) =
     if p.kind == jsonArrayEnd: next(p)
     else: raiseParseErr(p, "']' end of array expected")
   of akPtr, akRef:
-    case p.kind 
+    case p.kind
     of jsonNull:
       setPointer(a, nil)
       next(p)
@@ -170,7 +181,7 @@ proc loadAny(p: var JsonParser, a: TAny, t: var Table[BiggestInt, pointer]) =
     of jsonArrayStart:
       next(p)
       if a.kind == akRef: invokeNew(a)
-      else: setPointer(a, alloc0(a.baseTypeSize))      
+      else: setPointer(a, alloc0(a.baseTypeSize))
       if p.kind == jsonInt:
         t[p.getInt] = getPointer(a)
         next(p)
@@ -179,8 +190,8 @@ proc loadAny(p: var JsonParser, a: TAny, t: var Table[BiggestInt, pointer]) =
       if p.kind == jsonArrayEnd: next(p)
       else: raiseParseErr(p, "']' end of ref-address pair expected")
     else: raiseParseErr(p, "int for pointer type expected")
-  of akProc, akPointer, akCString: 
-    case p.kind 
+  of akProc, akPointer, akCString:
+    case p.kind
     of jsonNull:
       setPointer(a, nil)
       next(p)
@@ -189,7 +200,7 @@ proc loadAny(p: var JsonParser, a: TAny, t: var Table[BiggestInt, pointer]) =
       next(p)
     else: raiseParseErr(p, "int for pointer type expected")
   of akString:
-    case p.kind 
+    case p.kind
     of jsonNull:
       setPointer(a, nil)
       next(p)
@@ -197,7 +208,7 @@ proc loadAny(p: var JsonParser, a: TAny, t: var Table[BiggestInt, pointer]) =
       setString(a, p.str)
       next(p)
     else: raiseParseErr(p, "string expected")
-  of akInt..akInt64, akUInt..akUInt64: 
+  of akInt..akInt64, akUInt..akUInt64:
     if p.kind == jsonInt:
       setBiggestInt(a, getInt(p))
       next(p)
@@ -243,22 +254,22 @@ proc to*[T](data: string): T =
   ## reads data and transforms it to a ``T``.
   var tab = initTable[BiggestInt, pointer]()
   loadAny(newStringStream(data), toAny(result), tab)
-  
+
 when not defined(testing) and isMainModule:
   template testit(x: expr) = echo($$to[type(x)]($$x))
 
   var x: array[0..4, array[0..4, string]] = [
-    ["test", "1", "2", "3", "4"], ["test", "1", "2", "3", "4"], 
-    ["test", "1", "2", "3", "4"], ["test", "1", "2", "3", "4"], 
+    ["test", "1", "2", "3", "4"], ["test", "1", "2", "3", "4"],
+    ["test", "1", "2", "3", "4"], ["test", "1", "2", "3", "4"],
     ["test", "1", "2", "3", "4"]]
   testit(x)
   var test2: tuple[name: string, s: uint] = ("tuple test", 56u)
   testit(test2)
-  
+
   type
     TE = enum
       blah, blah2
-  
+
     TestObj = object
       test, asd: int
       case test2: TE
@@ -266,7 +277,7 @@ when not defined(testing) and isMainModule:
         help: string
       else:
         nil
-        
+
     PNode = ref TNode
     TNode = object
       next, prev: PNode
@@ -294,7 +305,7 @@ when not defined(testing) and isMainModule:
   test4.a = "ref string test: A"
   test4.b = "ref string test: B"
   testit(test4)
-  
+
   var test5 = @[(0,1),(2,3),(4,5)]
   testit(test5)
 
@@ -305,7 +316,7 @@ when not defined(testing) and isMainModule:
   echo($$test7)
   testit(test7)
 
-  type 
+  type
     TA {.inheritable.} = object
     TB = object of TA
       f: int
diff --git a/lib/pure/math.nim b/lib/pure/math.nim
index daa108460..cb58ea39b 100644
--- a/lib/pure/math.nim
+++ b/lib/pure/math.nim
@@ -85,7 +85,7 @@ proc fac*(n: int): int {.noSideEffect.} =
 proc isPowerOfTwo*(x: int): bool {.noSideEffect.} =
   ## 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)
+  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.
@@ -114,18 +114,23 @@ proc sum*[T](x: openArray[T]): T {.noSideEffect.} =
   ## If `x` is empty, 0 is returned.
   for i in items(x): result = result + i
 
-proc mean*(x: openArray[float]): float {.noSideEffect.} = 
-  ## computes the mean of the elements in `x`. 
+template toFloat(f: float): float = f
+
+proc mean*[T](x: openArray[T]): float {.noSideEffect.} =
+  ## computes the mean of the elements in `x`, which are first converted to floats.
   ## If `x` is empty, NaN is returned.
-  result = sum(x) / toFloat(len(x))
+  ## ``toFloat(x: T): float`` must be defined.
+  for i in items(x): result = result + toFloat(i)
+  result = result / toFloat(len(x))
 
-proc variance*(x: openArray[float]): float {.noSideEffect.} = 
+proc variance*[T](x: openArray[T]): float {.noSideEffect.} =
   ## computes the variance of the elements in `x`. 
   ## If `x` is empty, NaN is returned.
+  ## ``toFloat(x: T): float`` must be defined.
   result = 0.0
   var m = mean(x)
-  for i in 0 .. high(x):
-    var diff = x[i] - m
+  for i in items(x):
+    var diff = toFloat(i) - m
     result = result + diff*diff
   result = result / toFloat(len(x))
 
diff --git a/lib/pure/pegs.nimfix b/lib/pure/pegs.nimfix
deleted file mode 100644
index 15bc95351..000000000
--- a/lib/pure/pegs.nimfix
+++ /dev/null
@@ -1,1770 +0,0 @@
-#
-#
-#            Nim's Runtime Library
-#        (c) Copyright 2012 Andreas Rumpf
-#
-#    See the file "copying.txt", included in this
-#    distribution, for details about the copyright.
-#
-
-## Simple PEG (Parsing expression grammar) matching. Uses no memorization, but
-## uses superoperators and symbol inlining to improve performance. Note:
-## Matching performance is hopefully competitive with optimized regular
-## expression engines.
-##
-## .. include:: ../doc/pegdocs.txt
-##
-
-include "system/inclrtl"
-
-const
-  useUnicode = true ## change this to deactivate proper UTF-8 support
-
-import
-  strutils
-
-when useUnicode:
-  import unicode
-
-const
-  InlineThreshold = 5  ## number of leaves; -1 to disable inlining
-  MaxSubpatterns* = 10 ## defines the maximum number of subpatterns that
-                       ## can be captured. More subpatterns cannot be captured! 
-
-type
-  PegKind = enum
-    pkEmpty,
-    pkAny,              ## any character (.)
-    pkAnyRune,          ## any Unicode character (_)
-    pkNewLine,          ## CR-LF, LF, CR
-    pkLetter,           ## Unicode letter
-    pkLower,            ## Unicode lower case letter
-    pkUpper,            ## Unicode upper case letter
-    pkTitle,            ## Unicode title character
-    pkWhitespace,       ## Unicode whitespace character
-    pkTerminal,
-    pkTerminalIgnoreCase,
-    pkTerminalIgnoreStyle,
-    pkChar,             ## single character to match
-    pkCharChoice,
-    pkNonTerminal,
-    pkSequence,         ## a b c ... --> Internal DSL: peg(a, b, c)
-    pkOrderedChoice,    ## a / b / ... --> Internal DSL: a / b or /[a, b, c]
-    pkGreedyRep,        ## a*     --> Internal DSL: *a
-                        ## a+     --> (a a*)
-    pkGreedyRepChar,    ## x* where x is a single character (superop)
-    pkGreedyRepSet,     ## [set]* (superop)
-    pkGreedyAny,        ## .* or _* (superop)
-    pkOption,           ## a?     --> Internal DSL: ?a
-    pkAndPredicate,     ## &a     --> Internal DSL: &a
-    pkNotPredicate,     ## !a     --> Internal DSL: !a
-    pkCapture,          ## {a}    --> Internal DSL: capture(a)
-    pkBackRef,          ## $i     --> Internal DSL: backref(i)
-    pkBackRefIgnoreCase,
-    pkBackRefIgnoreStyle,
-    pkSearch,           ## @a     --> Internal DSL: !*a
-    pkCapturedSearch,   ## {@} a  --> Internal DSL: !*\a
-    pkRule,             ## a <- b
-    pkList,             ## a, b
-    pkStartAnchor       ## ^      --> Internal DSL: startAnchor()
-  NonTerminalFlag = enum
-    ntDeclared, ntUsed
-  NonTerminalObj = object         ## represents a non terminal symbol
-    name: string                  ## the name of the symbol
-    line: int                     ## line the symbol has been declared/used in
-    col: int                      ## column the symbol has been declared/used in
-    flags: set[NonTerminalFlag]   ## the nonterminal's flags
-    rule: TNode                   ## the rule that the symbol refers to
-  TNode {.shallow.} = object
-    case kind: PegKind
-    of pkEmpty..pkWhitespace: nil
-    of pkTerminal, pkTerminalIgnoreCase, pkTerminalIgnoreStyle: term: string
-    of pkChar, pkGreedyRepChar: ch: char
-    of pkCharChoice, pkGreedyRepSet: charChoice: ref set[char]
-    of pkNonTerminal: nt: PNonTerminal
-    of pkBackRef..pkBackRefIgnoreStyle: index: range[0..MaxSubpatterns]
-    else: sons: seq[TNode]
-  PNonTerminal* = ref NonTerminalObj
-  TPeg* = TNode
-
-block:
-  type
-    Peg = TNode
-    NonTerminal = PNonTerminal
-  {.deprecated: [TPeg: Peg, PNonTerminal: NonTerminal].}
-
-proc term*(t: string): TPeg {.nosideEffect, rtl, extern: "npegs$1Str".} =
-  ## constructs a PEG from a terminal string
-  if t.len != 1:
-    result.kind = pkTerminal
-    result.term = t
-  else:
-    result.kind = pkChar
-    result.ch = t[0]
-
-proc termIgnoreCase*(t: string): TPeg {.nosideEffect, rtl, extern: "npegs$1".} =
-  ## constructs a PEG from a terminal string; ignore case for matching
-  result.kind = pkTerminalIgnoreCase
-  result.term = t
-
-proc termIgnoreStyle*(t: string): TPeg {.nosideEffect, rtl, extern: "npegs$1".} =
-  ## constructs a PEG from a terminal string; ignore style for matching
-  result.kind = pkTerminalIgnoreStyle
-  result.term = t
-
-proc term*(t: char): TPeg {.nosideEffect, rtl, extern: "npegs$1Char".} =
-  ## constructs a PEG from a terminal char
-  assert t != '\0'
-  result.kind = pkChar
-  result.ch = t
-  
-proc charSet*(s: set[char]): TPeg {.nosideEffect, rtl, extern: "npegs$1".} =
-  ## constructs a PEG from a character set `s`
-  assert '\0' notin s
-  result.kind = pkCharChoice
-  new(result.charChoice)
-  result.charChoice[] = s
-
-proc len(a: TPeg): int {.inline.} = return a.sons.len
-proc add(d: var TPeg, s: TPeg) {.inline.} = add(d.sons, s)
-
-proc addChoice(dest: var TPeg, elem: TPeg) =
-  var L = dest.len-1
-  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: 
-      dest.sons[L] = charSet(dest.sons[L].charChoice[] + {elem.ch})
-    else: add(dest, elem)
-  else: add(dest, elem)
-
-template multipleOp(k: PegKind, localOpt: expr) =
-  result.kind = k
-  result.sons = @[]
-  for x in items(a):
-    if x.kind == k:
-      for y in items(x.sons):
-        localOpt(result, y)
-    else:
-      localOpt(result, x)
-  if result.len == 1:
-    result = result.sons[0]
-
-proc `/`*(a: varargs[TPeg]): TPeg {.
-  nosideEffect, rtl, extern: "npegsOrderedChoice".} =
-  ## constructs an ordered choice with the PEGs in `a`
-  multipleOp(pkOrderedChoice, addChoice)
-
-proc addSequence(dest: var TPeg, elem: TPeg) =
-  var L = dest.len-1
-  if L >= 0 and dest.sons[L].kind == pkTerminal: 
-    # caution! Do not introduce false aliasing here!
-    case elem.kind
-    of pkTerminal: 
-      dest.sons[L] = term(dest.sons[L].term & elem.term)
-    of pkChar: 
-      dest.sons[L] = term(dest.sons[L].term & elem.ch)
-    else: add(dest, elem)
-  else: add(dest, elem)
-
-proc sequence*(a: varargs[TPeg]): TPeg {.
-  nosideEffect, rtl, extern: "npegs$1".} =
-  ## constructs a sequence with all the PEGs from `a`
-  multipleOp(pkSequence, addSequence)
- 
-proc `?`*(a: TPeg): TPeg {.nosideEffect, rtl, extern: "npegsOptional".} =
-  ## constructs an optional for the PEG `a`
-  if a.kind in {pkOption, pkGreedyRep, pkGreedyAny, pkGreedyRepChar,
-                pkGreedyRepSet}:
-    # a* ?  --> a*
-    # a? ?  --> a?
-    result = a
-  else:
-    result.kind = pkOption
-    result.sons = @[a]
-
-proc `*`*(a: TPeg): TPeg {.nosideEffect, rtl, extern: "npegsGreedyRep".} =
-  ## constructs a "greedy repetition" for the PEG `a`
-  case a.kind
-  of pkGreedyRep, pkGreedyRepChar, pkGreedyRepSet, pkGreedyAny, pkOption:
-    assert false
-    # produces endless loop!
-  of pkChar:
-    result.kind = pkGreedyRepChar
-    result.ch = a.ch
-  of pkCharChoice:
-    result.kind = pkGreedyRepSet
-    result.charChoice = a.charChoice # copying a reference suffices!
-  of pkAny, pkAnyRune:
-    result.kind = pkGreedyAny
-  else:
-    result.kind = pkGreedyRep
-    result.sons = @[a]
-
-proc `!*`*(a: TPeg): TPeg {.nosideEffect, rtl, extern: "npegsSearch".} =
-  ## constructs a "search" for the PEG `a`
-  result.kind = pkSearch
-  result.sons = @[a]
-
-proc `!*\`*(a: TPeg): TPeg {.noSideEffect, rtl, 
-                             extern: "npgegsCapturedSearch".} =
-  ## constructs a "captured search" for the PEG `a`
-  result.kind = pkCapturedSearch
-  result.sons = @[a]
-
-proc `+`*(a: TPeg): TPeg {.nosideEffect, rtl, extern: "npegsGreedyPosRep".} =
-  ## constructs a "greedy positive repetition" with the PEG `a`
-  return sequence(a, *a)
-  
-proc `&`*(a: TPeg): TPeg {.nosideEffect, rtl, extern: "npegsAndPredicate".} =
-  ## constructs an "and predicate" with the PEG `a`
-  result.kind = pkAndPredicate
-  result.sons = @[a]
-
-proc `!`*(a: TPeg): TPeg {.nosideEffect, rtl, extern: "npegsNotPredicate".} =
-  ## constructs a "not predicate" with the PEG `a`
-  result.kind = pkNotPredicate
-  result.sons = @[a]
-
-proc any*: TPeg {.inline.} =
-  ## constructs the PEG `any character`:idx: (``.``)
-  result.kind = pkAny
-
-proc anyRune*: TPeg {.inline.} =
-  ## constructs the PEG `any rune`:idx: (``_``)
-  result.kind = pkAnyRune
-
-proc newLine*: TPeg {.inline.} =
-  ## constructs the PEG `newline`:idx: (``\n``)
-  result.kind = pkNewLine
-
-proc unicodeLetter*: TPeg {.inline.} = 
-  ## constructs the PEG ``\letter`` which matches any Unicode letter.
-  result.kind = pkLetter
-  
-proc unicodeLower*: TPeg {.inline.} = 
-  ## constructs the PEG ``\lower`` which matches any Unicode lowercase letter.
-  result.kind = pkLower 
-
-proc unicodeUpper*: TPeg {.inline.} = 
-  ## constructs the PEG ``\upper`` which matches any Unicode uppercase letter.
-  result.kind = pkUpper
-  
-proc unicodeTitle*: TPeg {.inline.} = 
-  ## constructs the PEG ``\title`` which matches any Unicode title letter.
-  result.kind = pkTitle
-
-proc unicodeWhitespace*: TPeg {.inline.} = 
-  ## constructs the PEG ``\white`` which matches any Unicode 
-  ## whitespace character.
-  result.kind = pkWhitespace
-
-proc startAnchor*: TPeg {.inline.} = 
-  ## constructs the PEG ``^`` which matches the start of the input.  
-  result.kind = pkStartAnchor
-
-proc endAnchor*: TPeg {.inline.} = 
-  ## constructs the PEG ``$`` which matches the end of the input.  
-  result = !any()
-
-proc capture*(a: TPeg): TPeg {.nosideEffect, rtl, extern: "npegsCapture".} =
-  ## constructs a capture with the PEG `a`
-  result.kind = pkCapture
-  result.sons = @[a]
-
-proc backref*(index: range[1..MaxSubpatterns]): TPeg {.
-  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]): TPeg {.
-  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]): TPeg {.
-  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
-  result.index = index-1
-
-proc spaceCost(n: TPeg): int =
-  case n.kind
-  of pkEmpty: discard
-  of pkTerminal, pkTerminalIgnoreCase, pkTerminalIgnoreStyle, pkChar,
-     pkGreedyRepChar, pkCharChoice, pkGreedyRepSet, 
-     pkAny..pkWhitespace, pkGreedyAny:
-    result = 1
-  of pkNonTerminal:
-    # we cannot inline a rule with a non-terminal
-    result = InlineThreshold+1
-  else:
-    for i in 0..n.len-1:
-      inc(result, spaceCost(n.sons[i]))
-      if result >= InlineThreshold: break
-
-proc nonterminal*(n: PNonTerminal): TPeg {.
-  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:
-    when false: echo "inlining symbol: ", n.name
-    result = n.rule # inlining of rule enables better optimizations
-  else:
-    result.kind = pkNonTerminal
-    result.nt = n
-
-proc newNonTerminal*(name: string, line, column: int): PNonTerminal {.
-  nosideEffect, rtl, extern: "npegs$1".} =
-  ## constructs a nonterminal symbol
-  new(result)
-  result.name = name
-  result.line = line
-  result.col = column
-
-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'})
-
-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', '_'})
-
-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 = 
-  case c
-  of '\b': result = "\\b"
-  of '\t': result = "\\t"
-  of '\c': result = "\\c"
-  of '\L': result = "\\l"
-  of '\v': result = "\\v"
-  of '\f': result = "\\f"
-  of '\e': result = "\\e"
-  of '\a': result = "\\a"
-  of '\\': result = "\\\\"
-  of 'a'..'z', 'A'..'Z', '0'..'9', '_': result = $c
-  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 = 
-  result = "'"
-  for c in items(str): add result, esc(c, {'\''})
-  add result, '\''
-  
-proc charSetEscAux(cc: set[char]): string = 
-  const reserved = {'^', '-', ']'}
-  result = ""
-  var c1 = 0
-  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: 
-        add result, esc(chr(c1), reserved)
-      elif c2 == succ(c1): 
-        add result, esc(chr(c1), reserved) & esc(chr(c2), reserved)
-      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: 
-    result = "[^" & charSetEscAux({'\1'..'\xFF'} - cc) & ']'
-  else: 
-    result = '[' & charSetEscAux(cc) & ']'
-  
-proc toStrAux(r: TPeg, res: var string) = 
-  case r.kind
-  of pkEmpty: add(res, "()")
-  of pkAny: add(res, '.')
-  of pkAnyRune: add(res, '_')
-  of pkLetter: add(res, "\\letter")
-  of pkLower: add(res, "\\lower")
-  of pkUpper: add(res, "\\upper")
-  of pkTitle: add(res, "\\title")
-  of pkWhitespace: add(res, "\\white")
-
-  of pkNewLine: add(res, "\\n")
-  of pkTerminal: add(res, singleQuoteEsc(r.term))
-  of pkTerminalIgnoreCase:
-    add(res, 'i')
-    add(res, singleQuoteEsc(r.term))
-  of pkTerminalIgnoreStyle:
-    add(res, 'y')
-    add(res, singleQuoteEsc(r.term))
-  of pkChar: add(res, singleQuoteEsc(r.ch))
-  of pkCharChoice: add(res, charSetEsc(r.charChoice[]))
-  of pkNonTerminal: add(res, r.nt.name)
-  of pkSequence:
-    add(res, '(')
-    toStrAux(r.sons[0], res)
-    for i in 1 .. high(r.sons):
-      add(res, ' ')
-      toStrAux(r.sons[i], res)
-    add(res, ')')
-  of pkOrderedChoice:
-    add(res, '(')
-    toStrAux(r.sons[0], res)
-    for i in 1 .. high(r.sons):
-      add(res, " / ")
-      toStrAux(r.sons[i], res)
-    add(res, ')')
-  of pkGreedyRep:
-    toStrAux(r.sons[0], res)
-    add(res, '*')
-  of pkGreedyRepChar:
-    add(res, singleQuoteEsc(r.ch))
-    add(res, '*')
-  of pkGreedyRepSet:
-    add(res, charSetEsc(r.charChoice[]))
-    add(res, '*')
-  of pkGreedyAny:
-    add(res, ".*")
-  of pkOption:
-    toStrAux(r.sons[0], res)
-    add(res, '?')
-  of pkAndPredicate:
-    add(res, '&')
-    toStrAux(r.sons[0], res)
-  of pkNotPredicate:
-    add(res, '!')
-    toStrAux(r.sons[0], res)
-  of pkSearch:
-    add(res, '@')
-    toStrAux(r.sons[0], res)
-  of pkCapturedSearch:
-    add(res, "{@}")
-    toStrAux(r.sons[0], res)
-  of pkCapture:
-    add(res, '{')
-    toStrAux(r.sons[0], res)    
-    add(res, '}')
-  of pkBackRef: 
-    add(res, '$')
-    add(res, $r.index)
-  of pkBackRefIgnoreCase: 
-    add(res, "i$")
-    add(res, $r.index)
-  of pkBackRefIgnoreStyle: 
-    add(res, "y$")
-    add(res, $r.index)
-  of pkRule:
-    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")  
-  of pkStartAnchor:
-    add(res, '^')
-
-proc `$` *(r: TPeg): string {.nosideEffect, rtl, extern: "npegsToString".} =
-  ## converts a PEG to its string representation
-  result = ""
-  toStrAux(r, result)
-
-# --------------------- core engine -------------------------------------------
-
-type
-  Captures* = object ## contains the captured substrings.
-    matches: array[0..MaxSubpatterns-1, tuple[first, last: int]]
-    ml: int
-    origStart: int
-
-{.deprecated: [TCaptures: Captures].}
-
-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]
-
-when not useUnicode:
-  type
-    Rune = char
-  template fastRuneAt(s, i, ch: expr) =
-    ch = s[i]
-    inc(i)
-  template runeLenAt(s, i: expr): expr = 1
-
-  proc isAlpha(a: char): bool {.inline.} = return a in {'a'..'z','A'..'Z'}
-  proc isUpper(a: char): bool {.inline.} = return a in {'A'..'Z'}
-  proc isLower(a: char): bool {.inline.} = return a in {'a'..'z'}
-  proc isTitle(a: char): bool {.inline.} = return false
-  proc isWhiteSpace(a: char): bool {.inline.} = return a in {' ', '\9'..'\13'}
-
-proc rawMatch*(s: string, p: TPeg, start: int, c: var Captures): int {.
-               nosideEffect, rtl, extern: "npegs$1".} =
-  ## 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
-  case p.kind
-  of pkEmpty: result = 0 # match of length 0
-  of pkAny:
-    if s[start] != '\0': result = 1
-    else: result = -1
-  of pkAnyRune:
-    if s[start] != '\0':
-      result = runeLenAt(s, start)
-    else:
-      result = -1
-  of pkLetter: 
-    if s[start] != '\0':
-      var a: Rune
-      result = start
-      fastRuneAt(s, result, a)
-      if isAlpha(a): dec(result, start)
-      else: result = -1
-    else:
-      result = -1
-  of pkLower: 
-    if s[start] != '\0':
-      var a: Rune
-      result = start
-      fastRuneAt(s, result, a)
-      if isLower(a): dec(result, start)
-      else: result = -1
-    else:
-      result = -1
-  of pkUpper: 
-    if s[start] != '\0':
-      var a: Rune
-      result = start
-      fastRuneAt(s, result, a)
-      if isUpper(a): dec(result, start)
-      else: result = -1
-    else:
-      result = -1
-  of pkTitle: 
-    if s[start] != '\0':
-      var a: Rune
-      result = start
-      fastRuneAt(s, result, a)
-      if isTitle(a): dec(result, start) 
-      else: result = -1
-    else:
-      result = -1
-  of pkWhitespace: 
-    if s[start] != '\0':
-      var a: Rune
-      result = start
-      fastRuneAt(s, result, a)
-      if isWhiteSpace(a): dec(result, start)
-      else: result = -1
-    else:
-      result = -1
-  of pkGreedyAny:
-    result = len(s) - start
-  of pkNewLine:
-    if s[start] == '\L': result = 1
-    elif s[start] == '\C':
-      if s[start+1] == '\L': result = 2
-      else: result = 1
-    else: result = -1
-  of pkTerminal:
-    result = len(p.term)
-    for i in 0..result-1:
-      if p.term[i] != s[start+i]:
-        result = -1
-        break
-  of pkTerminalIgnoreCase:
-    var
-      i = 0
-      a, b: Rune
-    result = start
-    while i < len(p.term):
-      fastRuneAt(p.term, i, a)
-      fastRuneAt(s, result, b)
-      if toLower(a) != toLower(b):
-        result = -1
-        break
-    dec(result, start)
-  of pkTerminalIgnoreStyle:
-    var
-      i = 0
-      a, b: Rune
-    result = start
-    while i < len(p.term):
-      while true:
-        fastRuneAt(p.term, i, a)
-        if a != Rune('_'): break
-      while true:
-        fastRuneAt(s, result, b)
-        if b != Rune('_'): break
-      if toLower(a) != toLower(b):
-        result = -1
-        break
-    dec(result, start)
-  of pkChar:
-    if p.ch == s[start]: result = 1
-    else: result = -1
-  of pkCharChoice:
-    if contains(p.charChoice[], s[start]): result = 1
-    else: result = -1
-  of pkNonTerminal:
-    var oldMl = c.ml
-    when false: echo "enter: ", p.nt.name
-    result = rawMatch(s, p.nt.rule, start, c)
-    when false: echo "leave: ", p.nt.name
-    if result < 0: c.ml = oldMl
-  of pkSequence:
-    var oldMl = c.ml  
-    result = 0
-    for i in 0..high(p.sons):
-      var x = rawMatch(s, p.sons[i], start+result, c)
-      if x < 0:
-        c.ml = oldMl
-        result = -1
-        break
-      else: inc(result, x)
-  of pkOrderedChoice:
-    var oldMl = c.ml
-    for i in 0..high(p.sons):
-      result = rawMatch(s, p.sons[i], start, c)
-      if result >= 0: break
-      c.ml = oldMl
-  of pkSearch:
-    var oldMl = c.ml
-    result = 0
-    while start+result < s.len:
-      var x = rawMatch(s, p.sons[0], start+result, c)
-      if x >= 0:
-        inc(result, x)
-        return
-      inc(result)
-    result = -1
-    c.ml = oldMl
-  of pkCapturedSearch:
-    var idx = c.ml # reserve a slot for the subpattern
-    inc(c.ml)
-    result = 0
-    while start+result < s.len:
-      var x = rawMatch(s, p.sons[0], start+result, c)
-      if x >= 0:
-        if idx < MaxSubpatterns:
-          c.matches[idx] = (start, start+result-1)
-        #else: silently ignore the capture
-        inc(result, x)
-        return
-      inc(result)
-    result = -1
-    c.ml = idx
-  of pkGreedyRep:
-    result = 0
-    while true:
-      var x = rawMatch(s, p.sons[0], start+result, c)
-      # if x == 0, we have an endless loop; so the correct behaviour would be
-      # not to break. But endless loops can be easily introduced:
-      # ``(comment / \w*)*`` is such an example. Breaking for x == 0 does the
-      # expected thing in this case.
-      if x <= 0: break
-      inc(result, x)
-  of pkGreedyRepChar:
-    result = 0
-    var ch = p.ch
-    while ch == s[start+result]: inc(result)
-  of pkGreedyRepSet:
-    result = 0
-    while contains(p.charChoice[], s[start+result]): inc(result)
-  of pkOption:
-    result = max(0, rawMatch(s, p.sons[0], start, c))
-  of pkAndPredicate:
-    var oldMl = c.ml
-    result = rawMatch(s, p.sons[0], start, c)
-    if result >= 0: result = 0 # do not consume anything
-    else: c.ml = oldMl
-  of pkNotPredicate:
-    var oldMl = c.ml
-    result = rawMatch(s, p.sons[0], start, c)
-    if result < 0: result = 0
-    else:
-      c.ml = oldMl
-      result = -1
-  of pkCapture:
-    var idx = c.ml # reserve a slot for the subpattern
-    inc(c.ml)
-    result = rawMatch(s, p.sons[0], start, c)
-    if result >= 0:
-      if idx < MaxSubpatterns:
-        c.matches[idx] = (start, start+result-1)
-      #else: silently ignore the capture
-    else:
-      c.ml = idx
-  of pkBackRef..pkBackRefIgnoreStyle: 
-    if p.index >= c.ml: return -1
-    var (a, b) = c.matches[p.index]
-    var n: TPeg
-    n.kind = succ(pkTerminal, ord(p.kind)-ord(pkBackRef)) 
-    n.term = s.substr(a, b)
-    result = rawMatch(s, n, start, c)
-  of pkStartAnchor:
-    if c.origStart == start: result = 0
-    else: result = -1
-  of pkRule, pkList: assert false
-
-template fillMatches(s, caps, c: expr) =
-  for k in 0..c.ml-1:
-    caps[k] = substr(s, c.matches[k][0], c.matches[k][1])
-
-proc match*(s: string, pattern: TPeg, matches: var openArray[string],
-            start = 0): bool {.nosideEffect, rtl, extern: "npegs$1Capture".} =
-  ## returns ``true`` if ``s[start..]`` matches the ``pattern`` and
-  ## the captured substrings in the array ``matches``. If it does not
-  ## match, nothing is written into ``matches`` and ``false`` is
-  ## returned.
-  var c: Captures
-  c.origStart = start
-  result = rawMatch(s, pattern, start, c) == len(s) - start
-  if result: fillMatches(s, matches, c)
-
-proc match*(s: string, pattern: TPeg, 
-            start = 0): bool {.nosideEffect, rtl, extern: "npegs$1".} =
-  ## returns ``true`` if ``s`` matches the ``pattern`` beginning from ``start``.
-  var c: Captures
-  c.origStart = start
-  result = rawMatch(s, pattern, start, c) == len(s)-start
-
-proc matchLen*(s: string, pattern: TPeg, matches: var openArray[string],
-               start = 0): int {.nosideEffect, rtl, extern: "npegs$1Capture".} =
-  ## 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
-  ## of zero can happen. It's possible that a suffix of `s` remains
-  ## that does not belong to the match.
-  var c: Captures
-  c.origStart = start
-  result = rawMatch(s, pattern, start, c)
-  if result >= 0: fillMatches(s, matches, c)
-
-proc matchLen*(s: string, pattern: TPeg, 
-               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
-  ## of zero can happen. It's possible that a suffix of `s` remains
-  ## that does not belong to the match.
-  var c: Captures
-  c.origStart = start
-  result = rawMatch(s, pattern, start, c)
-
-proc find*(s: string, pattern: TPeg, matches: var openArray[string],
-           start = 0): int {.nosideEffect, rtl, extern: "npegs$1Capture".} =
-  ## returns the starting 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 is returned.
-  var c: Captures
-  c.origStart = start
-  for i in start .. s.len-1:
-    c.ml = 0
-    if rawMatch(s, pattern, i, c) >= 0:
-      fillMatches(s, matches, c)
-      return i
-  return -1
-  # could also use the pattern here: (!P .)* P
-  
-proc findBounds*(s: string, pattern: TPeg, 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`` 
-  ## and the captured
-  ## substrings in the array ``matches``. If it does not match, nothing
-  ## is written into ``matches`` and (-1,0) is returned.
-  var c: Captures
-  c.origStart = start
-  for i in start .. s.len-1:
-    c.ml = 0
-    var L = rawMatch(s, pattern, i, c)
-    if L >= 0:
-      fillMatches(s, matches, c)
-      return (i, i+L-1)
-  return (-1, 0)
-  
-proc find*(s: string, pattern: TPeg, 
-           start = 0): int {.nosideEffect, rtl, extern: "npegs$1".} =
-  ## returns the starting position of ``pattern`` in ``s``. If it does not
-  ## match, -1 is returned.
-  var c: Captures
-  c.origStart = start
-  for i in start .. s.len-1:
-    if rawMatch(s, pattern, i, c) >= 0: return i
-  return -1
-  
-iterator findAll*(s: string, pattern: TPeg, start = 0): string = 
-  ## yields all matching *substrings* of `s` that match `pattern`.
-  var c: Captures
-  c.origStart = start
-  var i = start
-  while i < s.len:
-    c.ml = 0
-    var L = rawMatch(s, pattern, i, c)
-    if L < 0:
-      inc(i, 1)
-    else:
-      yield substr(s, i, i+L-1)
-      inc(i, L)
-    
-proc findAll*(s: string, pattern: TPeg, start = 0): seq[string] {.
-  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: TPeg): bool =
-  ## 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+}": 
-  ##     # matches a key=value pair:
-  ##     echo("Key: ", matches[0])
-  ##     echo("Value: ", matches[1])
-  ##   elif line =~ peg"\s*{'#'.*}":
-  ##     # matches a comment
-  ##     # note that the implicit ``matches`` array is different from the
-  ##     # ``matches`` array of the first branch
-  ##     echo("comment: ", matches[0])
-  ##   else:
-  ##     echo("syntax error")
-  ##  
-  bind MaxSubpatterns
-  when not declaredInScope(matches):
-    var matches {.inject.}: array[0..MaxSubpatterns-1, string]
-  match(s, pattern, matches)
-
-# ------------------------- more string handling ------------------------------
-
-proc contains*(s: string, pattern: TPeg, start = 0): bool {.
-  nosideEffect, rtl, extern: "npegs$1".} =
-  ## same as ``find(s, pattern, start) >= 0``
-  return find(s, pattern, start) >= 0
-
-proc contains*(s: string, pattern: TPeg, matches: var openArray[string],
-              start = 0): bool {.nosideEffect, rtl, extern: "npegs$1Capture".} =
-  ## same as ``find(s, pattern, matches, start) >= 0``
-  return find(s, pattern, matches, start) >= 0
-
-proc startsWith*(s: string, prefix: TPeg, start = 0): bool {.
-  nosideEffect, rtl, extern: "npegs$1".} =
-  ## returns true if `s` starts with the pattern `prefix`
-  result = matchLen(s, prefix, start) >= 0
-
-proc endsWith*(s: string, suffix: TPeg, start = 0): bool {.
-  nosideEffect, rtl, extern: "npegs$1".} =
-  ## returns true if `s` ends with the pattern `prefix`
-  var c: Captures
-  c.origStart = start
-  for i in start .. s.len-1:
-    if rawMatch(s, suffix, i, c) == s.len - i: return true
-
-proc replacef*(s: string, sub: TPeg, by: string): string {.
-  nosideEffect, rtl, extern: "npegs$1".} =
-  ## Replaces `sub` in `s` by the string `by`. Captures can be accessed in `by`
-  ## with the notation ``$i`` and ``$#`` (see strutils.`%`). Examples:
-  ##
-  ## .. code-block:: nim
-  ##   "var1=key; var2=key2".replace(peg"{\ident}'='{\ident}", "$1<-$2$2")
-  ##
-  ## Results in:
-  ##
-  ## .. code-block:: nim
-  ##
-  ##   "var1<-keykey; val2<-key2key2"
-  result = ""
-  var i = 0
-  var caps: array[0..MaxSubpatterns-1, string]
-  var c: Captures
-  while i < s.len:
-    c.ml = 0
-    var x = rawMatch(s, sub, i, c)
-    if x <= 0:
-      add(result, s[i])
-      inc(i)
-    else:
-      fillMatches(s, caps, c)
-      addf(result, by, caps)
-      inc(i, x)
-  add(result, substr(s, i))
-
-proc replace*(s: string, sub: TPeg, by = ""): string {.
-  nosideEffect, rtl, extern: "npegs$1".} =
-  ## Replaces `sub` in `s` by the string `by`. Captures cannot be accessed
-  ## in `by`.
-  result = ""
-  var i = 0
-  var c: Captures
-  while i < s.len:
-    var x = rawMatch(s, sub, i, c)
-    if x <= 0:
-      add(result, s[i])
-      inc(i)
-    else:
-      add(result, by)
-      inc(i, x)
-  add(result, substr(s, i))
-  
-proc parallelReplace*(s: string, subs: varargs[
-                      tuple[pattern: TPeg, repl: string]]): string {.
-                      nosideEffect, rtl, extern: "npegs$1".} = 
-  ## Returns a modified copy of `s` with the substitutions in `subs`
-  ## applied in parallel.
-  result = ""
-  var i = 0
-  var c: Captures
-  var caps: array[0..MaxSubpatterns-1, string]
-  while i < s.len:
-    block searchSubs:
-      for j in 0..high(subs):
-        c.ml = 0
-        var x = rawMatch(s, subs[j][0], i, c)
-        if x > 0:
-          fillMatches(s, caps, c)
-          addf(result, subs[j][1], caps)
-          inc(i, x)
-          break searchSubs
-      add(result, s[i])
-      inc(i)
-  # copy the rest:
-  add(result, substr(s, i))  
-  
-proc transformFile*(infile, outfile: string,
-                    subs: varargs[tuple[pattern: TPeg, repl: string]]) {.
-                    rtl, extern: "npegs$1".} =
-  ## reads in the file `infile`, performs a parallel replacement (calls
-  ## `parallelReplace`) and writes back to `outfile`. Raises ``EIO`` if an
-  ## 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: TPeg): string =
-  ## Splits the string `s` into substrings.
-  ##
-  ## Substrings are separated by the PEG `sep`.
-  ## Examples:
-  ##
-  ## .. code-block:: nim
-  ##   for word in split("00232this02939is39an22example111", peg"\d+"):
-  ##     writeln(stdout, word)
-  ##
-  ## Results in:
-  ##
-  ## .. code-block:: nim
-  ##   "this"
-  ##   "is"
-  ##   "an"
-  ##   "example"
-  ##
-  var c: Captures
-  var
-    first = 0
-    last = 0
-  while last < len(s):
-    c.ml = 0
-    var x = rawMatch(s, sep, last, c)
-    if x > 0: inc(last, x)
-    first = last
-    while last < len(s):
-      inc(last)
-      c.ml = 0
-      x = rawMatch(s, sep, last, c)
-      if x > 0: break
-    if first < last:
-      yield substr(s, first, last-1)
-
-proc split*(s: string, sep: TPeg): seq[string] {.
-  nosideEffect, rtl, extern: "npegs$1".} =
-  ## Splits the string `s` into substrings.
-  accumulateResult(split(s, sep))
-
-# ------------------- scanner -------------------------------------------------
-
-type
-  TModifier = enum
-    modNone,
-    modVerbatim,
-    modIgnoreCase,
-    modIgnoreStyle
-  TTokKind = enum       ## enumeration of all tokens
-    tkInvalid,          ## invalid token
-    tkEof,              ## end of file reached
-    tkAny,              ## .
-    tkAnyRune,          ## _
-    tkIdentifier,       ## abc
-    tkStringLit,        ## "abc" or 'abc'
-    tkCharSet,          ## [^A-Z]
-    tkParLe,            ## '('
-    tkParRi,            ## ')'
-    tkCurlyLe,          ## '{'
-    tkCurlyRi,          ## '}'
-    tkCurlyAt,          ## '{@}'
-    tkArrow,            ## '<-'
-    tkBar,              ## '/'
-    tkStar,             ## '*'
-    tkPlus,             ## '+'
-    tkAmp,              ## '&'
-    tkNot,              ## '!'
-    tkOption,           ## '?'
-    tkAt,               ## '@'
-    tkBuiltin,          ## \identifier
-    tkEscaped,          ## \\
-    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
-    lineNumber: int           ## the current line number
-    lineStart: int            ## index of last line start in buffer
-    colOffset: int            ## column to add
-    filename: string
-
-const
-  tokKindToStr: array[TTokKind, string] = [
-    "invalid", "[EOF]", ".", "_", "identifier", "string literal",
-    "character set", "(", ")", "{", "}", "{@}",
-    "<-", "/", "*", "+", "&", "!", "?",
-    "@", "built-in", "escaped", "$", "$", "^"
-  ]
-
-proc handleCR(L: var PegLexer, pos: int): int =
-  assert(L.buf[pos] == '\c')
-  inc(L.lineNumber)
-  result = pos+1
-  if L.buf[result] == '\L': inc(result)
-  L.lineStart = result
-
-proc handleLF(L: var PegLexer, pos: int): int =
-  assert(L.buf[pos] == '\L')
-  inc(L.lineNumber)
-  result = pos+1
-  L.lineStart = result
-
-proc init(L: var PegLexer, input, filename: string, line = 1, col = 0) = 
-  L.buf = input
-  L.bufpos = 0
-  L.lineNumber = line
-  L.colOffset = col
-  L.lineStart = 0
-  L.filename = filename
-
-proc getColumn(L: PegLexer): int {.inline.} = 
-  result = abs(L.bufpos - L.lineStart) + L.colOffset
-
-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) = 
-  case c.buf[c.bufpos]
-  of '0'..'9': 
-    xi = (xi shl 4) or (ord(c.buf[c.bufpos]) - ord('0'))
-    inc(c.bufpos)
-  of 'a'..'f': 
-    xi = (xi shl 4) or (ord(c.buf[c.bufpos]) - ord('a') + 10)
-    inc(c.bufpos)
-  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) = 
-  inc(c.bufpos)
-  case c.buf[c.bufpos]
-  of 'r', 'R', 'c', 'C': 
-    add(tok.literal, '\c')
-    inc(c.bufpos)
-  of 'l', 'L': 
-    add(tok.literal, '\L')
-    inc(c.bufpos)
-  of 'f', 'F': 
-    add(tok.literal, '\f')
-    inc(c.bufpos)
-  of 'e', 'E': 
-    add(tok.literal, '\e')
-    inc(c.bufpos)
-  of 'a', 'A': 
-    add(tok.literal, '\a')
-    inc(c.bufpos)
-  of 'b', 'B': 
-    add(tok.literal, '\b')
-    inc(c.bufpos)
-  of 'v', 'V': 
-    add(tok.literal, '\v')
-    inc(c.bufpos)
-  of 't', 'T': 
-    add(tok.literal, '\t')
-    inc(c.bufpos)
-  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': 
-    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'}): 
-      val = val * 10 + ord(c.buf[c.bufpos]) - ord('0')
-      inc(c.bufpos)
-      inc(i)
-    if val > 0 and val <= 255: add(tok.literal, chr(val))
-    else: tok.kind = tkInvalid
-  of '\0'..'\31':
-    tok.kind = tkInvalid
-  elif c.buf[c.bufpos] in strutils.Letters:
-    tok.kind = tkInvalid
-  else:
-    add(tok.literal, c.buf[c.bufpos])
-    inc(c.bufpos)
-  
-proc skip(c: var PegLexer) = 
-  var pos = c.bufpos
-  var buf = c.buf
-  while true: 
-    case buf[pos]
-    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': 
-      pos = handleLF(c, pos)
-      buf = c.buf
-    else: 
-      break                   # EndOfFile also leaves the loop
-  c.bufpos = pos
-  
-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: 
-    case buf[pos]
-    of '\\':
-      c.bufpos = pos
-      getEscapedChar(c, tok)
-      pos = c.bufpos
-    of '\c', '\L', '\0':
-      tok.kind = tkInvalid
-      break
-    elif buf[pos] == quote:
-      inc(pos)
-      break      
-    else:
-      add(tok.literal, buf[pos])
-      inc(pos)
-  c.bufpos = pos
-  
-proc getDollar(c: var PegLexer, tok: var TToken) = 
-  var pos = c.bufpos + 1
-  var buf = c.buf
-  if buf[pos] in {'0'..'9'}:
-    tok.kind = tkBackref
-    tok.index = 0
-    while buf[pos] in {'0'..'9'}:
-      tok.index = tok.index * 10 + ord(buf[pos]) - ord('0')
-      inc(pos)
-  else:
-    tok.kind = tkDollar
-  c.bufpos = pos
-  
-proc getCharSet(c: var PegLexer, tok: var TToken) = 
-  tok.kind = tkCharSet
-  tok.charset = {}
-  var pos = c.bufpos + 1
-  var buf = c.buf
-  var caret = false
-  if buf[pos] == '^':
-    inc(pos)
-    caret = true
-  while true:
-    var ch: char
-    case buf[pos]
-    of ']':
-      inc(pos)
-      break
-    of '\\':
-      c.bufpos = pos
-      getEscapedChar(c, tok)
-      pos = c.bufpos
-      ch = tok.literal[tok.literal.len-1]
-    of '\C', '\L', '\0':
-      tok.kind = tkInvalid
-      break
-    else: 
-      ch = buf[pos]
-      inc(pos)
-    incl(tok.charset, ch)
-    if buf[pos] == '-':
-      if buf[pos+1] == ']':
-        incl(tok.charset, '-')
-        inc(pos)
-      else:
-        inc(pos)
-        var ch2: char
-        case buf[pos]
-        of '\\':
-          c.bufpos = pos
-          getEscapedChar(c, tok)
-          pos = c.bufpos
-          ch2 = tok.literal[tok.literal.len-1]
-        of '\C', '\L', '\0':
-          tok.kind = tkInvalid
-          break
-        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) = 
-  var pos = c.bufpos
-  var buf = c.buf
-  while true: 
-    add(tok.literal, buf[pos])
-    inc(pos)
-    if buf[pos] notin strutils.IdentChars: break
-  c.bufpos = pos
-  tok.kind = tkIdentifier
-
-proc getBuiltin(c: var PegLexer, tok: var TToken) =
-  if c.buf[c.bufpos+1] in strutils.Letters:
-    inc(c.bufpos)
-    getSymbol(c, tok)
-    tok.kind = tkBuiltin
-  else:
-    tok.kind = tkEscaped
-    getEscapedChar(c, tok) # may set tok.kind to tkInvalid
-
-proc getTok(c: var PegLexer, tok: var TToken) = 
-  tok.kind = tkInvalid
-  tok.modifier = modNone
-  setLen(tok.literal, 0)
-  skip(c)
-  case c.buf[c.bufpos]
-  of '{':
-    inc(c.bufpos)
-    if c.buf[c.bufpos] == '@' and c.buf[c.bufpos+1] == '}':
-      tok.kind = tkCurlyAt
-      inc(c.bufpos, 2)
-      add(tok.literal, "{@}")
-    else:
-      tok.kind = tkCurlyLe
-      add(tok.literal, '{')
-  of '}': 
-    tok.kind = tkCurlyRi
-    inc(c.bufpos)
-    add(tok.literal, '}')
-  of '[': 
-    getCharSet(c, tok)
-  of '(':
-    tok.kind = tkParLe
-    inc(c.bufpos)
-    add(tok.literal, '(')
-  of ')':
-    tok.kind = tkParRi
-    inc(c.bufpos)
-    add(tok.literal, ')')
-  of '.': 
-    tok.kind = tkAny
-    inc(c.bufpos)
-    add(tok.literal, '.')
-  of '_':
-    tok.kind = tkAnyRune
-    inc(c.bufpos)
-    add(tok.literal, '_')
-  of '\\': 
-    getBuiltin(c, tok)
-  of '\'', '"': getString(c, tok)
-  of '$': getDollar(c, tok)
-  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 
-        c.buf[c.bufpos] == '$' and c.buf[c.bufpos+1] in {'0'..'9'}:
-      case tok.literal
-      of "i": tok.modifier = modIgnoreCase
-      of "y": tok.modifier = modIgnoreStyle
-      of "v": tok.modifier = modVerbatim
-      else: discard
-      setLen(tok.literal, 0)
-      if c.buf[c.bufpos] == '$':
-        getDollar(c, tok)
-      else:
-        getString(c, tok)
-      if tok.modifier == modNone: tok.kind = tkInvalid
-  of '+':
-    tok.kind = tkPlus
-    inc(c.bufpos)
-    add(tok.literal, '+')
-  of '*':
-    tok.kind = tkStar
-    inc(c.bufpos)
-    add(tok.literal, '+')
-  of '<':
-    if c.buf[c.bufpos+1] == '-':
-      inc(c.bufpos, 2)
-      tok.kind = tkArrow
-      add(tok.literal, "<-")
-    else:
-      add(tok.literal, '<')
-  of '/':
-    tok.kind = tkBar
-    inc(c.bufpos)
-    add(tok.literal, '/')
-  of '?':
-    tok.kind = tkOption
-    inc(c.bufpos)
-    add(tok.literal, '?')
-  of '!':
-    tok.kind = tkNot
-    inc(c.bufpos)
-    add(tok.literal, '!')
-  of '&':
-    tok.kind = tkAmp
-    inc(c.bufpos)
-    add(tok.literal, '!')
-  of '@':
-    tok.kind = tkAt
-    inc(c.bufpos)
-    add(tok.literal, '@')
-    if c.buf[c.bufpos] == '@': 
-      tok.kind = tkCurlyAt
-      inc(c.bufpos)
-      add(tok.literal, '@')
-  of '^':
-    tok.kind = tkHat
-    inc(c.bufpos)
-    add(tok.literal, '^')
-  else:
-    add(tok.literal, c.buf[c.bufpos])
-    inc(c.bufpos)
-
-proc arrowIsNextTok(c: PegLexer): bool =
-  # the only look ahead we need
-  var pos = c.bufpos
-  while c.buf[pos] in {'\t', ' '}: inc(pos)
-  result = c.buf[pos] == '<' and c.buf[pos+1] == '-'
-
-# ----------------------------- parser ----------------------------------------
-    
-type
-  EInvalidPeg* = object of ValueError ## raised if an invalid
-                                         ## PEG has been detected
-  PegParser = object of PegLexer ## the PEG parser object
-    tok: TToken
-    nonterms: seq[PNonTerminal]
-    modifier: TModifier
-    captures: int
-    identIsVerbatim: bool
-    skip: TPeg
-
-proc pegError(p: PegParser, msg: string, line = -1, col = -1) =
-  var e: ref EInvalidPeg
-  new(e)
-  e.msg = errorStr(p, msg, line, col)
-  raise e
-
-proc getTok(p: var PegParser) = 
-  getTok(p, p.tok)
-  if p.tok.kind == tkInvalid: pegError(p, "invalid token")
-
-proc eat(p: var PegParser, kind: TTokKind) =
-  if p.tok.kind == kind: getTok(p)
-  else: pegError(p, tokKindToStr[kind] & " expected")
-
-proc parseExpr(p: var PegParser): TPeg
-
-proc getNonTerminal(p: var PegParser, name: string): PNonTerminal =
-  for i in 0..high(p.nonterms):
-    result = p.nonterms[i]
-    if cmpIgnoreStyle(result.name, name) == 0: return
-  # forward reference:
-  result = newNonTerminal(name, getLine(p), getColumn(p))
-  add(p.nonterms, result)
-
-proc modifiedTerm(s: string, m: TModifier): TPeg =
-  case m
-  of modNone, modVerbatim: result = term(s)
-  of modIgnoreCase: result = termIgnoreCase(s)
-  of modIgnoreStyle: result = termIgnoreStyle(s)
-
-proc modifiedBackref(s: int, m: TModifier): TPeg =
-  case m
-  of modNone, modVerbatim: result = backref(s)
-  of modIgnoreCase: result = backrefIgnoreCase(s)
-  of modIgnoreStyle: result = backrefIgnoreStyle(s)
-
-proc builtin(p: var PegParser): TPeg =
-  # do not use "y", "skip" or "i" as these would be ambiguous
-  case p.tok.literal
-  of "n": result = newLine()
-  of "d": result = charSet({'0'..'9'})
-  of "D": result = charSet({'\1'..'\xff'} - {'0'..'9'})
-  of "s": result = charSet({' ', '\9'..'\13'})
-  of "S": result = charSet({'\1'..'\xff'} - {' ', '\9'..'\13'})
-  of "w": result = charSet({'a'..'z', 'A'..'Z', '_', '0'..'9'})
-  of "W": result = charSet({'\1'..'\xff'} - {'a'..'z','A'..'Z','_','0'..'9'})
-  of "a": result = charSet({'a'..'z', 'A'..'Z'})
-  of "A": result = charSet({'\1'..'\xff'} - {'a'..'z', 'A'..'Z'})
-  of "ident": result = pegs.ident
-  of "letter": result = unicodeLetter()
-  of "upper": result = unicodeUpper()
-  of "lower": result = unicodeLower()
-  of "title": result = unicodeTitle()
-  of "white": result = unicodeWhitespace()
-  else: pegError(p, "unknown built-in: " & p.tok.literal)
-
-proc token(terminal: TPeg, p: PegParser): TPeg = 
-  if p.skip.kind == pkEmpty: result = terminal
-  else: result = sequence(p.skip, terminal)
-
-proc primary(p: var PegParser): TPeg =
-  case p.tok.kind
-  of tkAmp:
-    getTok(p)
-    return &primary(p)
-  of tkNot:
-    getTok(p)
-    return !primary(p)
-  of tkAt:
-    getTok(p)
-    return !*primary(p)
-  of tkCurlyAt:
-    getTok(p)
-    return !*\primary(p).token(p)
-  else: discard
-  case p.tok.kind
-  of tkIdentifier:
-    if p.identIsVerbatim: 
-      var m = p.tok.modifier
-      if m == modNone: m = p.modifier
-      result = modifiedTerm(p.tok.literal, m).token(p)
-      getTok(p)
-    elif not arrowIsNextTok(p):
-      var nt = getNonTerminal(p, p.tok.literal)
-      incl(nt.flags, ntUsed)
-      result = nonterminal(nt).token(p)
-      getTok(p)
-    else:
-      pegError(p, "expression expected, but found: " & p.tok.literal)
-  of tkStringLit:
-    var m = p.tok.modifier
-    if m == modNone: m = p.modifier
-    result = modifiedTerm(p.tok.literal, m).token(p)
-    getTok(p)
-  of tkCharSet:
-    if '\0' in p.tok.charset:
-      pegError(p, "binary zero ('\\0') not allowed in character class")
-    result = charSet(p.tok.charset).token(p)
-    getTok(p)
-  of tkParLe:
-    getTok(p)
-    result = parseExpr(p)
-    eat(p, tkParRi)
-  of tkCurlyLe:
-    getTok(p)
-    result = capture(parseExpr(p)).token(p)
-    eat(p, tkCurlyRi)
-    inc(p.captures)
-  of tkAny:
-    result = any().token(p)
-    getTok(p)
-  of tkAnyRune:
-    result = anyRune().token(p)
-    getTok(p)
-  of tkBuiltin:
-    result = builtin(p).token(p)
-    getTok(p)
-  of tkEscaped:
-    result = term(p.tok.literal[0]).token(p)
-    getTok(p)
-  of tkDollar: 
-    result = endAnchor()
-    getTok(p)
-  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: 
-      pegError(p, "invalid back reference index: " & $p.tok.index)
-    getTok(p)
-  else:
-    pegError(p, "expression expected, but found: " & p.tok.literal)
-    getTok(p) # we must consume a token here to prevent endless loops!
-  while true:
-    case p.tok.kind
-    of tkOption:
-      result = ?result
-      getTok(p)
-    of tkStar:
-      result = *result
-      getTok(p)
-    of tkPlus:
-      result = +result
-      getTok(p)
-    else: break
-
-proc seqExpr(p: var PegParser): TPeg =
-  result = primary(p)
-  while true:
-    case p.tok.kind
-    of tkAmp, tkNot, tkAt, tkStringLit, tkCharSet, tkParLe, tkCurlyLe,
-       tkAny, tkAnyRune, tkBuiltin, tkEscaped, tkDollar, tkBackref, 
-       tkHat, tkCurlyAt:
-      result = sequence(result, primary(p))
-    of tkIdentifier:
-      if not arrowIsNextTok(p):
-        result = sequence(result, primary(p))
-      else: break
-    else: break
-
-proc parseExpr(p: var PegParser): TPeg =
-  result = seqExpr(p)
-  while p.tok.kind == tkBar:
-    getTok(p)
-    result = result / seqExpr(p)
-  
-proc parseRule(p: var PegParser): PNonTerminal =
-  if p.tok.kind == tkIdentifier and arrowIsNextTok(p):
-    result = getNonTerminal(p, p.tok.literal)
-    if ntDeclared in result.flags:
-      pegError(p, "attempt to redefine: " & result.name)
-    result.line = getLine(p)
-    result.col = getColumn(p)
-    getTok(p)
-    eat(p, tkArrow)
-    result.rule = parseExpr(p)
-    incl(result.flags, ntDeclared) # NOW inlining may be attempted
-  else:
-    pegError(p, "rule expected, but found: " & p.tok.literal)
-  
-proc rawParse(p: var PegParser): TPeg =
-  ## parses a rule or a PEG expression
-  while p.tok.kind == tkBuiltin:
-    case p.tok.literal
-    of "i":
-      p.modifier = modIgnoreCase
-      getTok(p)
-    of "y":
-      p.modifier = modIgnoreStyle
-      getTok(p)
-    of "skip":
-      getTok(p)
-      p.skip = ?primary(p)
-    else: break
-  if p.tok.kind == tkIdentifier and arrowIsNextTok(p):
-    result = parseRule(p).rule
-    while p.tok.kind != tkEof:
-      discard parseRule(p)
-  else:
-    p.identIsVerbatim = true
-    result = parseExpr(p)
-  if p.tok.kind != tkEof:
-    pegError(p, "EOF expected, but found: " & p.tok.literal)
-  for i in 0..high(p.nonterms):
-    var nt = p.nonterms[i]
-    if ntDeclared notin nt.flags:
-      pegError(p, "undeclared identifier: " & nt.name, nt.line, nt.col)
-    elif ntUsed notin nt.flags and i > 0:
-      pegError(p, "unused rule: " & nt.name, nt.line, nt.col)
-
-proc parsePeg*(pattern: string, filename = "pattern", line = 1, col = 0): TPeg =
-  ## constructs a Peg object from `pattern`. `filename`, `line`, `col` are
-  ## used for error messages, but they only provide start offsets. `parsePeg`
-  ## keeps track of line and column numbers within `pattern`.
-  var p: PegParser
-  init(PegLexer(p), pattern, filename, line, col)
-  p.tok.kind = tkInvalid
-  p.tok.modifier = modNone
-  p.tok.literal = ""
-  p.tok.charset = {}
-  p.nonterms = @[]
-  p.identIsVerbatim = false
-  getTok(p)
-  result = rawParse(p)
-
-proc peg*(pattern: string): TPeg =
-  ## constructs a Peg object from the `pattern`. The short name has been
-  ## chosen to encourage its use as a raw string modifier::
-  ##
-  ##   peg"{\ident} \s* '=' \s* {.*}"
-  result = parsePeg(pattern, "pattern")
-
-proc escapePeg*(s: string): string =
-  ## escapes `s` so that it is matched verbatim when used as a peg.
-  result = ""
-  var inQuote = false
-  for c in items(s):
-    case c
-    of '\0'..'\31', '\'', '"', '\\':
-      if inQuote:
-        result.add('\'')
-        inQuote = false
-      result.add("\\x")
-      result.add(toHex(ord(c), 2))
-    else:
-      if not inQuote:
-        result.add('\'')
-        inQuote = true
-      result.add(c)
-  if inQuote: result.add('\'')
-
-when isMainModule:
-  assert escapePeg("abc''def'") == r"'abc'\x27\x27'def'\x27"
-  assert match("(a b c)", peg"'(' @ ')'")
-  assert match("W_HI_Le", peg"\y 'while'")
-  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+")
-  assert "ABC".match(peg"\d+ / \w+")
-
-  for word in split("00232this02939is39an22example111", peg"\d+"):
-    writeln(stdout, word)
-
-  assert matchLen("key", ident) == 3
-
-  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)
-  var a = ""
-  for i in 0..c.ml-1:
-    a.add(substr(s, c.matches[i][0], c.matches[i][1]))
-  assert a == "abcdef"
-  #echo expr.rule
-
-  #const filename = "lib/devel/peg/grammar.txt"
-  #var grammar = parsePeg(newFileStream(filename, fmRead), filename)
-  #echo "a <- [abc]*?".match(grammar)
-  assert find("_____abc_______", term("abc"), 2) == 5
-  assert match("_______ana", peg"A <- 'ana' / . A")
-  assert match("abcs%%%", peg"A <- ..A / .A / '%'")
-
-  var matches: array[0..MaxSubpatterns-1, string]
-  if "abc" =~ peg"{'a'}'bc' 'xyz' / {\ident}":
-    assert matches[0] == "abc"
-  else:
-    assert false
-  
-  var g2 = peg"""S <- A B / C D
-                 A <- 'a'+
-                 B <- 'b'+
-                 C <- 'c'+
-                 D <- 'd'+
-              """
-  assert($g2 == "((A B) / (C D))")
-  assert match("cccccdddddd", g2)
-  assert("var1=key; var2=key2".replacef(peg"{\ident}'='{\ident}", "$1<-$2$2") ==
-         "var1<-keykey; var2<-key2key2")
-  assert("var1=key; var2=key2".replace(peg"{\ident}'='{\ident}", "$1<-$2$2") ==
-         "$1<-$2$2; $1<-$2$2")
-  assert "var1=key; var2=key2".endsWith(peg"{\ident}'='{\ident}")
-
-  if "aaaaaa" =~ peg"'aa' !. / ({'a'})+":
-    assert matches[0] == "a"
-  else:
-    assert false
-
-  if match("abcdefg", peg"c {d} ef {g}", matches, 2):
-    assert matches[0] == "d"
-    assert matches[1] == "g"
-  else:
-    assert false
-
-  for x in findAll("abcdef", peg".", 3):
-    echo x
-
-  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*)+")
-  assert match("EINE ÜBERSICHT UND AUSSERDEM", peg"(\upper \white*)+")
-  assert(not match("456678", peg"(\letter)+"))
-
-  assert("var1 = key; var2 = key2".replacef(
-    peg"\skip(\s*) {\ident}'='{\ident}", "$1<-$2$2") ==
-         "var1<-keykey;var2<-key2key2")
-
-  assert match("prefix/start", peg"^start$", 7)
-
diff --git a/lib/pure/strtabs.nim b/lib/pure/strtabs.nim
index 727d5a386..7fdd994f2 100644
--- a/lib/pure/strtabs.nim
+++ b/lib/pure/strtabs.nim
@@ -168,6 +168,12 @@ proc newStringTable*(mode: StringTableMode): StringTableRef {.
   result.counter = 0
   newSeq(result.data, startSize)
 
+proc clear*(s: StringTableRef, mode: StringTableMode) =
+  ## resets a string table to be empty again.
+  s.mode = mode
+  s.counter = 0
+  s.data.setLen(startSize)
+
 proc newStringTable*(keyValuePairs: varargs[string],
                      mode: StringTableMode): StringTableRef {.
   rtl, extern: "nst$1WithPairs".} =
@@ -227,7 +233,7 @@ proc `$`*(t: StringTableRef): string {.rtl, extern: "nstDollar".} =
     result = "{:}"
   else:
     result = "{"
-    for key, val in pairs(t): 
+    for key, val in pairs(t):
       if result.len > 1: result.add(", ")
       result.add(key)
       result.add(": ")
diff --git a/lib/pure/strutils.nim b/lib/pure/strutils.nim
index 1b248126b..59cebf7fa 100644
--- a/lib/pure/strutils.nim
+++ b/lib/pure/strutils.nim
@@ -1410,7 +1410,8 @@ when isMainModule:
   doAssert wordWrap(inp, 10, false) == outp
 
   doAssert formatBiggestFloat(0.00000000001, ffDecimal, 11) == "0.00000000001"
-  doAssert formatBiggestFloat(0.00000000001, ffScientific, 1) == "1.0e-11"
+  doAssert formatBiggestFloat(0.00000000001, ffScientific, 1) in
+                                                   ["1.0e-11", "1.0e-011"]
 
   doAssert "$# $3 $# $#" % ["a", "b", "c"] == "a c b c"
   when not defined(testing):
diff --git a/lib/pure/terminal.nim b/lib/pure/terminal.nim
index a3c5cdcfb..29f700db5 100644
--- a/lib/pure/terminal.nim
+++ b/lib/pure/terminal.nim
@@ -51,12 +51,13 @@ else:
   proc setRaw(fd: FileHandle, time: cint = TCSAFLUSH) =
     var mode: Termios
     discard fd.tcgetattr(addr mode)
-    mode.iflag = mode.iflag and not Tcflag(BRKINT or ICRNL or INPCK or ISTRIP or IXON)
-    mode.oflag = mode.oflag and not Tcflag(OPOST)
-    mode.cflag = (mode.cflag and not Tcflag(CSIZE or PARENB)) or CS8
-    mode.lflag = mode.lflag and not Tcflag(ECHO or ICANON or IEXTEN or ISIG)
-    mode.cc[VMIN] = 1.cuchar
-    mode.cc[VTIME] = 0.cuchar
+    mode.c_iflag = mode.c_iflag and not Tcflag(BRKINT or ICRNL or INPCK or
+      ISTRIP or IXON)
+    mode.c_oflag = mode.c_oflag and not Tcflag(OPOST)
+    mode.c_cflag = (mode.c_cflag and not Tcflag(CSIZE or PARENB)) or CS8
+    mode.c_lflag = mode.c_lflag and not Tcflag(ECHO or ICANON or IEXTEN or ISIG)
+    mode.c_cc[VMIN] = 1.cuchar
+    mode.c_cc[VTIME] = 0.cuchar
     discard fd.tcsetattr(time, addr mode)
 
 proc setCursorPos*(x, y: int) =
diff --git a/lib/pure/times.nim b/lib/pure/times.nim
index c275ede69..5f8835c6a 100644
--- a/lib/pure/times.nim
+++ b/lib/pure/times.nim
@@ -764,7 +764,7 @@ proc parseToken(info: var TimeInfo; token, value: string; j: var int) =
     info.monthday = value[j..j+1].parseInt()
     j += 2
   of "ddd":
-    case value[j..j+2].toLower():
+    case value[j..j+2].toLower()
     of "sun":
       info.weekday = dSun
     of "mon":
@@ -1068,45 +1068,45 @@ when isMainModule:
   var f = "dddd at hh:mmtt on MMM d, yyyy"
   assert($s.parse(f) == "Tue Dec 15 09:04:00 2015")
   # ANSIC       = "Mon Jan _2 15:04:05 2006"
-  s = "Mon Jan 2 15:04:05 2006"
-  f = "ddd MMM d HH:mm:ss yyyy"
-  assert($s.parse(f) == "Mon Jan  2 15:04:05 2006")
+  s = "Thu Jan 12 15:04:05 2006"
+  f = "ddd MMM dd HH:mm:ss yyyy"
+  assert($s.parse(f) == "Thu Jan 12 15:04:05 2006")
   # UnixDate    = "Mon Jan _2 15:04:05 MST 2006"
-  s = "Mon Jan 2 15:04:05 MST 2006"
-  f = "ddd MMM d HH:mm:ss ZZZ yyyy"
-  assert($s.parse(f) == "Mon Jan  2 15:04:05 2006")
+  s = "Thu Jan 12 15:04:05 MST 2006"
+  f = "ddd MMM dd HH:mm:ss ZZZ yyyy"
+  assert($s.parse(f) == "Thu Jan 12 15:04:05 2006")
   # RubyDate    = "Mon Jan 02 15:04:05 -0700 2006"
-  s = "Mon Jan 02 15:04:05 -07:00 2006"
+  s = "Thu Jan 12 15:04:05 -07:00 2006"
   f = "ddd MMM dd HH:mm:ss zzz yyyy"
-  assert($s.parse(f) == "Mon Jan  2 15:04:05 2006")
+  assert($s.parse(f) == "Thu Jan 12 15:04:05 2006")
   # RFC822      = "02 Jan 06 15:04 MST"
-  s = "02 Jan 06 15:04 MST"
+  s = "12 Jan 16 15:04 MST"
   f = "dd MMM yy HH:mm ZZZ"
-  assert($s.parse(f) == "Mon Jan  2 15:04:00 2006")
+  assert($s.parse(f) == "Tue Jan 12 15:04:00 2016")
   # RFC822Z     = "02 Jan 06 15:04 -0700" # RFC822 with numeric zone
-  s = "02 Jan 06 15:04 -07:00"
+  s = "12 Jan 16 15:04 -07:00"
   f = "dd MMM yy HH:mm zzz"
-  assert($s.parse(f) == "Mon Jan  2 15:04:00 2006")
+  assert($s.parse(f) == "Tue Jan 12 15:04:00 2016")
   # RFC850      = "Monday, 02-Jan-06 15:04:05 MST"
-  s = "Monday, 02-Jan-06 15:04:05 MST"
+  s = "Monday, 12-Jan-06 15:04:05 MST"
   f = "dddd, dd-MMM-yy HH:mm:ss ZZZ"
-  assert($s.parse(f) == "Mon Jan  2 15:04:05 2006")
+  assert($s.parse(f) == "Thu Jan 12 15:04:05 2006")
   # RFC1123     = "Mon, 02 Jan 2006 15:04:05 MST"
-  s = "Mon, 02 Jan 2006 15:04:05 MST"
+  s = "Thu, 12 Jan 2006 15:04:05 MST"
   f = "ddd, dd MMM yyyy HH:mm:ss ZZZ"
-  assert($s.parse(f) == "Mon Jan  2 15:04:05 2006")
+  assert($s.parse(f) == "Thu Jan 12 15:04:05 2006")
   # RFC1123Z    = "Mon, 02 Jan 2006 15:04:05 -0700" # RFC1123 with numeric zone
-  s = "Mon, 02 Jan 2006 15:04:05 -07:00"
+  s = "Thu, 12 Jan 2006 15:04:05 -07:00"
   f = "ddd, dd MMM yyyy HH:mm:ss zzz"
-  assert($s.parse(f) == "Mon Jan  2 15:04:05 2006")
+  assert($s.parse(f) == "Thu Jan 12 15:04:05 2006")
   # RFC3339     = "2006-01-02T15:04:05Z07:00"
-  s = "2006-01-02T15:04:05Z-07:00"
+  s = "2006-01-12T15:04:05Z-07:00"
   f = "yyyy-MM-ddTHH:mm:ssZzzz"
-  assert($s.parse(f) == "Mon Jan  2 15:04:05 2006")
+  assert($s.parse(f) == "Thu Jan 12 15:04:05 2006")
   # RFC3339Nano = "2006-01-02T15:04:05.999999999Z07:00"
-  s = "2006-01-02T15:04:05.999999999Z-07:00"
+  s = "2006-01-12T15:04:05.999999999Z-07:00"
   f = "yyyy-MM-ddTHH:mm:ss.999999999Zzzz"
-  assert($s.parse(f) == "Mon Jan  2 15:04:05 2006")
+  assert($s.parse(f) == "Thu Jan 12 15:04:05 2006")
   # Kitchen     = "3:04PM"
   s = "3:04PM"
   f = "h:mmtt"
diff --git a/lib/pure/unicode.nim b/lib/pure/unicode.nim
index 4a9f4631d..5fd3c2418 100644
--- a/lib/pure/unicode.nim
+++ b/lib/pure/unicode.nim
@@ -105,6 +105,31 @@ template fastRuneAt*(s: string, i: int, result: expr, doInc = true) =
     result = Rune(ord(s[i]))
     when doInc: inc(i)
 
+proc validateUtf8*(s: string): int =
+  ## returns the position of the invalid byte in ``s`` if the string ``s`` does
+  ## not hold valid UTF-8 data. Otherwise -1 is returned.
+  var i = 0
+  let L = s.len
+  while i < L:
+    if ord(s[i]) <=% 127:
+      inc(i)
+    elif ord(s[i]) shr 5 == 0b110:
+      if i+1 < L and ord(s[i+1]) shr 6 == 0b10: inc(i, 2)
+      else: return i
+    elif ord(s[i]) shr 4 == 0b1110:
+      if i+2 < L and ord(s[i+1]) shr 6 == 0b10 and ord(s[i+2]) shr 6 == 0b10:
+        inc i, 3
+      else: return i
+    elif ord(s[i]) shr 3 == 0b11110:
+      if i+3 < L and ord(s[i+1]) shr 6 == 0b10 and
+                     ord(s[i+2]) shr 6 == 0b10 and
+                     ord(s[i+3]) shr 6 == 0b10:
+        inc i, 4
+      else: return i
+    else:
+      return i
+  return -1
+
 proc runeAt*(s: string, i: Natural): Rune =
   ## returns the unicode character in `s` at byte index `i`
   fastRuneAt(s, i, result, false)
diff --git a/lib/pure/uri.nim b/lib/pure/uri.nim
index b0afb75f9..1890a9bf4 100644
--- a/lib/pure/uri.nim
+++ b/lib/pure/uri.nim
@@ -53,10 +53,10 @@ proc parseAuthority(authority: string, result: var Uri) =
   while true:
     case authority[i]
     of '@':
-      result.password = result.port
-      result.port = ""
-      result.username = result.hostname
-      result.hostname = ""
+      swap result.password, result.port
+      result.port.setLen(0)
+      swap result.username, result.hostname
+      result.hostname.setLen(0)
       inPort = false
     of ':':
       inPort = true
@@ -75,7 +75,7 @@ proc parsePath(uri: string, i: var int, result: var Uri) =
   # The 'mailto' scheme's PATH actually contains the hostname/username
   if result.scheme.toLower == "mailto":
     parseAuthority(result.path, result)
-    result.path = ""
+    result.path.setLen(0)
 
   if uri[i] == '?':
     i.inc # Skip '?'
@@ -85,13 +85,21 @@ proc parsePath(uri: string, i: var int, result: var Uri) =
     i.inc # Skip '#'
     i.inc parseUntil(uri, result.anchor, {}, i)
 
-proc initUri(): Uri =
+proc initUri*(): Uri =
+  ## Initializes a URI.
   result = Uri(scheme: "", username: "", password: "", hostname: "", port: "",
                 path: "", query: "", anchor: "")
 
-proc parseUri*(uri: string): Uri =
-  ## Parses a URI.
-  result = initUri()
+proc resetUri(uri: var Uri) =
+  for f in uri.fields:
+    when f is string:
+      f.setLen(0)
+    else:
+      f = false
+
+proc parseUri*(uri: string, result: var Uri) =
+  ## Parses a URI. The `result` variable will be cleared before.
+  resetUri(result)
 
   var i = 0
 
@@ -105,7 +113,7 @@ proc parseUri*(uri: string): Uri =
   if uri[i] != ':':
     # Assume this is a reference URI (relative URI)
     i = 0
-    result.scheme = ""
+    result.scheme.setLen(0)
     parsePath(uri, i, result)
     return
   i.inc # Skip ':'
@@ -124,6 +132,11 @@ proc parseUri*(uri: string): Uri =
   # Path
   parsePath(uri, i, result)
 
+proc parseUri*(uri: string): Uri =
+  ## Parses a URI and returns it.
+  result = initUri()
+  parseUri(uri, result)
+
 proc removeDotSegments(path: string): string =
   var collection: seq[string] = @[]
   let endsWithSlash = path[path.len-1] == '/'
diff --git a/lib/system.nim b/lib/system.nim
index 85f1350d7..ca4c81411 100644
--- a/lib/system.nim
+++ b/lib/system.nim
@@ -1532,10 +1532,10 @@ const
   NimMajor*: int = 0
     ## is the major number of Nim's version.
 
-  NimMinor*: int = 10
+  NimMinor*: int = 11
     ## is the minor number of Nim's version.
 
-  NimPatch*: int = 3
+  NimPatch*: int = 2
     ## is the patch number of Nim's version.
 
   NimVersion*: string = $NimMajor & "." & $NimMinor & "." & $NimPatch
diff --git a/lib/system/excpt.nim b/lib/system/excpt.nim
index 1b3471978..189d52f57 100644
--- a/lib/system/excpt.nim
+++ b/lib/system/excpt.nim
@@ -58,7 +58,7 @@ proc pushSafePoint(s: PSafePoint) {.compilerRtl, inl.} =
 proc popSafePoint {.compilerRtl, inl.} =
   excHandler = excHandler.prev
 
-proc pushCurrentException(e: ref Exception) {.compilerRtl, inl.} = 
+proc pushCurrentException(e: ref Exception) {.compilerRtl, inl.} =
   e.parent = currException
   currException = e
 
@@ -69,12 +69,12 @@ proc popCurrentException {.compilerRtl, inl.} =
 const
   nativeStackTraceSupported* = (defined(macosx) or defined(linux)) and
                               not NimStackTrace
-  hasSomeStackTrace = NimStackTrace or 
+  hasSomeStackTrace = NimStackTrace or
     defined(nativeStackTrace) and nativeStackTraceSupported
 
 when defined(nativeStacktrace) and nativeStackTraceSupported:
   type
-    TDl_info {.importc: "Dl_info", header: "<dlfcn.h>", 
+    TDl_info {.importc: "Dl_info", header: "<dlfcn.h>",
                final, pure.} = object
       dli_fname: cstring
       dli_fbase: pointer
@@ -98,7 +98,7 @@ when defined(nativeStacktrace) and nativeStackTraceSupported:
         tempDlInfo: TDl_info
     # This is allowed to be expensive since it only happens during crashes
     # (but this way you don't need manual stack tracing)
-    var size = backtrace(cast[ptr pointer](addr(tempAddresses)), 
+    var size = backtrace(cast[ptr pointer](addr(tempAddresses)),
                          len(tempAddresses))
     var enabled = false
     for i in 0..size-1:
@@ -123,7 +123,7 @@ when defined(nativeStacktrace) and nativeStackTraceSupported:
 when not hasThreadSupport:
   var
     tempFrames: array [0..127, PFrame] # should not be alloc'd on stack
-  
+
 proc auxWriteStackTrace(f: PFrame, s: var string) =
   when hasThreadSupport:
     var
@@ -160,7 +160,7 @@ proc auxWriteStackTrace(f: PFrame, s: var string) =
     inc(i)
     b = b.prev
   for j in countdown(i-1, 0):
-    if tempFrames[j] == nil: 
+    if tempFrames[j] == nil:
       add(s, "(")
       add(s, $skipped)
       add(s, " calls omitted) ...")
@@ -214,41 +214,49 @@ proc raiseExceptionAux(e: ref Exception) =
     if not localRaiseHook(e): return
   if globalRaiseHook != nil:
     if not globalRaiseHook(e): return
-  if excHandler != nil:
-    if not excHandler.hasRaiseAction or excHandler.raiseAction(e):
+  when defined(cpp):
+    if e[] of OutOfMemError:
+      showErrorMessage(e.name)
+      quitOrDebug()
+    else:
       pushCurrentException(e)
-      c_longjmp(excHandler.context, 1)
-  elif e[] of OutOfMemError:
-    showErrorMessage(e.name)
-    quitOrDebug()
+      {.emit: "throw NimException(`e`, `e`->name);".}
   else:
-    when hasSomeStackTrace:
-      var buf = newStringOfCap(2000)
-      if isNil(e.trace): rawWriteStackTrace(buf)
-      else: add(buf, e.trace)
-      add(buf, "Error: unhandled exception: ")
-      if not isNil(e.msg): add(buf, e.msg)
-      add(buf, " [")
-      add(buf, $e.name)
-      add(buf, "]\n")
-      showErrorMessage(buf)
+    if excHandler != nil:
+      if not excHandler.hasRaiseAction or excHandler.raiseAction(e):
+        pushCurrentException(e)
+        c_longjmp(excHandler.context, 1)
+    elif e[] of OutOfMemError:
+      showErrorMessage(e.name)
+      quitOrDebug()
     else:
-      # ugly, but avoids heap allocations :-)
-      template xadd(buf, s, slen: expr) =
-        if L + slen < high(buf):
-          copyMem(addr(buf[L]), cstring(s), slen)
-          inc L, slen
-      template add(buf, s: expr) =
-        xadd(buf, s, s.len)
-      var buf: array [0..2000, char]
-      var L = 0
-      add(buf, "Error: unhandled exception: ")
-      if not isNil(e.msg): add(buf, e.msg)
-      add(buf, " [")
-      xadd(buf, e.name, c_strlen(e.name))
-      add(buf, "]\n")
-      showErrorMessage(buf)
-    quitOrDebug()
+      when hasSomeStackTrace:
+        var buf = newStringOfCap(2000)
+        if isNil(e.trace): rawWriteStackTrace(buf)
+        else: add(buf, e.trace)
+        add(buf, "Error: unhandled exception: ")
+        if not isNil(e.msg): add(buf, e.msg)
+        add(buf, " [")
+        add(buf, $e.name)
+        add(buf, "]\n")
+        showErrorMessage(buf)
+      else:
+        # ugly, but avoids heap allocations :-)
+        template xadd(buf, s, slen: expr) =
+          if L + slen < high(buf):
+            copyMem(addr(buf[L]), cstring(s), slen)
+            inc L, slen
+        template add(buf, s: expr) =
+          xadd(buf, s, s.len)
+        var buf: array [0..2000, char]
+        var L = 0
+        add(buf, "Error: unhandled exception: ")
+        if not isNil(e.msg): add(buf, e.msg)
+        add(buf, " [")
+        xadd(buf, e.name, c_strlen(e.name))
+        add(buf, "]\n")
+        showErrorMessage(buf)
+      quitOrDebug()
 
 proc raiseException(e: ref Exception, ename: cstring) {.compilerRtl.} =
   e.name = ename
@@ -309,7 +317,7 @@ when not defined(noSignalHandler):
   proc signalHandler(sig: cint) {.exportc: "signalHandler", noconv.} =
     template processSignal(s, action: expr) {.immediate,  dirty.} =
       if s == SIGINT: action("SIGINT: Interrupted by Ctrl-C.\n")
-      elif s == SIGSEGV: 
+      elif s == SIGSEGV:
         action("SIGSEGV: Illegal storage access. (Attempt to read from nil?)\n")
       elif s == SIGABRT:
         when defined(endb):
diff --git a/lib/windows/winlean.nim b/lib/windows/winlean.nim
index 584f7cf48..57b79c7de 100644
--- a/lib/windows/winlean.nim
+++ b/lib/windows/winlean.nim
@@ -10,6 +10,8 @@
 ## This module implements a small wrapper for some needed Win API procedures,
 ## so that the Nim compiler does not depend on the huge Windows module.
 
+{.deadCodeElim:on.}
+
 const
   useWinUnicode* = not defined(useWinAnsi)
 
@@ -29,7 +31,7 @@ type
     nLength*: int32
     lpSecurityDescriptor*: pointer
     bInheritHandle*: WINBOOL
-  
+
   TSTARTUPINFO* {.final, pure.} = object
     cb*: int32
     lpReserved*: cstring
@@ -59,7 +61,7 @@ type
   TFILETIME* {.final, pure.} = object ## CANNOT BE int64 BECAUSE OF ALIGNMENT
     dwLowDateTime*: DWORD
     dwHighDateTime*: DWORD
-  
+
   TBY_HANDLE_FILE_INFORMATION* {.final, pure.} = object
     dwFileAttributes*: DWORD
     ftCreationTime*: TFILETIME
@@ -94,26 +96,26 @@ const
   STD_ERROR_HANDLE* = -12'i32
 
   DETACHED_PROCESS* = 8'i32
-  
+
   SW_SHOWNORMAL* = 1'i32
   INVALID_HANDLE_VALUE* = THandle(-1)
-  
+
   CREATE_UNICODE_ENVIRONMENT* = 1024'i32
 
 proc closeHandle*(hObject: THandle): WINBOOL {.stdcall, dynlib: "kernel32",
     importc: "CloseHandle".}
-    
+
 proc readFile*(hFile: THandle, Buffer: pointer, nNumberOfBytesToRead: int32,
                lpNumberOfBytesRead: ptr int32, lpOverlapped: pointer): WINBOOL{.
     stdcall, dynlib: "kernel32", importc: "ReadFile".}
-    
+
 proc writeFile*(hFile: THandle, Buffer: pointer, nNumberOfBytesToWrite: int32,
-                lpNumberOfBytesWritten: ptr int32, 
+                lpNumberOfBytesWritten: ptr int32,
                 lpOverlapped: pointer): WINBOOL{.
     stdcall, dynlib: "kernel32", importc: "WriteFile".}
 
 proc createPipe*(hReadPipe, hWritePipe: var THandle,
-                 lpPipeAttributes: var TSECURITY_ATTRIBUTES, 
+                 lpPipeAttributes: var TSECURITY_ATTRIBUTES,
                  nSize: int32): WINBOOL{.
     stdcall, dynlib: "kernel32", importc: "CreatePipe".}
 
@@ -159,7 +161,7 @@ proc setStdHandle*(nStdHandle: int32, hHandle: THandle): WINBOOL {.stdcall,
 proc flushFileBuffers*(hFile: THandle): WINBOOL {.stdcall, dynlib: "kernel32",
     importc: "FlushFileBuffers".}
 
-proc getLastError*(): int32 {.importc: "GetLastError", 
+proc getLastError*(): int32 {.importc: "GetLastError",
     stdcall, dynlib: "kernel32".}
 
 when useWinUnicode:
@@ -179,7 +181,7 @@ proc localFree*(p: pointer) {.
   importc: "LocalFree", stdcall, dynlib: "kernel32".}
 
 when useWinUnicode:
-  proc getCurrentDirectoryW*(nBufferLength: int32, 
+  proc getCurrentDirectoryW*(nBufferLength: int32,
                              lpBuffer: WideCString): int32 {.
     importc: "GetCurrentDirectoryW", dynlib: "kernel32", stdcall.}
   proc setCurrentDirectoryW*(lpPathName: WideCString): int32 {.
@@ -191,8 +193,8 @@ when useWinUnicode:
   proc setEnvironmentVariableW*(lpName, lpValue: WideCString): int32 {.
     stdcall, dynlib: "kernel32", importc: "SetEnvironmentVariableW".}
 
-  proc getModuleFileNameW*(handle: THandle, buf: WideCString, 
-                           size: int32): int32 {.importc: "GetModuleFileNameW", 
+  proc getModuleFileNameW*(handle: THandle, buf: WideCString,
+                           size: int32): int32 {.importc: "GetModuleFileNameW",
     dynlib: "kernel32", stdcall.}
 else:
   proc getCurrentDirectoryA*(nBufferLength: int32, lpBuffer: cstring): int32 {.
@@ -269,14 +271,14 @@ proc findClose*(hFindFile: THandle) {.stdcall, dynlib: "kernel32",
 
 when useWinUnicode:
   proc getFullPathNameW*(lpFileName: WideCString, nBufferLength: int32,
-                        lpBuffer: WideCString, 
+                        lpBuffer: WideCString,
                         lpFilePart: var WideCString): int32 {.
-                        stdcall, dynlib: "kernel32", 
+                        stdcall, dynlib: "kernel32",
                         importc: "GetFullPathNameW".}
   proc getFileAttributesW*(lpFileName: WideCString): int32 {.
-                          stdcall, dynlib: "kernel32", 
+                          stdcall, dynlib: "kernel32",
                           importc: "GetFileAttributesW".}
-  proc setFileAttributesW*(lpFileName: WideCString, 
+  proc setFileAttributesW*(lpFileName: WideCString,
                            dwFileAttributes: int32): WINBOOL {.
       stdcall, dynlib: "kernel32", importc: "SetFileAttributesW".}
 
@@ -299,12 +301,12 @@ when useWinUnicode:
 else:
   proc getFullPathNameA*(lpFileName: cstring, nBufferLength: int32,
                         lpBuffer: cstring, lpFilePart: var cstring): int32 {.
-                        stdcall, dynlib: "kernel32", 
+                        stdcall, dynlib: "kernel32",
                         importc: "GetFullPathNameA".}
   proc getFileAttributesA*(lpFileName: cstring): int32 {.
-                          stdcall, dynlib: "kernel32", 
+                          stdcall, dynlib: "kernel32",
                           importc: "GetFileAttributesA".}
-  proc setFileAttributesA*(lpFileName: cstring, 
+  proc setFileAttributesA*(lpFileName: cstring,
                            dwFileAttributes: int32): WINBOOL {.
       stdcall, dynlib: "kernel32", importc: "SetFileAttributesA".}
 
@@ -324,10 +326,10 @@ else:
   proc getCommandLineA*(): cstring {.
     importc: "GetCommandLineA", stdcall, dynlib: "kernel32".}
 
-proc rdFileTime*(f: TFILETIME): int64 = 
+proc rdFileTime*(f: TFILETIME): int64 =
   result = ze64(f.dwLowDateTime) or (ze64(f.dwHighDateTime) shl 32)
 
-proc rdFileSize*(f: TWIN32_FIND_DATA): int64 = 
+proc rdFileSize*(f: TWIN32_FIND_DATA): int64 =
   result = ze64(f.nFileSizeLow) or (ze64(f.nFileSizeHigh) shl 32)
 
 proc getSystemTimeAsFileTime*(lpSystemTimeAsFileTime: var TFILETIME) {.
@@ -347,7 +349,7 @@ else:
                      lpParameters, lpDirectory: cstring,
                      nShowCmd: int32): THandle{.
       stdcall, dynlib: "shell32.dll", importc: "ShellExecuteA".}
-  
+
 proc getFileInformationByHandle*(hFile: THandle,
   lpFileInformation: ptr TBY_HANDLE_FILE_INFORMATION): WINBOOL{.
     stdcall, dynlib: "kernel32", importc: "GetFileInformationByHandle".}
@@ -357,12 +359,12 @@ const
   WSASYS_STATUS_LEN* = 128
   FD_SETSIZE* = 64
   MSG_PEEK* = 2
- 
+
   INADDR_ANY* = 0
   INADDR_LOOPBACK* = 0x7F000001
   INADDR_BROADCAST* = -1
   INADDR_NONE* = -1
-  
+
   ws2dll = "Ws2_32.dll"
 
   WSAEWOULDBLOCK* = 10035
@@ -376,31 +378,31 @@ type
 {.deprecated: [TSocketHandle: SocketHandle].}
 
 type
-  WSAData* {.importc: "WSADATA", header: "winsock2.h".} = object 
+  WSAData* {.importc: "WSADATA", header: "winsock2.h".} = object
     wVersion, wHighVersion: int16
     szDescription: array[0..WSADESCRIPTION_LEN, char]
     szSystemStatus: array[0..WSASYS_STATUS_LEN, char]
     iMaxSockets, iMaxUdpDg: int16
     lpVendorInfo: cstring
-    
-  SockAddr* {.importc: "SOCKADDR", header: "winsock2.h".} = object 
+
+  SockAddr* {.importc: "SOCKADDR", header: "winsock2.h".} = object
     sa_family*: int16 # unsigned
     sa_data: array[0..13, char]
 
   InAddr* {.importc: "IN_ADDR", header: "winsock2.h".} = object
     s_addr*: int32  # IP address
-  
-  Sockaddr_in* {.importc: "SOCKADDR_IN", 
+
+  Sockaddr_in* {.importc: "SOCKADDR_IN",
                   header: "winsock2.h".} = object
     sin_family*: int16
     sin_port*: int16 # unsigned
     sin_addr*: InAddr
     sin_zero*: array[0..7, char]
 
-  In6_addr* {.importc: "IN6_ADDR", header: "winsock2.h".} = object 
+  In6_addr* {.importc: "IN6_ADDR", header: "winsock2.h".} = object
     bytes*: array[0..15, char]
 
-  Sockaddr_in6* {.importc: "SOCKADDR_IN6", 
+  Sockaddr_in6* {.importc: "SOCKADDR_IN6",
                    header: "winsock2.h".} = object
     sin6_family*: int16
     sin6_port*: int16 # unsigned
@@ -430,23 +432,23 @@ type
     h_addrtype*: int16
     h_length*: int16
     h_addr_list*: cstringArray
-  
+
   TFdSet* = object
     fd_count*: cint # unsigned
     fd_array*: array[0..FD_SETSIZE-1, SocketHandle]
-    
+
   Timeval* = object
     tv_sec*, tv_usec*: int32
-    
+
   AddrInfo* = object
-    ai_flags*: cint         ## Input flags. 
-    ai_family*: cint        ## Address family of socket. 
-    ai_socktype*: cint      ## Socket type. 
-    ai_protocol*: cint      ## Protocol of socket. 
-    ai_addrlen*: int        ## Length of socket address. 
+    ai_flags*: cint         ## Input flags.
+    ai_family*: cint        ## Address family of socket.
+    ai_socktype*: cint      ## Socket type.
+    ai_protocol*: cint      ## Protocol of socket.
+    ai_addrlen*: int        ## Length of socket address.
     ai_canonname*: cstring  ## Canonical name of service location.
-    ai_addr*: ptr SockAddr ## Socket address of socket. 
-    ai_next*: ptr AddrInfo ## Pointer to next in list. 
+    ai_addr*: ptr SockAddr ## Socket address of socket.
+    ai_next*: ptr AddrInfo ## Pointer to next in list.
 
   SockLen* = cuint
 
@@ -501,7 +503,7 @@ proc bindSocket*(s: SocketHandle, name: ptr SockAddr, namelen: SockLen): cint {.
   stdcall, importc: "bind", dynlib: ws2dll.}
 proc connect*(s: SocketHandle, name: ptr SockAddr, namelen: SockLen): cint {.
   stdcall, importc: "connect", dynlib: ws2dll.}
-proc getsockname*(s: SocketHandle, name: ptr SockAddr, 
+proc getsockname*(s: SocketHandle, name: ptr SockAddr,
                   namelen: ptr SockLen): cint {.
   stdcall, importc: "getsockname", dynlib: ws2dll.}
 proc getsockopt*(s: SocketHandle, level, optname: cint, optval: pointer,
@@ -515,7 +517,7 @@ proc listen*(s: SocketHandle, backlog: cint): cint {.
   stdcall, importc: "listen", dynlib: ws2dll.}
 proc recv*(s: SocketHandle, buf: pointer, len, flags: cint): cint {.
   stdcall, importc: "recv", dynlib: ws2dll.}
-proc recvfrom*(s: SocketHandle, buf: cstring, len, flags: cint, 
+proc recvfrom*(s: SocketHandle, buf: cstring, len, flags: cint,
                fromm: ptr SockAddr, fromlen: ptr SockLen): cint {.
   stdcall, importc: "recvfrom", dynlib: ws2dll.}
 proc select*(nfds: cint, readfds, writefds, exceptfds: ptr TFdSet,
@@ -529,22 +531,22 @@ proc sendto*(s: SocketHandle, buf: pointer, len, flags: cint,
 
 proc shutdown*(s: SocketHandle, how: cint): cint {.
   stdcall, importc: "shutdown", dynlib: ws2dll.}
-  
+
 proc getnameinfo*(a1: ptr SockAddr, a2: SockLen,
                   a3: cstring, a4: SockLen, a5: cstring,
                   a6: SockLen, a7: cint): cint {.
   stdcall, importc: "getnameinfo", dynlib: ws2dll.}
-  
+
 proc inet_addr*(cp: cstring): int32 {.
-  stdcall, importc: "inet_addr", dynlib: ws2dll.} 
+  stdcall, importc: "inet_addr", dynlib: ws2dll.}
 
 proc WSAFDIsSet(s: SocketHandle, set: var TFdSet): bool {.
   stdcall, importc: "__WSAFDIsSet", dynlib: ws2dll, noSideEffect.}
 
-proc FD_ISSET*(socket: SocketHandle, set: var TFdSet): cint = 
+proc FD_ISSET*(socket: SocketHandle, set: var TFdSet): cint =
   result = if WSAFDIsSet(socket, set): 1'i32 else: 0'i32
 
-proc FD_SET*(socket: SocketHandle, s: var TFdSet) = 
+proc FD_SET*(socket: SocketHandle, s: var TFdSet) =
   if s.fd_count < FD_SETSIZE:
     s.fd_array[int(s.fd_count)] = socket
     inc(s.fd_count)
@@ -575,8 +577,8 @@ type
 proc waitForMultipleObjects*(nCount: DWORD, lpHandles: PWOHandleArray,
                              bWaitAll: WINBOOL, dwMilliseconds: DWORD): DWORD{.
     stdcall, dynlib: "kernel32", importc: "WaitForMultipleObjects".}
-    
-    
+
+
 # for memfiles.nim:
 
 const
@@ -586,7 +588,7 @@ const
   FILE_SHARE_READ* = 1'i32
   FILE_SHARE_DELETE* = 4'i32
   FILE_SHARE_WRITE* = 2'i32
- 
+
   CREATE_ALWAYS* = 2'i32
   CREATE_NEW* = 1'i32
   OPEN_EXISTING* = 3'i32
@@ -628,7 +630,7 @@ proc setEndOfFile*(hFile: THandle): WINBOOL {.stdcall, dynlib: "kernel32",
     importc: "SetEndOfFile".}
 
 proc setFilePointer*(hFile: THandle, lDistanceToMove: LONG,
-                     lpDistanceToMoveHigh: ptr LONG, 
+                     lpDistanceToMoveHigh: ptr LONG,
                      dwMoveMethod: DWORD): DWORD {.
     stdcall, dynlib: "kernel32", importc: "SetFilePointer".}
 
@@ -637,14 +639,14 @@ proc getFileSize*(hFile: THandle, lpFileSizeHigh: ptr DWORD): DWORD{.stdcall,
 
 proc mapViewOfFileEx*(hFileMappingObject: THandle, dwDesiredAccess: DWORD,
                       dwFileOffsetHigh, dwFileOffsetLow: DWORD,
-                      dwNumberOfBytesToMap: DWORD, 
+                      dwNumberOfBytesToMap: DWORD,
                       lpBaseAddress: pointer): pointer{.
     stdcall, dynlib: "kernel32", importc: "MapViewOfFileEx".}
 
 proc createFileMappingW*(hFile: THandle,
                        lpFileMappingAttributes: pointer,
                        flProtect, dwMaximumSizeHigh: DWORD,
-                       dwMaximumSizeLow: DWORD, 
+                       dwMaximumSizeLow: DWORD,
                        lpName: pointer): THandle {.
   stdcall, dynlib: "kernel32", importc: "CreateFileMappingW".}
 
@@ -702,7 +704,7 @@ proc getOverlappedResult*(hFile: THandle, lpOverlapped: TOVERLAPPED,
               lpNumberOfBytesTransferred: var DWORD, bWait: WINBOOL): WINBOOL{.
     stdcall, dynlib: "kernel32", importc: "GetOverlappedResult".}
 
-const 
+const
  IOC_OUT* = 0x40000000
  IOC_IN*  = 0x80000000
  IOC_WS2* = 0x08000000
@@ -725,7 +727,7 @@ var
 proc WSAIoctl*(s: SocketHandle, dwIoControlCode: DWORD, lpvInBuffer: pointer,
   cbInBuffer: DWORD, lpvOutBuffer: pointer, cbOutBuffer: DWORD,
   lpcbBytesReturned: PDWORD, lpOverlapped: POVERLAPPED,
-  lpCompletionRoutine: POVERLAPPED_COMPLETION_ROUTINE): cint 
+  lpCompletionRoutine: POVERLAPPED_COMPLETION_ROUTINE): cint
   {.stdcall, importc: "WSAIoctl", dynlib: "Ws2_32.dll".}
 
 type
@@ -746,7 +748,7 @@ proc WSASend*(s: SocketHandle, buf: ptr TWSABuf, bufCount: DWORD,
 proc get_osfhandle*(fd:FileHandle): THandle {.
   importc: "_get_osfhandle", header:"<io.h>".}
 
-proc getSystemTimes*(lpIdleTime, lpKernelTime, 
+proc getSystemTimes*(lpIdleTime, lpKernelTime,
                      lpUserTime: var TFILETIME): WINBOOL {.stdcall,
   dynlib: "kernel32", importc: "GetSystemTimes".}
 
diff --git a/tests/ccgbugs/tpartialcs.nim b/tests/ccgbugs/tpartialcs.nim
new file mode 100644
index 000000000..12ff65c37
--- /dev/null
+++ b/tests/ccgbugs/tpartialcs.nim
@@ -0,0 +1,20 @@
+
+# bug #2551
+
+type Tup = tuple
+  A, a: int
+
+type Obj = object
+  A, a: int
+
+var x: Tup # This works.
+var y: Obj # This doesn't.
+
+# bug #2212
+
+proc f() =
+  let
+    p = 1.0
+    P = 0.25 + 0.5
+
+f()
diff --git a/tests/collections/tcounttable.nim b/tests/collections/tcounttable.nim
new file mode 100644
index 000000000..ebbb1c8e5
--- /dev/null
+++ b/tests/collections/tcounttable.nim
@@ -0,0 +1,19 @@
+discard """
+  output: "And we get here"
+"""
+
+# bug #2625
+
+const s_len = 32
+
+import tables
+var substr_counts: CountTable[string] = initCountTable[string]()
+var my_string = "Hello, this is sadly broken for strings over 64 characters. Note that it *does* appear to work for short strings."
+for i in 0..(my_string.len - s_len):
+  let s = my_string[i..i+s_len-1]
+  substr_counts[s] = 1
+  # substr_counts[s] = substr_counts[s] + 1  # Also breaks, + 2 as well, etc.
+  # substr_counts.inc(s)  # This works
+  #echo "Iteration ", i
+
+echo "And we get here"
diff --git a/tests/cpp/tcppraise.nim b/tests/cpp/tcppraise.nim
new file mode 100644
index 000000000..a9ea8e6ce
--- /dev/null
+++ b/tests/cpp/tcppraise.nim
@@ -0,0 +1,17 @@
+discard """
+  cmd: "nim cpp $file"
+  output: '''foo
+bar
+Need odd and >= 3 digits##
+baz'''
+"""
+
+# bug #1888
+echo "foo"
+try:
+  echo "bar"
+  raise newException(ValueError, "Need odd and >= 3 digits")
+#  echo "baz"
+except ValueError:
+  echo getCurrentExceptionMsg(), "##"
+echo "baz"
diff --git a/tests/distinct/tdistinct_consts.nim b/tests/distinct/tdistinct_consts.nim
new file mode 100644
index 000000000..4f6ced2d2
--- /dev/null
+++ b/tests/distinct/tdistinct_consts.nim
@@ -0,0 +1,20 @@
+
+# bug #2641
+
+type MyChar = distinct char
+const c:MyChar = MyChar('a')
+
+type MyBool = distinct bool
+const b:MyBool = MyBool(true)
+
+type MyBoolSet = distinct set[bool]
+const bs:MyBoolSet = MyBoolSet({true})
+
+type MyCharSet= distinct set[char]
+const cs:MyCharSet = MyCharSet({'a'})
+
+type MyBoolSeq = distinct seq[bool]
+const bseq:MyBoolSeq = MyBoolSeq(@[true, false])
+
+type MyBoolArr = distinct array[3, bool]
+const barr:MyBoolArr = MyBoolArr([true, false, true])
diff --git a/tests/exception/texceptionbreak.nim b/tests/exception/texceptionbreak.nim
index 76e986787..00dd8ed9f 100644
--- a/tests/exception/texceptionbreak.nim
+++ b/tests/exception/texceptionbreak.nim
@@ -5,20 +5,20 @@ discard """
 
 # First variety
 try:
-  raise newException(EOS, "Problem")
-except EOS:
+  raise newException(OSError, "Problem")
+except OSError:
   for y in [1, 2, 3]:
     discard
   try:
     discard
-  except EOS:
+  except OSError:
     discard
 echo "1"
 
 # Second Variety
 try:
-  raise newException(EOS, "Problem")
-except EOS:
+  raise newException(OSError, "Problem")
+except OSError:
   for y in [1, 2, 3]:
     discard
   for y in [1, 2, 3]:
@@ -28,8 +28,8 @@ echo "2"
 
 # Third Variety
 try:
-  raise newException(EOS, "Problem")
-except EOS:
+  raise newException(OSError, "Problem")
+except OSError:
   block:
     break
 
@@ -38,8 +38,8 @@ echo "3"
 # Fourth Variety
 block:
   try:
-    raise newException(EOS, "Problem")
-  except EOS:
+    raise newException(OSError, "Problem")
+  except OSError:
     break
 
-echo "4"
\ No newline at end of file
+echo "4"
diff --git a/tests/exception/texcsub.nim b/tests/exception/texcsub.nim
index 3dba357f9..02125d2c0 100644
--- a/tests/exception/texcsub.nim
+++ b/tests/exception/texcsub.nim
@@ -5,12 +5,12 @@ discard """
 # Test inheritance for exception matching:
 
 try:
-  raise newException(EOS, "dummy message")
-except E_Base:
+  raise newException(OSError, "dummy message")
+except Exception:
   echo "caught!"
-except: 
+except:
   echo "wtf!?"
-  
+
 #OUT caught!
 
 
diff --git a/tests/exception/tfinally4.nim b/tests/exception/tfinally4.nim
index 05c57c4f5..3aa707ff6 100644
--- a/tests/exception/tfinally4.nim
+++ b/tests/exception/tfinally4.nim
@@ -8,19 +8,19 @@ discard """
 var raiseEx = true
 var returnA = true
 var returnB = false
- 
-proc main: int = 
+
+proc main: int =
   try: #A
     try: #B
       if raiseEx:
-        raise newException(EOS, "")
+        raise newException(OSError, "")
       return 3
     finally: #B
       echo "B1"
       if returnB:
         return 2
       echo "B2"
-  except EOS: #A
+  except OSError: #A
     echo "catch"
   finally: #A
     echo "A1"
diff --git a/tests/exception/tnestedreturn.nim b/tests/exception/tnestedreturn.nim
index 591638f0e..1480764f1 100644
--- a/tests/exception/tnestedreturn.nim
+++ b/tests/exception/tnestedreturn.nim
@@ -7,7 +7,7 @@ discard """
 
 proc test1() =
 
-  finally: echo "A"
+  defer: echo "A"
 
   try:
     raise newException(OSError, "Problem")
@@ -19,7 +19,7 @@ test1()
 
 proc test2() =
 
-  finally: echo "B"
+  defer: echo "B"
 
   try:
     return
diff --git a/tests/exception/tonraise.nim b/tests/exception/tonraise.nim
index 1a555dd94..a155f0b8e 100644
--- a/tests/exception/tonraise.nim
+++ b/tests/exception/tonraise.nim
@@ -4,8 +4,8 @@ success'''
 """
 
 type
-  ESomething = object of E_Base
-  ESomeOtherErr = object of E_Base
+  ESomething = object of Exception
+  ESomeOtherErr = object of Exception
 
 proc genErrors(s: string) =
   if s == "error!":
@@ -17,14 +17,14 @@ proc foo() =
   var i = 0
   try:
     inc i
-    onRaise(proc (e: ref E_Base): bool =
+    onRaise(proc (e: ref Exception): bool =
       echo "i: ", i)
     genErrors("errssor!")
   except ESomething:
     echo("ESomething happened")
   except:
     echo("Some other error happened")
-    
+
   # test that raise handler is gone:
   try:
     genErrors("error!")
diff --git a/tests/macros/treturnsempty.nim b/tests/macros/treturnsempty.nim
new file mode 100644
index 000000000..7af26a747
--- /dev/null
+++ b/tests/macros/treturnsempty.nim
@@ -0,0 +1,12 @@
+discard """
+  errormsg: "type mismatch"
+  line: 11
+"""
+# bug #2372
+macro foo(dummy: int): stmt =
+  discard
+
+proc takeStr(s: string) = echo s
+
+takeStr foo(12)
+
diff --git a/tests/overload/tspec.nim b/tests/overload/tspec.nim
index 685df503a..f2002a390 100644
--- a/tests/overload/tspec.nim
+++ b/tests/overload/tspec.nim
@@ -11,7 +11,10 @@ ref T
 123
 2
 1
-@[123, 2, 1]'''
+@[123, 2, 1]
+Called!
+merge with var
+merge no var'''
 """
 
 # Things that's even in the spec now!
@@ -79,3 +82,37 @@ proc takeV[T](a: varargs[T]) =
 
 takeV([123, 2, 1]) # takeV's T is "int", not "array of int"
 echo(@[123, 2, 1])
+
+# bug #2600
+
+type
+  FutureBase* = ref object of RootObj ## Untyped future.
+
+  Future*[T] = ref object of FutureBase ## Typed future.
+    value: T ## Stored value
+
+  FutureVar*[T] = distinct Future[T]
+
+proc newFuture*[T](): Future[T] =
+  new(result)
+
+proc newFutureVar*[T](): FutureVar[T] =
+  result = FutureVar[T](newFuture[T]())
+
+proc mget*[T](future: FutureVar[T]): var T =
+  Future[T](future).value
+
+proc reset*[T](future: FutureVar[T]) =
+  echo "Called!"
+
+proc merge[T](x: Future[T]) = echo "merge no var"
+proc merge[T](x: var Future[T]) = echo "merge with var"
+
+when true:
+  var foo = newFutureVar[string]()
+  foo.mget() = ""
+  foo.mget.add("Foobar")
+  foo.reset()
+  var bar = newFuture[int]()
+  bar.merge # merge with var
+  merge(newFuture[int]()) # merge no var
diff --git a/tests/sets/tsets.nim b/tests/sets/tsets.nim
index e370209ed..646175329 100644
--- a/tests/sets/tsets.nim
+++ b/tests/sets/tsets.nim
@@ -1,6 +1,7 @@
 discard """

   file: "tsets.nim"

-  output: "Ha ein F ist in s!"

+  output: '''Ha ein F ist in s!

+false'''

 """

 # Test the handling of sets

 

@@ -15,30 +16,30 @@ type
   TAZ = range['a'..'z']

   TAZset = set[TAZ]

 

-  TTokType* = enum 

+  TTokType* = enum

     tkInvalid, tkEof,

     tkSymbol,

-    tkAddr, tkAnd, tkAs, tkAsm, tkBlock, tkBreak, tkCase, tkCast, tkConst, 

-    tkContinue, tkConverter, tkDiscard, tkDiv, tkElif, tkElse, tkEnd, tkEnum, 

-    tkExcept, tkException, tkFinally, tkFor, tkFrom, tkGeneric, tkIf, tkImplies, 

-    tkImport, tkIn, tkInclude, tkIs, tkIsnot, tkIterator, tkLambda, tkMacro, 

-    tkMethod, tkMod, tkNil, tkNot, tkNotin, tkObject, tkOf, tkOr, tkOut, tkProc, 

-    tkPtr, tkRaise, tkRecord, tkRef, tkReturn, tkShl, tkShr, tkTemplate, tkTry, 

+    tkAddr, tkAnd, tkAs, tkAsm, tkBlock, tkBreak, tkCase, tkCast, tkConst,

+    tkContinue, tkConverter, tkDiscard, tkDiv, tkElif, tkElse, tkEnd, tkEnum,

+    tkExcept, tkException, tkFinally, tkFor, tkFrom, tkGeneric, tkIf, tkImplies,

+    tkImport, tkIn, tkInclude, tkIs, tkIsnot, tkIterator, tkLambda, tkMacro,

+    tkMethod, tkMod, tkNil, tkNot, tkNotin, tkObject, tkOf, tkOr, tkOut, tkProc,

+    tkPtr, tkRaise, tkRecord, tkRef, tkReturn, tkShl, tkShr, tkTemplate, tkTry,

     tkType, tkVar, tkWhen, tkWhere, tkWhile, tkWith, tkWithout, tkXor, tkYield,

-    tkIntLit, tkInt8Lit, tkInt16Lit, tkInt32Lit, tkInt64Lit, tkFloatLit, 

-    tkFloat32Lit, tkFloat64Lit, tkStrLit, tkRStrLit, tkTripleStrLit, tkCharLit, 

-    tkRCharLit, tkParLe, tkParRi, tkBracketLe, tkBracketRi, tkCurlyLe, 

-    tkCurlyRi, tkBracketDotLe, tkBracketDotRi, 

-    tkCurlyDotLe, tkCurlyDotRi, 

+    tkIntLit, tkInt8Lit, tkInt16Lit, tkInt32Lit, tkInt64Lit, tkFloatLit,

+    tkFloat32Lit, tkFloat64Lit, tkStrLit, tkRStrLit, tkTripleStrLit, tkCharLit,

+    tkRCharLit, tkParLe, tkParRi, tkBracketLe, tkBracketRi, tkCurlyLe,

+    tkCurlyRi, tkBracketDotLe, tkBracketDotRi,

+    tkCurlyDotLe, tkCurlyDotRi,

     tkParDotLe, tkParDotRi,

-    tkComma, tkSemiColon, tkColon, tkEquals, tkDot, tkDotDot, tkHat, tkOpr, 

+    tkComma, tkSemiColon, tkColon, tkEquals, tkDot, tkDotDot, tkHat, tkOpr,

     tkComment, tkAccent, tkInd, tkSad, tkDed,

     tkSpaces, tkInfixOpr, tkPrefixOpr, tkPostfixOpr

   TTokTypeRange = range[tkSymbol..tkDed]

   TTokTypes* = set[TTokTypeRange]

 

 const

-  toktypes: TTokTypes = {TTokTypeRange(tkSymbol)..pred(tkIntLit), 

+  toktypes: TTokTypes = {TTokTypeRange(tkSymbol)..pred(tkIntLit),

                          tkStrLit..tkTripleStrLit}

 

 var

@@ -62,3 +63,142 @@ for x in low(TTokTypeRange) .. high(TTokTypeRange):
 #OUT Ha ein F ist in s!

 

 

+type

+  TMsgKind* = enum

+    errUnknown, errIllFormedAstX, errInternal, errCannotOpenFile, errGenerated,

+    errXCompilerDoesNotSupportCpp, errStringLiteralExpected,

+    errIntLiteralExpected, errInvalidCharacterConstant,

+    errClosingTripleQuoteExpected, errClosingQuoteExpected,

+    errTabulatorsAreNotAllowed, errInvalidToken, errLineTooLong,

+    errInvalidNumber, errNumberOutOfRange, errNnotAllowedInCharacter,

+    errClosingBracketExpected, errMissingFinalQuote, errIdentifierExpected,

+    errNewlineExpected,

+    errInvalidModuleName,

+    errOperatorExpected, errTokenExpected, errStringAfterIncludeExpected,

+    errRecursiveDependencyX, errOnOrOffExpected, errNoneSpeedOrSizeExpected,

+    errInvalidPragma, errUnknownPragma, errInvalidDirectiveX,

+    errAtPopWithoutPush, errEmptyAsm, errInvalidIndentation,

+    errExceptionExpected, errExceptionAlreadyHandled,

+    errYieldNotAllowedHere, errYieldNotAllowedInTryStmt,

+    errInvalidNumberOfYieldExpr, errCannotReturnExpr, errAttemptToRedefine,

+    errStmtInvalidAfterReturn, errStmtExpected, errInvalidLabel,

+    errInvalidCmdLineOption, errCmdLineArgExpected, errCmdLineNoArgExpected,

+    errInvalidVarSubstitution, errUnknownVar, errUnknownCcompiler,

+    errOnOrOffExpectedButXFound, errNoneBoehmRefcExpectedButXFound,

+    errNoneSpeedOrSizeExpectedButXFound, errGuiConsoleOrLibExpectedButXFound,

+    errUnknownOS, errUnknownCPU, errGenOutExpectedButXFound,

+    errArgsNeedRunOption, errInvalidMultipleAsgn, errColonOrEqualsExpected,

+    errExprExpected, errUndeclaredIdentifier, errUseQualifier, errTypeExpected,

+    errSystemNeeds, errExecutionOfProgramFailed, errNotOverloadable,

+    errInvalidArgForX, errStmtHasNoEffect, errXExpectsTypeOrValue,

+    errXExpectsArrayType, errIteratorCannotBeInstantiated, errExprXAmbiguous,

+    errConstantDivisionByZero, errOrdinalTypeExpected,

+    errOrdinalOrFloatTypeExpected, errOverOrUnderflow,

+    errCannotEvalXBecauseIncompletelyDefined, errChrExpectsRange0_255,

+    errDynlibRequiresExportc, errUndeclaredFieldX, errNilAccess,

+    errIndexOutOfBounds, errIndexTypesDoNotMatch, errBracketsInvalidForType,

+    errValueOutOfSetBounds, errFieldInitTwice, errFieldNotInit,

+    errExprXCannotBeCalled, errExprHasNoType, errExprXHasNoType,

+    errCastNotInSafeMode, errExprCannotBeCastedToX, errCommaOrParRiExpected,

+    errCurlyLeOrParLeExpected, errSectionExpected, errRangeExpected,

+    errMagicOnlyInSystem, errPowerOfTwoExpected,

+    errStringMayNotBeEmpty, errCallConvExpected, errProcOnlyOneCallConv,

+    errSymbolMustBeImported, errExprMustBeBool, errConstExprExpected,

+    errDuplicateCaseLabel, errRangeIsEmpty, errSelectorMustBeOfCertainTypes,

+    errSelectorMustBeOrdinal, errOrdXMustNotBeNegative, errLenXinvalid,

+    errWrongNumberOfVariables, errExprCannotBeRaised, errBreakOnlyInLoop,

+    errTypeXhasUnknownSize, errConstNeedsConstExpr, errConstNeedsValue,

+    errResultCannotBeOpenArray, errSizeTooBig, errSetTooBig,

+    errBaseTypeMustBeOrdinal, errInheritanceOnlyWithNonFinalObjects,

+    errInheritanceOnlyWithEnums, errIllegalRecursionInTypeX,

+    errCannotInstantiateX, errExprHasNoAddress, errXStackEscape,

+    errVarForOutParamNeeded,

+    errPureTypeMismatch, errTypeMismatch, errButExpected, errButExpectedX,

+    errAmbiguousCallXYZ, errWrongNumberOfArguments,

+    errXCannotBePassedToProcVar,

+    errXCannotBeInParamDecl, errPragmaOnlyInHeaderOfProc, errImplOfXNotAllowed,

+    errImplOfXexpected, errNoSymbolToBorrowFromFound, errDiscardValueX,

+    errInvalidDiscard, errIllegalConvFromXtoY, errCannotBindXTwice,

+    errInvalidOrderInArrayConstructor,

+    errInvalidOrderInEnumX, errEnumXHasHoles, errExceptExpected, errInvalidTry,

+    errOptionExpected, errXisNoLabel, errNotAllCasesCovered,

+    errUnknownSubstitionVar, errComplexStmtRequiresInd, errXisNotCallable,

+    errNoPragmasAllowedForX, errNoGenericParamsAllowedForX,

+    errInvalidParamKindX, errDefaultArgumentInvalid, errNamedParamHasToBeIdent,

+    errNoReturnTypeForX, errConvNeedsOneArg, errInvalidPragmaX,

+    errXNotAllowedHere, errInvalidControlFlowX,

+    errXisNoType, errCircumNeedsPointer, errInvalidExpression,

+    errInvalidExpressionX, errEnumHasNoValueX, errNamedExprExpected,

+    errNamedExprNotAllowed, errXExpectsOneTypeParam,

+    errArrayExpectsTwoTypeParams, errInvalidVisibilityX, errInitHereNotAllowed,

+    errXCannotBeAssignedTo, errIteratorNotAllowed, errXNeedsReturnType,

+    errNoReturnTypeDeclared,

+    errInvalidCommandX, errXOnlyAtModuleScope,

+    errXNeedsParamObjectType,

+    errTemplateInstantiationTooNested, errInstantiationFrom,

+    errInvalidIndexValueForTuple, errCommandExpectsFilename,

+    errMainModuleMustBeSpecified,

+    errXExpected,

+    errTIsNotAConcreteType,

+    errInvalidSectionStart, errGridTableNotImplemented, errGeneralParseError,

+    errNewSectionExpected, errWhitespaceExpected, errXisNoValidIndexFile,

+    errCannotRenderX, errVarVarTypeNotAllowed, errInstantiateXExplicitly,

+    errOnlyACallOpCanBeDelegator, errUsingNoSymbol,

+    errMacroBodyDependsOnGenericTypes,

+    errDestructorNotGenericEnough,

+    errInlineIteratorsAsProcParams,

+    errXExpectsTwoArguments,

+    errXExpectsObjectTypes, errXcanNeverBeOfThisSubtype, errTooManyIterations,

+    errCannotInterpretNodeX, errFieldXNotFound, errInvalidConversionFromTypeX,

+    errAssertionFailed, errCannotGenerateCodeForX, errXRequiresOneArgument,

+    errUnhandledExceptionX, errCyclicTree, errXisNoMacroOrTemplate,

+    errXhasSideEffects, errIteratorExpected, errLetNeedsInit,

+    errThreadvarCannotInit, errWrongSymbolX, errIllegalCaptureX,

+    errXCannotBeClosure, errXMustBeCompileTime,

+    errCannotInferTypeOfTheLiteral,

+    errCannotInferReturnType,

+    errGenericLambdaNotAllowed,

+    errCompilerDoesntSupportTarget,

+    errUser,

+    warnCannotOpenFile,

+    warnOctalEscape, warnXIsNeverRead, warnXmightNotBeenInit,

+    warnDeprecated, warnConfigDeprecated,

+    warnSmallLshouldNotBeUsed, warnUnknownMagic, warnRedefinitionOfLabel,

+    warnUnknownSubstitutionX, warnLanguageXNotSupported,

+    warnFieldXNotSupported, warnCommentXIgnored,

+    warnNilStatement, warnTypelessParam,

+    warnDifferentHeaps, warnWriteToForeignHeap, warnUnsafeCode,

+    warnEachIdentIsTuple, warnShadowIdent,

+    warnProveInit, warnProveField, warnProveIndex, warnGcUnsafe, warnGcUnsafe2,

+    warnUninit, warnGcMem, warnDestructor, warnLockLevel, warnResultShadowed,

+    warnUser,

+    hintSuccess, hintSuccessX,

+    hintLineTooLong, hintXDeclaredButNotUsed, hintConvToBaseNotNeeded,

+    hintConvFromXtoItselfNotNeeded, hintExprAlwaysX, hintQuitCalled,

+    hintProcessing, hintCodeBegin, hintCodeEnd, hintConf, hintPath,

+    hintConditionAlwaysTrue, hintName, hintPattern,

+    hintUser

+

+const

+  fatalMin* = errUnknown

+  fatalMax* = errInternal

+  errMin* = errUnknown

+  errMax* = errUser

+  warnMin* = warnCannotOpenFile

+  warnMax* = pred(hintSuccess)

+  hintMin* = hintSuccess

+  hintMax* = high(TMsgKind)

+

+type

+  TNoteKind* = range[warnMin..hintMax] # "notes" are warnings or hints

+  TNoteKinds* = set[TNoteKind]

+

+var

+  gNotes*: TNoteKinds = {low(TNoteKind)..high(TNoteKind)} -

+                        {warnShadowIdent, warnUninit,

+                         warnProveField, warnProveIndex, warnGcUnsafe}

+

+

+#import compiler.msgs

+

+echo warnUninit in gNotes

diff --git a/tests/stdlib/tdialogs.nim b/tests/stdlib/tdialogs.nim
deleted file mode 100644
index f0203d319..000000000
--- a/tests/stdlib/tdialogs.nim
+++ /dev/null
@@ -1,17 +0,0 @@
-# Test the dialogs module
-
-import dialogs, gtk2
-
-gtk2.nimrod_init()
-
-var x = chooseFilesToOpen(nil)
-for a in items(x):
-  writeln(stdout, a)
-
-info(nil, "start with an info box")
-warning(nil, "now a warning ...")
-error(nil, "... and an error!")
-
-writeln(stdout, chooseFileToOpen(nil))
-writeln(stdout, chooseFileToSave(nil))
-writeln(stdout, chooseDir(nil))
diff --git a/tests/template/tdefault_nil.nim b/tests/template/tdefault_nil.nim
new file mode 100644
index 000000000..891166306
--- /dev/null
+++ b/tests/template/tdefault_nil.nim
@@ -0,0 +1,14 @@
+
+# bug #2629
+import sequtils, os
+
+template glob_rst(basedir: string = nil): expr =
+  if baseDir.isNil:
+    to_seq(walk_files("*.rst"))
+  else:
+    to_seq(walk_files(basedir/"*.rst"))
+
+let
+  rst_files = concat(glob_rst(), glob_rst("docs"))
+
+when isMainModule: echo rst_files
diff --git a/tests/testament/categories.nim b/tests/testament/categories.nim
index 4476fccf2..07a2421a6 100644
--- a/tests/testament/categories.nim
+++ b/tests/testament/categories.nim
@@ -226,7 +226,7 @@ proc testStdlib(r: var TResults, pattern, options: string, cat: Category) =
   for test in os.walkFiles(pattern):
     let contents = readFile(test).string
     if contents.contains("when isMainModule"):
-      testSpec r, makeTest(test, options, cat, actionRun)
+      testSpec r, makeTest(test, options, cat, actionRunNoSpec)
     else:
       testNoSpec r, makeTest(test, options, cat, actionCompile)
 
diff --git a/tests/testament/specs.nim b/tests/testament/specs.nim
index 8bf1a4ad7..9306bf025 100644
--- a/tests/testament/specs.nim
+++ b/tests/testament/specs.nim
@@ -10,13 +10,14 @@
 import parseutils, strutils, os, osproc, streams, parsecfg
 
 const
-  cmdTemplate* = r"nim $target --hints:on $options $file"
+  cmdTemplate* = r"nim $target --hints:on -d:testing $options $file"
 
 type
   TTestAction* = enum
     actionCompile = "compile"
     actionRun = "run"
     actionReject = "reject"
+    actionRunNoSpec = "runNoSpec"
   TResultEnum* = enum
     reNimcCrash,     # nim compiler seems to have crashed
     reMsgsDiffer,       # error messages differ
@@ -78,7 +79,7 @@ proc extractSpec(filename: string): string =
 when not defined(nimhygiene):
   {.pragma: inject.}
 
-template parseSpecAux(fillResult: stmt) {.immediate.} =
+template parseSpecAux(fillResult: untyped) =
   var ss = newStringStream(extractSpec(filename))
   var p {.inject.}: CfgParser
   open(p, ss, filename, 1)
@@ -92,8 +93,7 @@ template parseSpecAux(fillResult: stmt) {.immediate.} =
       fillResult
   close(p)
 
-proc parseSpec*(filename: string): TSpec =
-  result.file = filename
+proc specDefaults*(result: var TSpec) =
   result.msg = ""
   result.outp = ""
   result.nimout = ""
@@ -101,6 +101,10 @@ proc parseSpec*(filename: string): TSpec =
   result.cmd = cmdTemplate
   result.line = 0
   result.column = 0
+
+proc parseSpec*(filename: string): TSpec =
+  specDefaults(result)
+  result.file = filename
   parseSpecAux:
     case normalize(e.key)
     of "action":
@@ -112,7 +116,7 @@ proc parseSpec*(filename: string): TSpec =
     of "file": result.file = e.value
     of "line": discard parseInt(e.value, result.line)
     of "column": discard parseInt(e.value, result.column)
-    of "output": 
+    of "output":
       result.action = actionRun
       result.outp = e.value
     of "outputsub":
@@ -121,7 +125,7 @@ proc parseSpec*(filename: string): TSpec =
       result.substr = true
     of "sortoutput":
       result.sortoutput = parseCfgBool(e.value)
-    of "exitcode": 
+    of "exitcode":
       discard parseInt(e.value, result.exitCode)
     of "msg":
       result.msg = e.value
diff --git a/tests/testament/tester.nim b/tests/testament/tester.nim
index ed39109ad..b3e65959a 100644
--- a/tests/testament/tester.nim
+++ b/tests/testament/tester.nim
@@ -196,7 +196,12 @@ proc testSpec(r: var TResults, test: TTest) =
   let tname = test.name.addFileExt(".nim")
   inc(r.total)
   styledEcho "Processing ", fgCyan, extractFilename(tname)
-  var expected = parseSpec(tname)
+  var expected: TSpec
+  if test.action != actionRunNoSpec:
+    expected = parseSpec(tname)
+  else:
+    specDefaults expected
+    expected.action = actionRunNoSpec
   if expected.err == reIgnored:
     r.addResult(test, "", "", reIgnored)
     inc(r.skipped)
@@ -206,7 +211,7 @@ proc testSpec(r: var TResults, test: TTest) =
       var given = callCompiler(expected.cmd, test.name,
         test.options & " --hint[Path]:off --hint[Processing]:off", test.target)
       compilerOutputTests(test, given, expected, r)
-    of actionRun:
+    of actionRun, actionRunNoSpec:
       var given = callCompiler(expected.cmd, test.name, test.options,
                                test.target)
       if given.err != reSuccess:
diff --git a/tests/tuples/tuple_with_nil.nim b/tests/tuples/tuple_with_nil.nim
new file mode 100644
index 000000000..26e4ae85e
--- /dev/null
+++ b/tests/tuples/tuple_with_nil.nim
@@ -0,0 +1,766 @@
+import macros
+from strutils import IdentStartChars
+import parseutils
+import unicode
+import math
+import fenv
+import unsigned
+import pegs
+import streams
+
+type
+  FormatError = object of Exception ## Error in the format string.
+
+  Writer = concept W
+    ## Writer to output a character `c`.
+    when (NimMajor, NimMinor, NimPatch) > (0, 10, 2):
+      write(W, 'c')
+    else:
+      block:
+        var x: W
+        write(x, char)
+
+  FmtAlign = enum ## Format alignment
+    faDefault  ## default for given format type
+    faLeft     ## left aligned
+    faRight    ## right aligned
+    faCenter   ## centered
+    faPadding  ## right aligned, fill characters after sign (numbers only)
+
+  FmtSign = enum ## Format sign
+    fsMinus    ## only unary minus, no reservered sign space for positive numbers
+    fsPlus     ## unary minus and unary plus
+    fsSpace    ## unary minus and reserved space for positive numbers
+
+  FmtType = enum ## Format type
+    ftDefault  ## default format for given parameter type
+    ftStr      ## string
+    ftChar     ## character
+    ftDec      ## decimal integer
+    ftBin      ## binary integer
+    ftOct      ## octal integer
+    ftHex      ## hexadecimal integer
+    ftFix      ## real number in fixed point notation
+    ftSci      ## real number in scientific notation
+    ftGen      ## real number in generic form (either fixed point or scientific)
+    ftPercent  ## real number multiplied by 100 and % added
+
+  Format = tuple ## Formatting information.
+    typ: FmtType     ## format type
+    precision: int    ## floating point precision
+    width: int        ## minimal width
+    fill: string      ## the fill character, UTF8
+    align: FmtAlign  ## aligment
+    sign: FmtSign    ## sign notation
+    baseprefix: bool  ## whether binary, octal, hex should be prefixed by 0b, 0x, 0o
+    upcase: bool      ## upper case letters in hex or exponential formats
+    comma: bool       ##
+    arysep: string    ## separator for array elements
+
+  PartKind = enum pkStr, pkFmt
+
+  Part = object
+    ## Information of a part of the target string.
+    case kind: PartKind ## type of the part
+    of pkStr:
+      str: string ## literal string
+    of pkFmt:
+      arg: int ## position argument
+      fmt: string ## format string
+      field: string ## field of argument to be accessed
+      index: int ## array index of argument to be accessed
+      nested: bool ## true if the argument contains nested formats
+
+const
+  DefaultPrec = 6 ## Default precision for floating point numbers.
+  DefaultFmt: Format = (ftDefault, -1, -1, nil, faDefault, fsMinus, false, false, false, nil)
+    ## Default format corresponding to the empty format string, i.e.
+    ##   `x.format("") == x.format(DefaultFmt)`.
+  round_nums = [0.5, 0.05, 0.005, 0.0005, 0.00005, 0.000005, 0.0000005, 0.00000005]
+    ## Rounding offset for floating point numbers up to precision 8.
+
+proc write(s: var string; c: char) =
+  s.add(c)
+
+proc has(c: Captures; i: range[0..pegs.MaxSubpatterns-1]): bool {.nosideeffect, inline.} =
+  ## Tests whether `c` contains a non-empty capture `i`.
+  let b = c.bounds(i)
+  result = b.first <= b.last
+
+proc get(str: string; c: Captures; i: range[0..MaxSubpatterns-1]; def: char): char {.nosideeffect, inline.} =
+  ## If capture `i` is non-empty return that portion of `str` casted
+  ## to `char`, otherwise return `def`.
+  result = if c.has(i): str[c.bounds(i).first] else: def
+
+proc get(str: string; c: Captures; i: range[0..MaxSubpatterns-1]; def: string; begoff: int = 0): string {.nosideeffect, inline.} =
+  ## If capture `i` is non-empty return that portion of `str` as
+  ## string, otherwise return `def`.
+  let b = c.bounds(i)
+  result = if c.has(i): str.substr(b.first + begoff, b.last) else: def
+
+proc get(str: string; c: Captures; i: range[0..MaxSubpatterns-1]; def: int; begoff: int = 0): int {.nosideeffect, inline.} =
+  ## If capture `i` is non-empty return that portion of `str`
+  ## converted to int, otherwise return `def`.
+  if c.has(i):
+    discard str.parseInt(result, c.bounds(i).first + begoff)
+  else:
+    result = def
+
+proc parse(fmt: string): Format {.nosideeffect.} =
+  # Converts the format string `fmt` into a `Format` structure.
+  let p =
+    sequence(capture(?sequence(anyRune(), &charSet({'<', '>', '=', '^'}))),
+             capture(?charSet({'<', '>', '=', '^'})),
+             capture(?charSet({'-', '+', ' '})),
+             capture(?charSet({'#'})),
+             capture(?(+digits())),
+             capture(?charSet({','})),
+             capture(?sequence(charSet({'.'}), +digits())),
+             capture(?charSet({'b', 'c', 'd', 'e', 'E', 'f', 'F', 'g', 'G', 'n', 'o', 's', 'x', 'X', '%'})),
+             capture(?sequence(charSet({'a'}), *pegs.any())))
+  # let p=peg"{(_&[<>=^])?}{[<>=^]?}{[-+ ]?}{[#]?}{[0-9]+?}{[,]?}{([.][0-9]+)?}{[bcdeEfFgGnosxX%]?}{(a.*)?}"
+
+  var caps: Captures
+  if fmt.rawmatch(p, 0, caps) < 0:
+    raise newException(FormatError, "Invalid format string")
+
+  result.fill = fmt.get(caps, 0, nil)
+
+  case fmt.get(caps, 1, 0.char)
+  of '<': result.align = faLeft
+  of '>': result.align = faRight
+  of '^': result.align = faCenter
+  of '=': result.align = faPadding
+  else: result.align = faDefault
+
+  case fmt.get(caps, 2, '-')
+  of '-': result.sign = fsMinus
+  of '+': result.sign = fsPlus
+  of ' ': result.sign = fsSpace
+  else: result.sign = fsMinus
+
+  result.baseprefix = caps.has(3)
+
+  result.width = fmt.get(caps, 4, -1)
+
+  if caps.has(4) and fmt[caps.bounds(4).first] == '0':
+    if result.fill != nil:
+      raise newException(FormatError, "Leading 0 in with not allowed with explicit fill character")
+    if result.align != faDefault:
+      raise newException(FormatError, "Leading 0 in with not allowed with explicit alignment")
+    result.fill = "0"
+    result.align = faPadding
+
+  result.comma = caps.has(5)
+
+  result.precision = fmt.get(caps, 6, -1, 1)
+
+  case fmt.get(caps, 7, 0.char)
+  of 's': result.typ = ftStr
+  of 'c': result.typ = ftChar
+  of 'd', 'n': result.typ = ftDec
+  of 'b': result.typ = ftBin
+  of 'o': result.typ = ftOct
+  of 'x': result.typ = ftHex
+  of 'X': result.typ = ftHex; result.upcase = true
+  of 'f', 'F': result.typ = ftFix
+  of 'e': result.typ = ftSci
+  of 'E': result.typ = ftSci; result.upcase = true
+  of 'g': result.typ = ftGen
+  of 'G': result.typ = ftGen; result.upcase = true
+  of '%': result.typ = ftPercent
+  else: result.typ = ftDefault
+
+  result.arysep = fmt.get(caps, 8, nil, 1)
+
+proc getalign(fmt: Format; defalign: FmtAlign; slen: int) : tuple[left, right:int] {.nosideeffect.} =
+  ## Returns the number of left and right padding characters for a
+  ## given format alignment and width of the object to be printed.
+  ##
+  ## `fmt`
+  ##    the format data
+  ## `default`
+  ##    if `fmt.align == faDefault`, then this alignment is used
+  ## `slen`
+  ##    the width of the object to be printed.
+  ##
+  ## The returned values `(left, right)` will be as minimal as possible
+  ## so that `left + slen + right >= fmt.width`.
+  result.left = 0
+  result.right = 0
+  if (fmt.width >= 0) and (slen < fmt.width):
+    let alg = if fmt.align == faDefault: defalign else: fmt.align
+    case alg:
+    of faLeft: result.right = fmt.width - slen
+    of faRight, faPadding: result.left = fmt.width - slen
+    of faCenter:
+      result.left = (fmt.width - slen) div 2
+      result.right = fmt.width - slen - result.left
+    else: discard
+
+proc writefill(o: var Writer; fmt: Format; n: int; signum: int = 0) =
+  ## Write characters for filling. This function also writes the sign
+  ## of a numeric format and handles the padding alignment
+  ## accordingly.
+  ##
+  ## `o`
+  ##   output object
+  ## `add`
+  ##   output function
+  ## `fmt`
+  ##   format to be used (important for padding aligment)
+  ## `n`
+  ##   the number of filling characters to be written
+  ## `signum`
+  ##   the sign of the number to be written, < 0 negative, > 0 positive, = 0 zero
+  if fmt.align == faPadding and signum != 0:
+    if signum < 0: write(o, '-')
+    elif fmt.sign == fsPlus: write(o, '+')
+    elif fmt.sign == fsSpace: write(o, ' ')
+
+  if fmt.fill == nil:
+    for i in 1..n: write(o, ' ')
+  else:
+    for i in 1..n:
+      for c in fmt.fill:
+        write(o, c)
+
+  if fmt.align != faPadding and signum != 0:
+    if signum < 0: write(o, '-')
+    elif fmt.sign == fsPlus: write(o, '+')
+    elif fmt.sign == fsSpace: write(o, ' ')
+
+proc writeformat(o: var Writer; s: string; fmt: Format) =
+  ## Write string `s` according to format `fmt` using output object
+  ## `o` and output function `add`.
+  if fmt.typ notin {ftDefault, ftStr}:
+    raise newException(FormatError, "String variable must have 's' format type")
+
+  # compute alignment
+  let len = if fmt.precision < 0: runelen(s) else: min(runelen(s), fmt.precision)
+  var alg = getalign(fmt, faLeft, len)
+  writefill(o, fmt, alg.left)
+  var pos = 0
+  for i in 0..len-1:
+    let rlen = runeLenAt(s, pos)
+    for j in pos..pos+rlen-1: write(o, s[j])
+    pos += rlen
+  writefill(o, fmt, alg.right)
+
+proc writeformat(o: var Writer; c: char; fmt: Format) =
+  ## Write character `c` according to format `fmt` using output object
+  ## `o` and output function `add`.
+  if not (fmt.typ in {ftChar, ftDefault}):
+    raise newException(FormatError, "Character variable must have 'c' format type")
+
+  # compute alignment
+  var alg = getalign(fmt, faLeft, 1)
+  writefill(o, fmt, alg.left)
+  write(o, c)
+  writefill(o, fmt, alg.right)
+
+proc writeformat(o: var Writer; c: Rune; fmt: Format) =
+  ## Write rune `c` according to format `fmt` using output object
+  ## `o` and output function `add`.
+  if not (fmt.typ in {ftChar, ftDefault}):
+    raise newException(FormatError, "Character variable must have 'c' format type")
+
+  # compute alignment
+  var alg = getalign(fmt, faLeft, 1)
+  writefill(o, fmt, alg.left)
+  let s = c.toUTF8
+  for c in s: write(o, c)
+  writefill(o, fmt, alg.right)
+
+proc abs(x: SomeUnsignedInt): SomeUnsignedInt {.inline.} = x
+  ## Return the absolute value of the unsigned int `x`.
+
+proc writeformat(o: var Writer; i: SomeInteger; fmt: Format) =
+  ## Write integer `i` according to format `fmt` using output object
+  ## `o` and output function `add`.
+  var fmt = fmt
+  if fmt.typ == ftDefault:
+    fmt.typ = ftDec
+  if not (fmt.typ in {ftBin, ftOct, ftHex, ftDec}):
+    raise newException(FormatError, "Integer variable must of one of the following types: b,o,x,X,d,n")
+
+  var base: type(i)
+  var len = 0
+  case fmt.typ:
+  of ftDec:
+    base = 10
+  of ftBin:
+    base = 2
+    if fmt.baseprefix: len += 2
+  of ftOct:
+    base = 8
+    if fmt.baseprefix: len += 2
+  of ftHex:
+    base = 16
+    if fmt.baseprefix: len += 2
+  else: assert(false)
+
+  if fmt.sign != fsMinus or i < 0: len.inc
+
+  var x: type(i) = abs(i)
+  var irev: type(i) = 0
+  var ilen = 0
+  while x > 0.SomeInteger:
+    len.inc
+    ilen.inc
+    irev = irev * base + x mod base
+    x = x div base
+  if ilen == 0:
+    ilen.inc
+    len.inc
+
+  var alg = getalign(fmt, faRight, len)
+  writefill(o, fmt, alg.left, if i >= 0.SomeInteger: 1 else: -1)
+  if fmt.baseprefix:
+    case fmt.typ
+    of ftBin:
+      write(o, '0')
+      write(o, 'b')
+    of ftOct:
+      write(o, '0')
+      write(o, 'o')
+    of ftHex:
+      write(o, '0')
+      write(o, 'x')
+    else:
+      raise newException(FormatError, "# only allowed with b, o, x or X")
+  while ilen > 0:
+    ilen.dec
+    let c = irev mod base
+    irev = irev div base
+    if c < 10:
+      write(o, ('0'.int + c.int).char)
+    elif fmt.upcase:
+      write(o, ('A'.int + c.int - 10).char)
+    else:
+      write(o, ('a'.int + c.int - 10).char)
+  writefill(o, fmt, alg.right)
+
+proc writeformat(o: var Writer; p: pointer; fmt: Format) =
+  ## Write pointer `i` according to format `fmt` using output object
+  ## `o` and output function `add`.
+  ##
+  ## Pointers are casted to unsigned int and formated as hexadecimal
+  ## with prefix unless specified otherwise.
+  var f = fmt
+  if f.typ == 0.char:
+    f.typ = 'x'
+    f.baseprefix = true
+  writeformat(o, add, cast[uint](p), f)
+
+proc writeformat(o: var Writer; x: SomeReal; fmt: Format) =
+  ## Write real number `x` according to format `fmt` using output
+  ## object `o` and output function `add`.
+  var fmt = fmt
+  # handle default format
+  if fmt.typ == ftDefault:
+    fmt.typ = ftGen
+    if fmt.precision < 0: fmt.precision = DefaultPrec
+  if not (fmt.typ in {ftFix, ftSci, ftGen, ftPercent}):
+    raise newException(FormatError, "Integer variable must of one of the following types: f,F,e,E,g,G,%")
+
+  let positive = x >= 0 and classify(x) != fcNegZero
+  var len = 0
+
+  if fmt.sign != fsMinus or not positive: len.inc
+
+  var prec = if fmt.precision < 0: DefaultPrec else: fmt.precision
+  var y = abs(x)
+  var exp = 0
+  var numstr, frstr: array[0..31, char]
+  var numlen, frbeg, frlen = 0
+
+  if fmt.typ == ftPercent: y *= 100
+
+  case classify(x):
+  of fcNan:
+    numstr[0..2] = ['n', 'a', 'n']
+    numlen = 3
+  of fcInf, fcNegInf:
+    numstr[0..2] = ['f', 'n', 'i']
+    numlen = 3
+  of fcZero, fcNegZero:
+    numstr[0] = '0'
+    numlen = 1
+  else: # a usual fractional number
+    if not (fmt.typ in {ftFix, ftPercent}): # not fixed point
+      exp = int(floor(log10(y)))
+      if fmt.typ == ftGen:
+        if prec == 0: prec = 1
+        if -4 <= exp and exp < prec:
+          prec = prec-1-exp
+          exp = 0
+        else:
+          prec = prec - 1
+          len += 4 # exponent
+      else:
+        len += 4 # exponent
+      # shift y so that 1 <= abs(y) < 2
+      if exp > 0: y /= pow(10.SomeReal, abs(exp).SomeReal)
+      elif exp < 0: y *= pow(10.SomeReal, abs(exp).SomeReal)
+    elif fmt.typ == ftPercent:
+      len += 1 # percent sign
+
+    # handle rounding by adding +0.5 * LSB
+    if prec < len(round_nums): y += round_nums[prec]
+
+    # split into integer and fractional part
+    var mult = 1'i64
+    for i in 1..prec: mult *= 10
+    var num = y.int64
+    var fr = ((y - num.SomeReal) * mult.SomeReal).int64
+    # build integer part string
+    while num != 0:
+      numstr[numlen] = ('0'.int + (num mod 10)).char
+      numlen.inc
+      num = num div 10
+    if numlen == 0:
+      numstr[0] = '0'
+      numlen.inc
+    # build fractional part string
+    while fr != 0:
+      frstr[frlen] = ('0'.int + (fr mod 10)).char
+      frlen.inc
+      fr = fr div 10
+    while frlen < prec:
+      frstr[frlen] = '0'
+      frlen.inc
+    # possible remove trailing 0
+    if fmt.typ == ftGen:
+      while frbeg < frlen and frstr[frbeg] == '0': frbeg.inc
+  # update length of string
+  len += numlen;
+  if frbeg < frlen:
+    len += 1 + frlen - frbeg # decimal point and fractional string
+
+  let alg = getalign(fmt, faRight, len)
+  writefill(o, fmt, alg.left, if positive: 1 else: -1)
+  for i in (numlen-1).countdown(0): write(o, numstr[i])
+  if frbeg < frlen:
+    write(o, '.')
+    for i in (frlen-1).countdown(frbeg): write(o, frstr[i])
+  if fmt.typ == ftSci or (fmt.typ == ftGen and exp != 0):
+    write(o, if fmt.upcase: 'E' else: 'e')
+    if exp >= 0:
+      write(o, '+')
+    else:
+      write(o, '-')
+      exp = -exp
+    if exp < 10:
+      write(o, '0')
+      write(o, ('0'.int + exp).char)
+    else:
+      var i=0
+      while exp > 0:
+        numstr[i] = ('0'.int + exp mod 10).char
+        i+=1
+        exp = exp div 10
+      while i>0:
+        i-=1
+        write(o, numstr[i])
+  if fmt.typ == ftPercent: write(o, '%')
+  writefill(o, fmt, alg.right)
+
+proc writeformat(o: var Writer; b: bool; fmt: Format) =
+  ## Write boolean value `b` according to format `fmt` using output
+  ## object `o`. A boolean may be formatted numerically or as string.
+  ## In the former case true is written as 1 and false as 0, in the
+  ## latter the strings "true" and "false" are shown, respectively.
+  ## The default is string format.
+  if fmt.typ in {ftStr, ftDefault}:
+    writeformat(o,
+                if b: "true"
+                else: "false",
+                fmt)
+  elif fmt.typ in {ftBin, ftOct, ftHex, ftDec}:
+    writeformat(o,
+                if b: 1
+                else: 0,
+                fmt)
+  else:
+    raise newException(FormatError, "Boolean values must of one of the following types: s,b,o,x,X,d,n")
+
+proc writeformat(o: var Writer; ary: openarray[any]; fmt: Format) =
+  ## Write array `ary` according to format `fmt` using output object
+  ## `o` and output function `add`.
+  if ary.len == 0: return
+
+  var sep: string
+  var nxtfmt = fmt
+  if fmt.arysep == nil:
+    sep = "\t"
+  elif fmt.arysep.len == 0:
+    sep = ""
+  else:
+    let sepch = fmt.arysep[0]
+    let nxt = 1 + skipUntil(fmt.arysep, sepch, 1)
+    if nxt >= 1:
+      nxtfmt.arysep = fmt.arysep.substr(nxt)
+      sep = fmt.arysep.substr(1, nxt-1)
+    else:
+      nxtfmt.arysep = ""
+      sep = fmt.arysep.substr(1)
+  writeformat(o, ary[0], nxtfmt)
+  for i in 1..ary.len-1:
+    for c in sep: write(o, c)
+    writeformat(o, ary[i], nxtfmt)
+
+proc addformat[T](o: var Writer; x: T; fmt: Format = DefaultFmt) {.inline.} =
+  ## Write `x` formatted with `fmt` to `o`.
+  writeformat(o, x, fmt)
+
+proc addformat[T](o: var Writer; x: T; fmt: string) {.inline.} =
+  ## The same as `addformat(o, x, parse(fmt))`.
+  addformat(o, x, fmt.parse)
+
+proc addformat(s: var string; x: string) {.inline.} =
+  ## Write `x` to `s`. This is a fast specialized version for
+  ## appending unformatted strings.
+  add(s, x)
+
+proc addformat(f: File; x: string) {.inline.} =
+  ## Write `x` to `f`. This is a fast specialized version for
+  ## writing unformatted strings to a file.
+  write(f, x)
+
+proc addformat[T](f: File; x: T; fmt: Format = DefaultFmt) {.inline.} =
+  ## Write `x` to file `f` using format `fmt`.
+  var g = f
+  writeformat(g, x, fmt)
+
+proc addformat[T](f: File; x: T; fmt: string) {.inline.} =
+  ## Write `x` to file `f` using format string `fmt`. This is the same
+  ## as `addformat(f, x, parse(fmt))`
+  addformat(f, x, parse(fmt))
+
+proc addformat(s: Stream; x: string) {.inline.} =
+  ## Write `x` to `s`. This is a fast specialized version for
+  ## writing unformatted strings to a stream.
+  write(s, x)
+
+proc addformat[T](s: Stream; x: T; fmt: Format = DefaultFmt) {.inline.} =
+  ## Write `x` to stream `s` using format `fmt`.
+  var g = s
+  writeformat(g, x, fmt)
+
+proc addformat[T](s: Stream; x: T; fmt: string) {.inline.} =
+  ## Write `x` to stream `s` using format string `fmt`. This is the same
+  ## as `addformat(s, x, parse(fmt))`
+  addformat(s, x, parse(fmt))
+
+proc format[T](x: T; fmt: Format): string =
+  ## Return `x` formatted as a string according to format `fmt`.
+  result = ""
+  addformat(result, x, fmt)
+
+proc format[T](x: T; fmt: string): string =
+  ## Return `x` formatted as a string according to format string `fmt`.
+  result = format(x, fmt.parse)
+
+proc format[T](x: T): string {.inline.} =
+  ## Return `x` formatted as a string according to the default format.
+  ## The default format corresponds to an empty format string.
+  var fmt {.global.} : Format = DefaultFmt
+  result = format(x, fmt)
+
+proc unquoted(s: string): string {.compileTime.} =
+  ## Return `s` {{ and }} by single { and }, respectively.
+  result = ""
+  var pos = 0
+  while pos < s.len:
+    let nxt = pos + skipUntil(s, {'{', '}'})
+    result.add(s.substr(pos, nxt))
+    pos = nxt + 2
+
+proc splitfmt(s: string): seq[Part] {.compiletime, nosideeffect.} =
+  ## Split format string `s` into a sequence of "parts".
+  ##
+
+  ## Each part is either a literal string or a format specification. A
+  ## format specification is a substring of the form
+  ## "{[arg][:format]}" where `arg` is either empty or a number
+  ## refering to the arg-th argument and an additional field or array
+  ## index. The format string is a string accepted by `parse`.
+  let subpeg = sequence(capture(digits()),
+                          capture(?sequence(charSet({'.'}), *pegs.identStartChars(), *identChars())),
+                          capture(?sequence(charSet({'['}), +digits(), charSet({']'}))),
+                          capture(?sequence(charSet({':'}), *pegs.any())))
+  result = @[]
+  var pos = 0
+  while true:
+    let oppos = pos + skipUntil(s, {'{', '}'}, pos)
+    # reached the end
+    if oppos >= s.len:
+      if pos < s.len:
+        result.add(Part(kind: pkStr, str: s.substr(pos).unquoted))
+      return
+    # skip double
+    if oppos + 1 < s.len and s[oppos] == s[oppos+1]:
+      result.add(Part(kind: pkStr, str: s.substr(pos, oppos)))
+      pos = oppos + 2
+      continue
+    if s[oppos] == '}':
+      error("Single '}' encountered in format string")
+    if oppos > pos:
+      result.add(Part(kind: pkStr, str: s.substr(pos, oppos-1).unquoted))
+    # find matching closing }
+    var lvl = 1
+    var nested = false
+    pos = oppos
+    while lvl > 0:
+      pos.inc
+      pos = pos + skipUntil(s, {'{', '}'}, pos)
+      if pos >= s.len:
+        error("Single '{' encountered in format string")
+      if s[pos] == '{':
+        lvl.inc
+        if lvl == 2:
+          nested = true
+        if lvl > 2:
+          error("Too many nested format levels")
+      else:
+        lvl.dec
+    let clpos = pos
+    var fmtpart = Part(kind: pkFmt, arg: -1, fmt: s.substr(oppos+1, clpos-1), field: nil, index: int.high, nested: nested)
+    if fmtpart.fmt.len > 0:
+      var m: array[0..3, string]
+      if not fmtpart.fmt.match(subpeg, m):
+        error("invalid format string")
+
+      if m[1] != nil and m[1].len > 0:
+        fmtpart.field = m[1].substr(1)
+      if m[2] != nil and m[2].len > 0:
+        discard parseInt(m[2].substr(1, m[2].len-2), fmtpart.index)
+
+      if m[0].len > 0: discard parseInt(m[0], fmtpart.arg)
+      if m[3] == nil or m[3].len == 0:
+        fmtpart.fmt = ""
+      elif m[3][0] == ':':
+        fmtpart.fmt = m[3].substr(1)
+      else:
+        fmtpart.fmt = m[3]
+    result.add(fmtpart)
+    pos = clpos + 1
+
+proc literal(s: string): NimNode {.compiletime, nosideeffect.} =
+  ## Return the nim literal of string `s`. This handles the case if
+  ## `s` is nil.
+  result = if s == nil: newNilLit() else: newLit(s)
+
+proc literal(b: bool): NimNode {.compiletime, nosideeffect.} =
+  ## Return the nim literal of boolean `b`. This is either `true`
+  ## or `false` symbol.
+  result = if b: "true".ident else: "false".ident
+
+proc literal[T](x: T): NimNode {.compiletime, nosideeffect.} =
+  ## Return the nim literal of value `x`.
+  when type(x) is enum:
+    result = ($x).ident
+  else:
+    result = newLit(x)
+
+proc generatefmt(fmtstr: string;
+                 args: var openarray[tuple[arg:NimNode, cnt:int]];
+                 arg: var int;): seq[tuple[val, fmt:NimNode]] {.compiletime.} =
+  ## fmtstr
+  ##   the format string
+  ## args
+  ##   array of expressions for the arguments
+  ## arg
+  ##   the number of the next argument for automatic parsing
+  ##
+  ## If arg is < 0 then the functions assumes that explicit numbering
+  ## must be used, otherwise automatic numbering is used starting at
+  ## `arg`. The value of arg is updated according to the number of
+  ## arguments being used. If arg == 0 then automatic and manual
+  ## numbering is not decided (because no explicit manual numbering is
+  ## fixed und no automatically numbered argument has been used so
+  ## far).
+  ##
+  ## The function returns a list of pairs `(val, fmt)` where `val` is
+  ## an expression to be formatted and `fmt` is the format string (or
+  ## Format). Therefore, the resulting string can be generated by
+  ## concatenating expressions `val.format(fmt)`. If `fmt` is `nil`
+  ## then `val` is a (literal) string expression.
+  try:
+    result = @[]
+    for part in splitfmt(fmtstr):
+      case part.kind
+      of pkStr: result.add((newLit(part.str), nil))
+      of pkFmt:
+        # first compute the argument expression
+        # start with the correct index
+        var argexpr : NimNode
+        if part.arg >= 0:
+          if arg > 0:
+            error("Cannot switch from automatic field numbering to manual field specification")
+          if part.arg >= args.len:
+            error("Invalid explicit argument index: " & $part.arg)
+          argexpr = args[part.arg].arg
+          args[part.arg].cnt = args[part.arg].cnt + 1
+          arg = -1
+        else:
+          if arg < 0:
+            error("Cannot switch from manual field specification to automatic field numbering")
+          if arg >= args.len:
+            error("Too few arguments for format string")
+          argexpr = args[arg].arg
+          args[arg].cnt = args[arg].cnt + 1
+          arg.inc
+        # possible field access
+        if part.field != nil and part.field.len > 0:
+          argexpr = newDotExpr(argexpr, part.field.ident)
+        # possible array access
+        if part.index < int.high:
+          argexpr = newNimNode(nnkBracketExpr).add(argexpr, newLit(part.index))
+        # now the expression for the format data
+        var fmtexpr: NimNode
+        if part.nested:
+          # nested format string. Compute the format string by
+          # concatenating the parts of the substring.
+          for e in generatefmt(part.fmt, args, arg):
+            var newexpr = if part.fmt == nil: e.val else: newCall(bindsym"format", e.val, e.fmt)
+            if fmtexpr != nil and fmtexpr.kind != nnkNilLit:
+              fmtexpr = infix(fmtexpr, "&", newexpr)
+            else:
+              fmtexpr = newexpr
+        else:
+          # literal format string, precompute the format data
+          fmtexpr = newNimNode(nnkPar)
+          for field, val in part.fmt.parse.fieldPairs:
+            fmtexpr.add(newNimNode(nnkExprColonExpr).add(field.ident, literal(val)))
+        # add argument
+        result.add((argexpr, fmtexpr))
+  finally:
+    discard
+
+proc addfmtfmt(fmtstr: string; args: NimNode; retvar: NimNode): NimNode {.compileTime.} =
+  var argexprs = newseq[tuple[arg:NimNode; cnt:int]](args.len)
+  result = newNimNode(nnkStmtListExpr)
+  # generate let bindings for arguments
+  for i in 0..args.len-1:
+    let argsym = gensym(nskLet, "arg" & $i)
+    result.add(newLetStmt(argsym, args[i]))
+    argexprs[i].arg = argsym
+  # add result values
+  var arg = 0
+  for e in generatefmt(fmtstr, argexprs, arg):
+    if e.fmt == nil or e.fmt.kind == nnkNilLit:
+      result.add(newCall(bindsym"addformat", retvar, e.val))
+    else:
+      result.add(newCall(bindsym"addformat", retvar, e.val, e.fmt))
+  for i, arg in argexprs:
+    if arg.cnt == 0:
+      warning("Argument " & $(i+1) & " `" & args[i].repr & "` is not used in format string")
+
+macro addfmt(s: var string, fmtstr: string{lit}, args: varargs[expr]): expr =
+  ## The same as `s.add(fmtstr.fmt(args...))` but faster.
+  result = addfmtfmt($fmtstr, args, s)
+
+var s: string = ""
+s.addfmt("a:{}", 42)
diff --git a/tests/tuples/tuple_with_seq.nim b/tests/tuples/tuple_with_seq.nim
new file mode 100644
index 000000000..39edb500f
--- /dev/null
+++ b/tests/tuples/tuple_with_seq.nim
@@ -0,0 +1,46 @@
+discard """
+  output: '''it's nil
+@[1, 2, 3]'''
+"""
+
+template foo(s: string = nil) =
+  if isNil(s):
+    echo "it's nil"
+  else:
+    echo s
+
+foo
+
+
+# bug #2632
+
+proc takeTup(x: tuple[s: string;x: seq[int]]) =
+  discard
+
+takeTup(("foo", @[]))
+
+
+#proc foobar(): () =
+
+proc f(xs: seq[int]) =
+  discard
+
+proc g(t: tuple[n:int, xs:seq[int]]) =
+  discard
+
+when isMainModule:
+  f(@[]) # OK
+  g((1,@[1])) # OK
+  g((0,@[])) # NG
+
+
+# bug #2630
+type T = tuple[a: seq[int], b: int]
+
+var t: T = (@[1,2,3], 7)
+
+proc test(s: seq[int]): T =
+  echo s
+  (s, 7)
+
+t = test(t.a)
diff --git a/tests/types/temptyseqs.nim b/tests/types/temptyseqs.nim
index 2b07ba679..834f63729 100644
--- a/tests/types/temptyseqs.nim
+++ b/tests/types/temptyseqs.nim
@@ -1,5 +1,13 @@
 discard """
-  output: "1"
+  output: '''1
+foo
+bar
+baz
+foo
+bar
+baz
+yes
+no'''
 """
 
 # bug #1708
@@ -24,3 +32,59 @@ when true:
 const foo2: seq[string] = @[]
 
 echo foo[0][0][0]
+
+proc takeEmpty(x: openArray[string] = []) = discard
+takeEmpty()
+takeEmpty([])
+
+proc takeEmpty2(x: openArray[string] = @[]) = discard
+takeEmpty2()
+takeEmpty2([])
+takeEmpty2(@[])
+
+#takeEmpty2([nil])
+
+#rawMessage(errExecutionOfProgramFailed, [])
+
+# bug #2470
+const
+  stuff: seq[string] = @[]
+
+for str in stuff:
+  echo "str=", str
+
+# bug #1354
+proc foo4[T](more: seq[T] = @[]) =
+  var more2 = more
+
+foo4[int]()
+
+proc maino: int =
+  var wd: cstring = nil
+  inc result
+
+discard maino()
+
+proc varargso(a: varargs[string]) =
+  for x in a:
+    echo x
+
+varargso(["foo", "bar", "baz"])
+varargso("foo", "bar", "baz")
+
+
+type
+  Flago = enum
+    tfNeedsInit, tfNotNil
+
+var s: set[Flago] = {tfNeedsInit}
+
+if {tfNeedsInit, tfNotNil} * s != {}:
+  echo "yes"
+else:
+  echo "no"
+
+if {tfNeedsInit, tfNotNil} * s <= {tfNotNil}:
+  echo "yes"
+else:
+  echo "no"
diff --git a/todo.txt b/todo.txt
index 12e82331f..4972015a7 100644
--- a/todo.txt
+++ b/todo.txt
@@ -1,20 +1,20 @@
-version 0.10.4
+version 0.11.2
 ==============
 
-- make 'nil' work for 'add':
-  - resizeString
-  - incrSeq
-  - addChar
-
-
-version 0.10.6 (RC1?)
-=====================
-
+- The remaining bugs of the lambda lifting pass that is responsible to enable
+  closures and closure iterators need to be fixed.
+- ``concept`` needs to be refined, a nice name for the feature is not enough.
+- Destructors need to be refined.
 - make '--implicitStatic:on' the default; then we can also clean up the
   'static[T]' mess in the compiler!
-- finish 'parallel' or mark as experimental
+
+- Finish the implementation of the 'parallel' statement.
 - Deprecate ``immediate`` for templates and macros
 - special case varargs[untyped] and varargs[typed]
+- make 'nil' work for 'add':
+  - resizeString
+  - incrSeq
+  - addChar
 
 
 version 1.0
diff --git a/tools/niminst/niminst.nim b/tools/niminst/niminst.nim
index e50b251d3..f0ae45484 100644
--- a/tools/niminst/niminst.nim
+++ b/tools/niminst/niminst.nim
@@ -35,6 +35,7 @@ type
     actionNsis,   # action: create NSIS installer
     actionScripts # action: create install and deinstall scripts
     actionZip,    # action: create zip file
+    actionTargz,  # action: create targz file
     actionDeb     # action: prepare deb package
 
   FileCategory = enum
@@ -171,6 +172,7 @@ proc parseCmdLine(c: var ConfigData) =
           of "csource": incl(c.actions, actionCSource)
           of "scripts": incl(c.actions, actionScripts)
           of "zip": incl(c.actions, actionZip)
+          of "targz": incl(c.actions, actionTargz)
           of "inno": incl(c.actions, actionInno)
           of "nsis": incl(c.actions, actionNsis)
           of "deb": incl(c.actions, actionDeb)
@@ -181,10 +183,10 @@ proc parseCmdLine(c: var ConfigData) =
         break
     of cmdLongoption, cmdShortOption:
       case normalize(key.string)
-      of "help", "h": 
+      of "help", "h":
         stdout.write(Usage)
         quit(0)
-      of "version", "v": 
+      of "version", "v":
         stdout.write(Version & "\n")
         quit(0)
       of "o", "output": c.outdir = val
@@ -240,7 +242,7 @@ proc incl(s: var seq[string], x: string): int =
   for i in 0.. <s.len:
     if cmpIgnoreStyle(s[i], x) == 0: return i
   s.add(x)
-  result = s.len-1 
+  result = s.len-1
 
 proc platforms(c: var ConfigData, v: string) =
   for line in splitLines(v):
@@ -277,17 +279,17 @@ proc parseIniFile(c: var ConfigData) =
           of "name": c.name = v
           of "displayname": c.displayName = v
           of "version": c.version = v
-          of "os": 
+          of "os":
             c.oses = split(v, {';'})
             hasCpuOs = true
             if c.explicitPlatforms:
               quit(errorStr(p, "you cannot have both 'platforms' and 'os'"))
-          of "cpu": 
+          of "cpu":
             c.cpus = split(v, {';'})
             hasCpuOs = true
             if c.explicitPlatforms:
               quit(errorStr(p, "you cannot have both 'platforms' and 'cpu'"))
-          of "platforms": 
+          of "platforms":
             platforms(c, v)
             c.explicitPlatforms = true
             if hasCpuOs:
@@ -389,7 +391,7 @@ proc readCFiles(c: var ConfigData, osA, cpuA: int) =
       of cfgKeyValuePair:
         case section
         of "ccompiler": pathFlags(p, k.key, k.value, c.ccompiler)
-        of "linker": 
+        of "linker":
           pathFlags(p, k.key, k.value, c.linker)
           # HACK: we conditionally add ``-lm -ldl``, so remove them from the
           # linker flags:
@@ -558,28 +560,68 @@ when haveZipLib:
     else:
       quit("Cannot open for writing: " & n)
 
+proc targzDist(c: var ConfigData) =
+  let proj = toLower(c.name) & "-" & c.version
+  var n = "$#.tar.gz" % proj
+  let tmpDir = if c.outdir.len == 0: "build" else: c.outdir
+
+  template processFile(z, dest, src) =
+    let s = src
+    let d = dest
+    echo "Copying ", s, " to ", tmpDir / d
+    let destdir = tmpdir / d.splitFile.dir
+    if not dirExists(destdir): createDir(destdir)
+    copyFile(s, tmpDir / d)
+
+  processFile(z, proj / buildBatFile32, "build" / buildBatFile32)
+  processFile(z, proj / buildBatFile64, "build" / buildBatFile64)
+  processFile(z, proj / buildShFile, "build" / buildShFile)
+  processFile(z, proj / makeFile, "build" / makeFile)
+  processFile(z, proj / installShFile, installShFile)
+  processFile(z, proj / deinstallShFile, deinstallShFile)
+  for f in walkFiles(c.libpath / "lib/*.h"):
+    processFile(z, proj / "c_code" / extractFilename(f), f)
+  for osA in 1..c.oses.len:
+    for cpuA in 1..c.cpus.len:
+      var dir = buildDir(osA, cpuA)
+      for k, f in walkDir("build" / dir):
+        if k == pcFile: processFile(z, proj / dir / extractFilename(f), f)
+
+  for cat in items({fcConfig..fcOther, fcUnix}):
+    for f in items(c.cat[cat]): processFile(z, proj / f, f)
+
+  let oldDir = getCurrentDir()
+  setCurrentDir(tmpDir)
+  try:
+    #if execShellCmd("7z a -ttar $1.tar $1" % proj) != 0 or
+    #   execShellCmd("7z a -tgzip $1.tar.gz $1.tar" % proj) != 0 or
+    if execShellCmd("7z a -tzip $1.zip $1" % proj) != 0:
+      echo("External program failed")
+  finally:
+    setCurrentDir(oldDir)
+
 # -- prepare build files for .deb creation
 
 proc debDist(c: var ConfigData) =
   if not existsFile(getOutputDir(c) / "build.sh"): quit("No build.sh found.")
   if not existsFile(getOutputDir(c) / "install.sh"): quit("No install.sh found.")
-  
+
   if c.debOpts.shortDesc == "": quit("shortDesc must be set in the .ini file.")
   if c.debOpts.licenses.len == 0:
     echo("[Warning] No licenses specified for .deb creation.")
-  
+
   # -- Copy files into /tmp/..
   echo("Copying source to tmp/niminst/deb/")
   var currentSource = getCurrentDir()
   var workingDir = getTempDir() / "niminst" / "deb"
   var upstreamSource = (c.name.toLower() & "-" & c.version)
-  
+
   createDir(workingDir / upstreamSource)
-  
+
   template copyNimDist(f, dest: string): stmt =
     createDir((workingDir / upstreamSource / dest).splitFile.dir)
     copyFile(currentSource / f, workingDir / upstreamSource / dest)
-  
+
   # Don't copy all files, only the ones specified in the config:
   copyNimDist(buildShFile, buildShFile)
   copyNimDist(makeFile, makeFile)
@@ -624,5 +666,7 @@ if actionZip in c.actions:
     zipDist(c)
   else:
     quit("libzip is not installed")
+if actionTargz in c.actions:
+  targzDist(c)
 if actionDeb in c.actions:
   debDist(c)
diff --git a/tools/niminst/nsis.tmpl b/tools/niminst/nsis.tmpl
index c21bfb9d5..843a8cf44 100644
--- a/tools/niminst/nsis.tmpl
+++ b/tools/niminst/nsis.tmpl
@@ -1,5 +1,5 @@
 #! stdtmpl(subsChar='?') | standard
-#proc generateNsisSetup(c: ConfigData): string = 
+#proc generateNsisSetup(c: ConfigData): string =
 #  result = "; NSIS script generated by niminst\n" &
 #           "; To regenerate run ``niminst nsis`` or ``koch nsis``\n"
 
@@ -35,8 +35,8 @@
 
   ; Default installation folder
   ; This is changed later (in .onInit) to the root directory, if possible.
-  InstallDir "$LOCALAPPDATA\?{c.name}"
-  
+  InstallDir "$LOCALAPPDATA\?{c.name}-?{c.version}"
+
   ; Get installation folder from registry if available
   InstallDirRegKey HKCU "Software\c.name\c.version" ""
 
@@ -86,14 +86,14 @@
 
   !insertmacro MUI_PAGE_INSTFILES
   !insertmacro MUI_PAGE_FINISH
-  
+
   ; Setup the uninstaller pages
   !insertmacro MUI_UNPAGE_CONFIRM
   !insertmacro MUI_UNPAGE_INSTFILES
-  
+
 ;--------------------------------
 ;Languages
- 
+
   !insertmacro MUI_LANGUAGE "English"
 
 ;--------------------------------
@@ -104,7 +104,7 @@
   ; Nim binary.
   Section "Core Files" CoreSection
     ; This is a mandotory section
-    SectionIn RO 
+    SectionIn RO
 
     ; Output files to the base installation directory
     SetOutPath "$INSTDIR"
@@ -164,7 +164,7 @@
 
   ; The downloadable sections. These sections are automatically generated by
   ; niminst and the template filters.
-  #var i = 0 
+  #var i = 0
   #for download in c.downloads:
   #  inc i
   #  let d = download.split('|')
@@ -207,7 +207,7 @@
         CreateShortCut "$SMPROGRAMS\$ICONS_GROUP\?{e}.lnk" "$INSTDIR\?dir\?{startMenuEntry.toWin}"
       !insertmacro MUI_STARTMENU_WRITE_END
     #  end if
-    
+
     ignore:
   SectionEnd
   #end
diff --git a/web/assets/style.css b/web/assets/style.css
index b74cbc486..17541a118 100644
--- a/web/assets/style.css
+++ b/web/assets/style.css
@@ -125,8 +125,8 @@ pre .end { background:url("images/tabEnd.png") no-repeat left bottom; }
       opacity 1s ease-in-out; }
 	#slideshow > div.active { visibility:visible; opacity:1; transition-delay:0s; }
 	#slideshow > div.init { transition-delay:0s; }
-	#slideshow-nav { z-index:3; position:absolute; top:110px;; right:-12px; }
-	#slideshow-nav > div { margin:5px 0; width:23px; height:23px; background:url("images/slideshow-nav.png") no-repeat; }
+	#slideshow-nav { z-index:3; position:absolute; top:341px; left:18px; }
+	#slideshow-nav > div { display:inline-block; margin:5px 0; width:23px; height:23px; background:url("images/slideshow-nav.png") no-repeat; }
 	#slideshow-nav > div:hover { background-image:url("images/slideshow-nav_active.png"); opacity:0.5; }
 	#slideshow-nav > div.active { background-image:url("images/slideshow-nav_active.png"); opacity:1; }
     
diff --git a/web/documentation.txt b/web/documentation.txt
index dbb737cd9..67f8b4070 100644
--- a/web/documentation.txt
+++ b/web/documentation.txt
@@ -8,13 +8,13 @@ Nim's Documentation
 
   .. container:: libraries
 
-    - | `Standard Library <lib.html>`_
+    - | `Standard Library <docs/lib.html>`_
       | This document describes Nim's standard library.
 
-    - | `Language Manual <manual.html>`_
+    - | `Language Manual <docs/manual.html>`_
       | The Nim manual is a draft that will evolve into a proper specification.
 
-    - | `Compiler User Guide <nimc.html>`_
+    - | `Compiler User Guide <docs/nimc.html>`_
       | The user guide lists command line arguments, special features of the
         compiler, etc.
 
@@ -26,11 +26,11 @@ Nim's Documentation
 
   .. container:: tools
 
-    - | `Source Code Filters <filters.html>`_
+    - | `Source Code Filters <docs/filters.html>`_
       | The Nim compiler supports source code filters as a simple yet powerful
         builtin templating system.
 
-    - | `Tools Documentation <tools.html>`_
+    - | `Tools Documentation <docs/tools.html>`_
       | Description of some tools that come with the standard distribution.
 
 
@@ -41,16 +41,17 @@ Nim's Documentation
 
   .. container:: internals
 
-    - | `Garbage Collector <gc.html>`_
+    - | `Garbage Collector <docs/gc.html>`_
       | Additional documentation about Nim's GC and how to operate it in a
         realtime setting.
 
-    - | `Internal Documentation <intern.html>`_
-      | The internal documentation describes how the compiler is implemented. Read
-        this if you want to hack the compiler.
+    - | `Internal Documentation <docs/intern.html>`_
+      | The internal documentation describes how the compiler is implemented.
+        Read this if you want to hack the compiler.
 
 
 Search Options
 --------------
 
-`Documentation Index <theindex.html>`_ - The generated index. **Index + (Ctrl+F) == Joy**
+`Documentation Index <docs/theindex.html>`_ - The generated
+index. **Index + (Ctrl+F) == Joy**
diff --git a/web/download.txt b/web/download.txt
index 3d47467f2..6acc80b53 100644
--- a/web/download.txt
+++ b/web/download.txt
@@ -13,8 +13,8 @@ Binaries
 --------
 
 Unfortunately for now we only provide builds for Windows.
-* 32 bit: `nim-0.10.2_x32.exe <download/nim-0.10.2_x32.exe>`_
-* 64 bit: `nim-0.10.2_x64.exe <download/nim-0.10.2_x64.exe>`_
+* 32 bit: `nim-0.11.2_x32.exe <download/nim-0.11.2_x32.exe>`_
+* 64 bit: `nim-0.11.2_x64.exe <download/nim-0.11.2_x64.exe>`_
 
 
 Installation based on generated C code
@@ -24,8 +24,12 @@ This installation method is the preferred way for Linux, Mac OS X, and other Uni
 like systems. Binary packages may be provided later.
 
 
-Download `nim-0.10.2.zip <download/nim-0.10.2.zip>`_, extract it and follow
-these instructions:
+Download one of these:
+
+* `nim-0.11.2.zip (28 MB) <download/nim-0.11.2.zip>`_
+* `nim-0.11.2.tar.xz (2.6MB) <download/nim-0.11.2.tar.xz>`_
+
+Extract the file and follow these instructions:
 
 * sh build.sh
 * Add ``$your_install_dir/bin`` to your PATH.
diff --git a/web/learn.txt b/web/learn.txt
index 7a9600e57..bf0cc43ef 100644
--- a/web/learn.txt
+++ b/web/learn.txt
@@ -8,10 +8,10 @@ Learning Nim
 
   .. container:: tutorials
 
-    - | `Tutorial (part I) <tut1.html>`_
+    - | `Tutorial (part I) <docs/tut1.html>`_
       | Learn the basics of Nim's types, variables, procedures, control flow, etc...
 
-    - | `Tutorial (part II) <tut2.html>`_
+    - | `Tutorial (part II) <docs/tut2.html>`_
       | Learn Nim's more advanced features such as OOP, generics, macros, etc...
 
 
@@ -52,5 +52,5 @@ Learning Nim
 Documentation
 -------------
 
-More examples of Nim code can be found in the `Nim Language Documentation <manual.html>`_.
+More examples of Nim code can be found in the `Nim Language Documentation <docs/manual.html>`_.
 
diff --git a/web/news.txt b/web/news.txt
index b3453feaf..9719fb8d7 100644
--- a/web/news.txt
+++ b/web/news.txt
@@ -3,344 +3,423 @@ News
 ====
 
 ..
-  2015-03-01 Version 0.10.4 released
+  2015-05-05 Version 0.11.2 released
   ==================================
 
-
   Changes affecting backwards compatibility
   -----------------------------------------
 
-  - Parameter names are finally properly ``gensym``'ed. This can break
-    templates though that used to rely on the fact that they are not.
-    (Bug #1915.) This means this doesn't compile anymore:
-
-  .. code-block:: nim
-
-    template doIt(body: stmt) {.immediate.} =
-      # this used to inject the 'str' parameter:
-      proc res(str: string) =
-        body
-
-    doIt:
-      echo str # Error: undeclared identifier: 'str'
-
-    Declare the ``doIt`` template as ``immediate, dirty`` to get the old
-    behaviour.
-  - Tuple field names are not ignored anymore, this caused too many problems
-    in practice so now the behaviour as it was for version 0.9.6: If field
-    names exist for the tuple type, they are checked.
-  - ``logging.level`` and ``logging.handlers`` are no longer exported.
-    ``addHandler``, ``getHandlers``, ``setLogFilter`` and ``getLogFilter``
-    should be used instead.
-  - ``nim idetools`` has been replaced by a separate tool `nimsuggest`_.
-  - *arrow like* operators are not right associative anymore.
-  - *arrow like* operators are now required to end with either ``->``, ``~>`` or
-    ``=>``, not just ``>``. Examples of operators still considered arrow like:
-    ``->``, ``==>``, ``+=>``. On the other hand, the following operators are now
-    considered regular operators again: ``|>``, ``-+>``, etc.
-  - Typeless parameters are now only allowed in templates and macros. The old
-    way turned out to be too error-prone.
-  - The 'addr' and 'type' operators are now parsed as unary function
-    application. This means ``type(x).name`` is now parsed as ``(type(x)).name``
-    and not as ``type((x).name)``. Note that this also affects the AST
-    structure; for immediate macro parameters ``nkCall('addr', 'x')`` is
-    produced instead of ``nkAddr('x')``.
-  - ``concept`` is now a keyword and is used instead of ``generic``.
-  - The ``inc``, ``dec``, ``+=``, ``-=`` builtins now produce OverflowError
-    exceptions. This means code like the following:
-
-  .. code-block:: nim
-    var x = low(T)
-    while x <= high(T):
-      echo x
-      inc x
-
-  Needs to be replaced by something like this:
-
-  .. code-block:: nim
-    var x = low(T).int
-    while x <= high(T).int:
-      echo x.T
-      inc x
-
-  - **Negative indexing for slicing does not work anymore!** Instead
-    of ``a[0.. -1]`` you can
-    use ``a[0.. ^1]``. This also works with accessing a single
-    element ``a[^1]``. Note that we cannot detect this reliably as it is
-    determined at **runtime** whether negative indexing is used!
-    ``a[0.. -1]`` now produces the empty string/sequence.
-  - The compiler now warns about code like ``foo +=1`` which uses inconsistent
-    spacing around binary operators. Later versions of the language will parse
-    these as unary operators instead so that ``echo $foo`` finally can do what
-    people expect it to do.
-  - ``system.untyped`` and ``system.typed`` have been introduced as aliases
-    for ``expr`` and ``stmt``. The new names capture the semantics much better
-    and most likely  ``expr`` and ``stmt`` will be deprecated in favor of the
-    new names.
-  - The ``split`` method in module ``re`` has changed. It now handles the case
-    of matches having a length of 0, and empty strings being yielded from the
-    iterator. A notable change might be that a pattern being matched at the
-    beginning and end of a string, will result in an empty string being produced
-    at the start and the end of the iterator.
 
   Language Additions
   ------------------
 
-  - For empty ``case object`` branches ``discard`` can finally be used instead
-    of ``nil``.
-  - Automatic dereferencing is now done for the first argument of a routine
-    call if overloading resolution produces no match otherwise. This feature
-    has to be enabled with the `experimental`_ pragma.
-  - Objects that do not use inheritance nor ``case`` can be put into ``const``
-    sections. This means that finally this is possible and produces rather
-    nice code:
 
-  .. code-block:: nim
-    import tables
+  Bugfixes
+  --------
+
 
-    const
-      foo = {"ah": "finally", "this": "is", "possible.": "nice!"}.toTable()
+2015-05-04 Version 0.11.2 released
+==================================
 
+This is just a bugfix release that fixes the most pressing regressions we
+introduced with version 0.11.0. The way types are computed was
+changed significantly causing all sort of problems. Sorry for the
+inconvenience; we grew overconfident our large test suite would prevent these
+things.
 
-  - Ordinary parameters can follow after a varargs parameter. This means the
-    following is finally accepted by the compiler:
 
-  .. code-block:: nim
-    template takesBlock(a, b: int, x: varargs[expr]; blck: stmt) =
-      blck
-      echo a, b
+2015-04-30 Version 0.11.0 released
+==================================
 
-    takesBlock 1, 2, "some", 0.90, "random stuff":
-      echo "yay"
+With this release we are one step closer to reaching version 1.0 and by
+extension the persistence of the Nim specification. As mentioned in the
+previous release notes, starting with version 1.0, we will not be introducing
+any more breaking changes to Nim.
 
-  - Overloading by 'var T' is now finally possible:
+The *language* itself is very close to 1.0, the primary area that requires
+more work is the standard library.
 
-  .. code-block:: nim
-    proc varOrConst(x: var int) = echo "var"
-    proc varOrConst(x: int) = echo "const"
+Take a look at the `download <download.html>`_ page for binaries (Windows-only)
+and 0.11.0 snapshots of the source code. The Windows installer now also
+includes `Aporia <https://github.com/nim-lang/aporia>`_,
+`Nimble <https://github.com/nim-lang/nimble>`_ and other useful tools to get
+you started with Nim.
 
-    var x: int
-    varOrConst(x) # "var"
-    varOrConst(45) # "const"
+What's left to be done
+~~~~~~~~~~~~~~~~~~~~~~
 
-  - Array and seq indexing can now use the builtin ``^`` operator to access
-    things from backwards: ``a[^1]`` is like Python's ``a[-1]``.
-  - A first version of the specification and implementation of the overloading
-    of the assignment operator has arrived!
-  - ``system.len`` for strings and sequences now returns 0 for nil.
+The 1.0 release is expected by the end of this year. Rumors say it will be in
+summer 2015. What's left:
 
-  - A single underscore can now be used to discard values when unpacking tuples.
+* Bug fixes, bug fixes, bug fixes, in particular:
+  - The remaining bugs of the lambda lifting pass that is responsible to enable
+    closures and closure iterators need to be fixed.
+  - ``concept`` needs to be refined, a nice name for the feature is not enough.
+  - Destructors need to be refined.
+  - ``static[T]`` needs to be fixed.
+  - Finish the implementation of the 'parallel' statement.
+* ``immediate`` templates and macros will be deprecated as these will soon be
+  completely unnecessary, instead the ``typed`` or ``untyped`` metatypes can
+  be used.
+* More of the standard library should be moved to Nimble packages and what's
+  left should use the features we have for concurrency and parallelism.
 
 
-  Library additions
-  -----------------
 
-  - ``reversed`` proc added to the ``unicode`` module.
-  - Added multipart param to httpclient's ``post`` and ``postContent`` together
-    with a ``newMultipartData`` proc.
-  - Added `%*` operator for JSON.
-  - The compiler is now available as Nimble package for c2nim.
-  - Added ``..^`` and ``..<`` templates to system so that the rather annoying
-    space between ``.. <`` and ``.. ^`` is not necessary anymore.
-  - Added ``system.xlen`` for strings and sequences to get back the old ``len``
-    operation that doesn't check for ``nil`` for efficiency.
+Changes affecting backwards compatibility
+-----------------------------------------
 
+- Parameter names are finally properly ``gensym``'ed. This can break
+  templates though that used to rely on the fact that they are not.
+  (Bug #1915.) This means this doesn't compile anymore:
 
-  Bugfixes
-  --------
+.. code-block:: nim
+
+  template doIt(body: stmt) {.immediate.} =
+    # this used to inject the 'str' parameter:
+    proc res(str: string) =
+      body
+
+  doIt:
+    echo str # Error: undeclared identifier: 'str'
+..
+
+  This used to inject the ``str`` parameter into the scope of the body.
+  Declare the ``doIt`` template as ``immediate, dirty`` to get the old
+  behaviour.
+- Tuple field names are not ignored anymore, this caused too many problems
+  in practice so now the behaviour is as it was for version 0.9.6: If field
+  names exist for the tuple type, they are checked.
+- ``logging.level`` and ``logging.handlers`` are no longer exported.
+  ``addHandler``, ``getHandlers``, ``setLogFilter`` and ``getLogFilter``
+  should be used instead.
+- ``nim idetools`` has been replaced by a separate
+  tool `nimsuggest <0.11.0/nimsuggest.html>`_.
+- *arrow like* operators are not right associative anymore and are required
+  to end with either ``->``, ``~>`` or
+  ``=>``, not just ``>``. Examples of operators still considered arrow like:
+  ``->``, ``==>``, ``+=>``. On the other hand, the following operators are now
+  considered regular operators again: ``|>``, ``-+>``, etc.
+- Typeless parameters are now only allowed in templates and macros. The old
+  way turned out to be too error-prone.
+- The 'addr' and 'type' operators are now parsed as unary function
+  application. This means ``type(x).name`` is now parsed as ``(type(x)).name``
+  and not as ``type((x).name)``. Note that this also affects the AST
+  structure; for immediate macro parameters ``nkCall('addr', 'x')`` is
+  produced instead of ``nkAddr('x')``.
+- ``concept`` is now a keyword and is used instead of ``generic``.
+- The ``inc``, ``dec``, ``+=``, ``-=`` builtins now produce OverflowError
+  exceptions. This means code like the following:
+
+.. code-block:: nim
+  var x = low(T)
+  while x <= high(T):
+    echo x
+    inc x
+
+Needs to be replaced by something like this:
+
+.. code-block:: nim
+  var x = low(T).int
+  while x <= high(T).int:
+    echo x.T
+    inc x
+
+- **Negative indexing for slicing does not work anymore!** Instead
+  of ``a[0.. -1]`` you can
+  use ``a[0.. ^1]``. This also works with accessing a single
+  element ``a[^1]``. Note that we cannot detect this reliably as it is
+  determined at **runtime** whether negative indexing is used!
+  ``a[0.. -1]`` now produces the empty string/sequence.
+- The compiler now warns about code like ``foo +=1`` which uses inconsistent
+  spacing around binary operators. Later versions of the language will parse
+  these as unary operators instead so that ``echo $foo`` finally can do what
+  people expect it to do.
+- ``system.untyped`` and ``system.typed`` have been introduced as aliases
+  for ``expr`` and ``stmt``. The new names capture the semantics much better
+  and most likely  ``expr`` and ``stmt`` will be deprecated in favor of the
+  new names.
+- The ``split`` method in module ``re`` has changed. It now handles the case
+  of matches having a length of 0, and empty strings being yielded from the
+  iterator. A notable change might be that a pattern being matched at the
+  beginning and end of a string, will result in an empty string being produced
+  at the start and the end of the iterator.
+- The compiler and nimsuggest now count columns starting with 1, not 0 for
+  consistency with the rest of the world.
+
+
+Language Additions
+------------------
+
+- For empty ``case object`` branches ``discard`` can finally be used instead
+  of ``nil``.
+- Automatic dereferencing is now done for the first argument of a routine
+  call if overloading resolution produces no match otherwise. This feature
+  has to be enabled with
+  the `experimental <0.11.0/manual.html#pragmas-experimental-pragma>`_ pragma.
+- Objects that do not use inheritance nor ``case`` can be put into ``const``
+  sections. This means that finally this is possible and produces rather
+  nice code:
+
+.. code-block:: nim
+  import tables
+
+  const
+    foo = {"ah": "finally", "this": "is", "possible.": "nice!"}.toTable()
+
+
+- Ordinary parameters can follow after a varargs parameter. This means the
+  following is finally accepted by the compiler:
+
+.. code-block:: nim
+  template takesBlock(a, b: int, x: varargs[expr]; blck: stmt) =
+    blck
+    echo a, b
+
+  takesBlock 1, 2, "some", 0.90, "random stuff":
+    echo "yay"
+
+- Overloading by 'var T' is now finally possible:
+
+.. code-block:: nim
+  proc varOrConst(x: var int) = echo "var"
+  proc varOrConst(x: int) = echo "const"
+
+  var x: int
+  varOrConst(x) # "var"
+  varOrConst(45) # "const"
+
+- Array and seq indexing can now use the builtin ``^`` operator to access
+  things from backwards: ``a[^1]`` is like Python's ``a[-1]``.
+- A first version of the specification and implementation of the overloading
+  of the assignment operator has arrived!
+- ``system.len`` for strings and sequences now returns 0 for nil.
+
+- A single underscore can now be used to discard values when unpacking tuples:
+
+.. code-block:: nim
+  let (path, _, _) = os.splitFile("path/file.ext")
+
+
+- ``marshal.$$`` and ``marshal.to`` can be executed at compile-time.
+- Interoperability with C++ improved tremendously; C++'s templates and
+  operators can be wrapped directly. See
+  `this <0.11.0/nimc.html#additional-features-importcpp-pragma>`_
+  for more information.
+- ``macros.getType`` can be used to query an AST's type at compile-time. This
+  enables more powerful macros, for instance *currying* can now be done with
+  a macro.
+
+
+Library additions
+-----------------
+
+- ``reversed`` proc added to the ``unicode`` module.
+- Added multipart param to httpclient's ``post`` and ``postContent`` together
+  with a ``newMultipartData`` proc.
+- Added `%*` operator for JSON.
+- The compiler is now available as Nimble package for c2nim.
+- Added ``..^`` and ``..<`` templates to system so that the rather annoying
+  space between ``.. <`` and ``.. ^`` is not necessary anymore.
+- Added ``system.xlen`` for strings and sequences to get back the old ``len``
+  operation that doesn't check for ``nil`` for efficiency.
+
+
+Bugfixes
+--------
+
+- Fixed internal compiler error when using ``char()`` in an echo call
+  (`#1788 <https://github.com/Araq/Nim/issues/1788>`_).
+- Fixed Windows cross-compilation on Linux.
+- Overload resolution now works for types distinguished only by a
+  ``static[int]`` param
+  (`#1056 <https://github.com/Araq/Nim/issues/1056>`_).
+- Other fixes relating to generic types and static params.
+- Fixed some compiler crashes with unnamed tuples
+  (`#1774 <https://github.com/Araq/Nim/issues/1774>`_).
+- Fixed ``channels.tryRecv`` blocking
+  (`#1816 <https://github.com/Araq/Nim/issues/1816>`_).
+- Fixed generic instantiation errors with ``typedesc``
+  (`#419 <https://github.com/Araq/Nim/issues/419>`_).
+- Fixed generic regression where the compiler no longer detected constant
+  expressions properly (`#544 <https://github.com/Araq/Nim/issues/544>`_).
+- Fixed internal error with generic proc using ``static[T]`` in a specific
+  way (`#1049 <https://github.com/Araq/Nim/issues/1049>`_).
+- More fixes relating to generics (`#1820 <https://github.com/Araq/Nim/issues/1820>`_,
+  `#1050 <https://github.com/Araq/Nim/issues/1050>`_,
+  `#1859 <https://github.com/Araq/Nim/issues/1859>`_,
+  `#1858 <https://github.com/Araq/Nim/issues/1858>`_).
+- Fixed httpclient to properly encode queries.
+- Many fixes to the ``uri`` module.
+- Async sockets are now closed on error.
+- Fixes to httpclient's handling of multipart data.
+- Fixed GC segfaults with asynchronous sockets
+  (`#1796 <https://github.com/Araq/Nim/issues/1796>`_).
+- Added more versions to openssl's DLL version list
+  (`076f993 <https://github.com/Araq/Nim/commit/076f993>`_).
+- Fixed shallow copy in iterators being broken
+  (`#1803 <https://github.com/Araq/Nim/issues/1803>`_).
+- ``nil`` can now be inserted into tables with the ``db_sqlite`` module
+  (`#1866 <https://github.com/Araq/Nim/issues/1866>`_).
+- Fixed "Incorrect assembler generated"
+  (`#1907 <https://github.com/Araq/Nim/issues/1907>`_)
+- Fixed "Expression templates that define macros are unusable in some contexts"
+  (`#1903 <https://github.com/Araq/Nim/issues/1903>`_)
+- Fixed "a second level generic subclass causes the compiler to crash"
+  (`#1919 <https://github.com/Araq/Nim/issues/1919>`_)
+- Fixed "nim 0.10.2 generates invalid AsyncHttpClient C code for MSVC "
+  (`#1901 <https://github.com/Araq/Nim/issues/1901>`_)
+- Fixed "1 shl n produces wrong C code"
+  (`#1928 <https://github.com/Araq/Nim/issues/1928>`_)
+- Fixed "Internal error on tuple yield"
+  (`#1838 <https://github.com/Araq/Nim/issues/1838>`_)
+- Fixed "ICE with template"
+  (`#1915 <https://github.com/Araq/Nim/issues/1915>`_)
+- Fixed "include the tool directory in the installer as it is required by koch"
+  (`#1947 <https://github.com/Araq/Nim/issues/1947>`_)
+- Fixed "Can't compile if file location contains spaces on Windows"
+  (`#1955 <https://github.com/Araq/Nim/issues/1955>`_)
+- Fixed "List comprehension macro only supports infix checks as guards"
+  (`#1920 <https://github.com/Araq/Nim/issues/1920>`_)
+- Fixed "wrong field names of compatible tuples in generic types"
+  (`#1910 <https://github.com/Araq/Nim/issues/1910>`_)
+- Fixed "Macros within templates no longer work as expected"
+  (`#1944 <https://github.com/Araq/Nim/issues/1944>`_)
+- Fixed "Compiling for Standalone AVR broken in 0.10.2"
+  (`#1964 <https://github.com/Araq/Nim/issues/1964>`_)
+- Fixed "Compiling for Standalone AVR broken in 0.10.2"
+  (`#1964 <https://github.com/Araq/Nim/issues/1964>`_)
+- Fixed "Code generation for mitems with tuple elements"
+  (`#1833 <https://github.com/Araq/Nim/issues/1833>`_)
+- Fixed "httpclient.HttpMethod should not be an enum"
+  (`#1962 <https://github.com/Araq/Nim/issues/1962>`_)
+- Fixed "terminal / eraseScreen() throws an OverflowError"
+  (`#1906 <https://github.com/Araq/Nim/issues/1906>`_)
+- Fixed "setControlCHook(nil) disables registered quit procs"
+  (`#1546 <https://github.com/Araq/Nim/issues/1546>`_)
+- Fixed "Unexpected idetools behaviour"
+  (`#325 <https://github.com/Araq/Nim/issues/325>`_)
+- Fixed "Unused lifted lambda does not compile"
+  (`#1642 <https://github.com/Araq/Nim/issues/1642>`_)
+- Fixed "'low' and 'high' don't work with cstring asguments"
+  (`#2030 <https://github.com/Araq/Nim/issues/2030>`_)
+- Fixed "Converting to int does not round in JS backend"
+  (`#1959 <https://github.com/Araq/Nim/issues/1959>`_)
+- Fixed "Internal error genRecordField 2 when adding region to pointer."
+  (`#2039 <https://github.com/Araq/Nim/issues/2039>`_)
+- Fixed "Macros fail to compile when compiled with --os:standalone"
+  (`#2041 <https://github.com/Araq/Nim/issues/2041>`_)
+- Fixed "Reading from {.compileTime.} variables can cause code generation to fail"
+  (`#2022 <https://github.com/Araq/Nim/issues/2022>`_)
+- Fixed "Passing overloaded symbols to templates fails inside generic procedures"
+  (`#1988 <https://github.com/Araq/Nim/issues/1988>`_)
+- Fixed "Compiling iterator with object assignment in release mode causes "var not init""
+  (`#2023 <https://github.com/Araq/Nim/issues/2023>`_)
+- Fixed "calling a large number of macros doing some computation fails"
+  (`#1989 <https://github.com/Araq/Nim/issues/1989>`_)
+- Fixed "Can't get Koch to install nim under Windows"
+  (`#2061 <https://github.com/Araq/Nim/issues/2061>`_)
+- Fixed "Template with two stmt parameters segfaults compiler"
+  (`#2057 <https://github.com/Araq/Nim/issues/2057>`_)
+- Fixed "`noSideEffect` not affected by `echo`"
+  (`#2011 <https://github.com/Araq/Nim/issues/2011>`_)
+- Fixed "Compiling with the cpp backend ignores --passc"
+  (`#1601 <https://github.com/Araq/Nim/issues/1601>`_)
+- Fixed "Put untyped procedure parameters behind the experimental pragma"
+  (`#1956 <https://github.com/Araq/Nim/issues/1956>`_)
+- Fixed "generic regression"
+  (`#2073 <https://github.com/Araq/Nim/issues/2073>`_)
+- Fixed "generic regression"
+  (`#2073 <https://github.com/Araq/Nim/issues/2073>`_)
+- Fixed "Regression in template lookup with generics"
+  (`#2004 <https://github.com/Araq/Nim/issues/2004>`_)
+- Fixed "GC's growObj is wrong for edge cases"
+  (`#2070 <https://github.com/Araq/Nim/issues/2070>`_)
+- Fixed "Compiler internal error when creating an array out of a typeclass"
+  (`#1131 <https://github.com/Araq/Nim/issues/1131>`_)
+- Fixed "GC's growObj is wrong for edge cases"
+  (`#2070 <https://github.com/Araq/Nim/issues/2070>`_)
+- Fixed "Invalid Objective-C code generated when calling class method"
+  (`#2068 <https://github.com/Araq/Nim/issues/2068>`_)
+- Fixed "walkDirRec Error"
+  (`#2116 <https://github.com/Araq/Nim/issues/2116>`_)
+- Fixed "Typo in code causes compiler SIGSEGV in evalAtCompileTime"
+  (`#2113 <https://github.com/Araq/Nim/issues/2113>`_)
+- Fixed "Regression on exportc"
+  (`#2118 <https://github.com/Araq/Nim/issues/2118>`_)
+- Fixed "Error message"
+  (`#2102 <https://github.com/Araq/Nim/issues/2102>`_)
+- Fixed "hint[path] = off not working in nim.cfg"
+  (`#2103 <https://github.com/Araq/Nim/issues/2103>`_)
+- Fixed "compiler crashes when getting a tuple from a sequence of generic tuples"
+  (`#2121 <https://github.com/Araq/Nim/issues/2121>`_)
+- Fixed "nim check hangs with when"
+  (`#2123 <https://github.com/Araq/Nim/issues/2123>`_)
+- Fixed "static[T] param in nested type resolve/caching issue"
+  (`#2125 <https://github.com/Araq/Nim/issues/2125>`_)
+- Fixed "repr should display ``\0``"
+  (`#2124 <https://github.com/Araq/Nim/issues/2124>`_)
+- Fixed "'nim check' never ends in case of recursive dependency "
+  (`#2051 <https://github.com/Araq/Nim/issues/2051>`_)
+- Fixed "From macros: Error: unhandled exception: sons is not accessible"
+  (`#2167 <https://github.com/Araq/Nim/issues/2167>`_)
+- Fixed "`fieldPairs` doesn't work inside templates"
+  (`#1902 <https://github.com/Araq/Nim/issues/1902>`_)
+- Fixed "fields iterator misbehavior on break statement"
+  (`#2134 <https://github.com/Araq/Nim/issues/2134>`_)
+- Fixed "Fix for compiler not building anymore since #c3244ef1ff"
+  (`#2193 <https://github.com/Araq/Nim/issues/2193>`_)
+- Fixed "JSON parser fails in cpp output mode"
+  (`#2199 <https://github.com/Araq/Nim/issues/2199>`_)
+- Fixed "macros.getType mishandles void return"
+  (`#2211 <https://github.com/Araq/Nim/issues/2211>`_)
+- Fixed "Regression involving templates instantiated within generics"
+  (`#2215 <https://github.com/Araq/Nim/issues/2215>`_)
+- Fixed ""Error: invalid type" for 'not nil' on generic type."
+  (`#2216 <https://github.com/Araq/Nim/issues/2216>`_)
+- Fixed "--threads:on breaks async"
+  (`#2074 <https://github.com/Araq/Nim/issues/2074>`_)
+- Fixed "Type mismatch not always caught, can generate bad code for C backend."
+  (`#2169 <https://github.com/Araq/Nim/issues/2169>`_)
+- Fixed "Failed C compilation when storing proc to own type in object"
+  (`#2233 <https://github.com/Araq/Nim/issues/2233>`_)
+- Fixed "Unknown line/column number in constant declaration type conversion error"
+  (`#2252 <https://github.com/Araq/Nim/issues/2252>`_)
+- Fixed "Adding {.compile.} fails if nimcache already exists."
+  (`#2247 <https://github.com/Araq/Nim/issues/2247>`_)
+- Fixed "Two different type names generated for a single type (C backend)"
+  (`#2250 <https://github.com/Araq/Nim/issues/2250>`_)
+- Fixed "Ambigous call when it should not be"
+  (`#2229 <https://github.com/Araq/Nim/issues/2229>`_)
+- Fixed "Make sure we can load root urls"
+  (`#2227 <https://github.com/Araq/Nim/issues/2227>`_)
+- Fixed "Failure to slice a string with an int subrange type"
+  (`#794 <https://github.com/Araq/Nim/issues/794>`_)
+- Fixed "documentation error"
+  (`#2205 <https://github.com/Araq/Nim/issues/2205>`_)
+- Fixed "Code growth when using `const`"
+  (`#1940 <https://github.com/Araq/Nim/issues/1940>`_)
+- Fixed "Instances of generic types confuse overload resolution"
+  (`#2220 <https://github.com/Araq/Nim/issues/2220>`_)
+- Fixed "Compiler error when initializing sdl2's EventType"
+  (`#2316 <https://github.com/Araq/Nim/issues/2316>`_)
+- Fixed "Parallel disjoint checking can't handle `<`, `items`, or arrays"
+  (`#2287 <https://github.com/Araq/Nim/issues/2287>`_)
+- Fixed "Strings aren't copied in parallel loop"
+  (`#2286 <https://github.com/Araq/Nim/issues/2286>`_)
+- Fixed "JavaScript compiler crash with tables"
+  (`#2298 <https://github.com/Araq/Nim/issues/2298>`_)
+- Fixed "Range checker too restrictive"
+  (`#1845 <https://github.com/Araq/Nim/issues/1845>`_)
+- Fixed "Failure to slice a string with an int subrange type"
+  (`#794 <https://github.com/Araq/Nim/issues/794>`_)
+- Fixed "Remind user when compiling in debug mode"
+  (`#1868 <https://github.com/Araq/Nim/issues/1868>`_)
+- Fixed "Compiler user guide has jumbled options/commands."
+  (`#1819 <https://github.com/Araq/Nim/issues/1819>`_)
+- Fixed "using `method`: 1 in a objects constructor fails when compiling"
+  (`#1791 <https://github.com/Araq/Nim/issues/1791>`_)
 
-  - Fixed internal compiler error when using ``char()`` in an echo call
-    (`#1788 <https://github.com/Araq/Nim/issues/1788>`_).
-  - Fixed Windows cross-compilation on Linux.
-  - Overload resolution now works for types distinguished only by a
-    ``static[int]`` param
-    (`#1056 <https://github.com/Araq/Nim/issues/1056>`_).
-  - Other fixes relating to generic types and static params.
-  - Fixed some compiler crashes with unnamed tuples
-    (`#1774 <https://github.com/Araq/Nim/issues/1774>`_).
-  - Fixed ``channels.tryRecv`` blocking
-    (`#1816 <https://github.com/Araq/Nim/issues/1816>`_).
-  - Fixed generic instantiation errors with ``typedesc``
-    (`#419 <https://github.com/Araq/Nim/issues/419>`_).
-  - Fixed generic regression where the compiler no longer detected constant
-    expressions properly (`#544 <https://github.com/Araq/Nim/issues/544>`_).
-  - Fixed internal error with generic proc using ``static[T]`` in a specific
-    way (`#1049 <https://github.com/Araq/Nim/issues/1049>`_).
-  - More fixes relating to generics
-    (`#1820 <https://github.com/Araq/Nim/issues/1820>`_,
-     `#1050 <https://github.com/Araq/Nim/issues/1050>`_,
-     `#1859 <https://github.com/Araq/Nim/issues/1859>`_,
-     `#1858 <https://github.com/Araq/Nim/issues/1858>`_).
-  - Fixed httpclient to properly encode queries.
-  - Many fixes to the ``uri`` module.
-  - Async sockets are now closed on error.
-  - Fixes to httpclient's handling of multipart data.
-  - Fixed GC segfaults with asynchronous sockets
-    (`#1796 <https://github.com/Araq/Nim/issues/1796>`_).
-  - Added more versions to openssl's DLL version list
-    (`076f993 <https://github.com/Araq/Nim/commit/076f993>`_).
-  - Fixed shallow copy in iterators being broken
-    (`#1803 <https://github.com/Araq/Nim/issues/1803>`_).
-  - ``nil`` can now be inserted into tables with the ``db_sqlite`` module
-    (`#1866 <https://github.com/Araq/Nim/issues/1866>`_).
-  - Fixed "Incorrect assembler generated"
-    (`#1907 <https://github.com/Araq/Nim/issues/1907>`_)
-  - Fixed "Expression templates that define macros are unusable in some contexts"
-    (`#1903 <https://github.com/Araq/Nim/issues/1903>`_)
-  - Fixed "a second level generic subclass causes the compiler to crash"
-    (`#1919 <https://github.com/Araq/Nim/issues/1919>`_)
-  - Fixed "nim 0.10.2 generates invalid AsyncHttpClient C code for MSVC "
-    (`#1901 <https://github.com/Araq/Nim/issues/1901>`_)
-  - Fixed "1 shl n produces wrong C code"
-    (`#1928 <https://github.com/Araq/Nim/issues/1928>`_)
-  - Fixed "Internal error on tuple yield"
-    (`#1838 <https://github.com/Araq/Nim/issues/1838>`_)
-  - Fixed "ICE with template"
-    (`#1915 <https://github.com/Araq/Nim/issues/1915>`_)
-  - Fixed "include the tool directory in the installer as it is required by koch"
-    (`#1947 <https://github.com/Araq/Nim/issues/1947>`_)
-  - Fixed "Can't compile if file location contains spaces on Windows"
-    (`#1955 <https://github.com/Araq/Nim/issues/1955>`_)
-  - Fixed "List comprehension macro only supports infix checks as guards"
-    (`#1920 <https://github.com/Araq/Nim/issues/1920>`_)
-  - Fixed "wrong field names of compatible tuples in generic types"
-    (`#1910 <https://github.com/Araq/Nim/issues/1910>`_)
-  - Fixed "Macros within templates no longer work as expected"
-    (`#1944 <https://github.com/Araq/Nim/issues/1944>`_)
-  - Fixed "Compiling for Standalone AVR broken in 0.10.2"
-    (`#1964 <https://github.com/Araq/Nim/issues/1964>`_)
-  - Fixed "Compiling for Standalone AVR broken in 0.10.2"
-    (`#1964 <https://github.com/Araq/Nim/issues/1964>`_)
-  - Fixed "Code generation for mitems with tuple elements"
-    (`#1833 <https://github.com/Araq/Nim/issues/1833>`_)
-  - Fixed "httpclient.HttpMethod should not be an enum"
-    (`#1962 <https://github.com/Araq/Nim/issues/1962>`_)
-  - Fixed "terminal / eraseScreen() throws an OverflowError"
-    (`#1906 <https://github.com/Araq/Nim/issues/1906>`_)
-  - Fixed "setControlCHook(nil) disables registered quit procs"
-    (`#1546 <https://github.com/Araq/Nim/issues/1546>`_)
-  - Fixed "Unexpected idetools behaviour"
-    (`#325 <https://github.com/Araq/Nim/issues/325>`_)
-  - Fixed "Unused lifted lambda does not compile"
-    (`#1642 <https://github.com/Araq/Nim/issues/1642>`_)
-  - Fixed "'low' and 'high' don't work with cstring asguments"
-    (`#2030 <https://github.com/Araq/Nim/issues/2030>`_)
-  - Fixed "Converting to int does not round in JS backend"
-    (`#1959 <https://github.com/Araq/Nim/issues/1959>`_)
-  - Fixed "Internal error genRecordField 2 when adding region to pointer."
-    (`#2039 <https://github.com/Araq/Nim/issues/2039>`_)
-  - Fixed "Macros fail to compile when compiled with --os:standalone"
-    (`#2041 <https://github.com/Araq/Nim/issues/2041>`_)
-  - Fixed "Reading from {.compileTime.} variables can cause code generation to fail"
-    (`#2022 <https://github.com/Araq/Nim/issues/2022>`_)
-  - Fixed "Passing overloaded symbols to templates fails inside generic procedures"
-    (`#1988 <https://github.com/Araq/Nim/issues/1988>`_)
-  - Fixed "Compiling iterator with object assignment in release mode causes "var not init""
-    (`#2023 <https://github.com/Araq/Nim/issues/2023>`_)
-  - Fixed "calling a large number of macros doing some computation fails"
-    (`#1989 <https://github.com/Araq/Nim/issues/1989>`_)
-  - Fixed "Can't get Koch to install nim under Windows"
-    (`#2061 <https://github.com/Araq/Nim/issues/2061>`_)
-  - Fixed "Template with two stmt parameters segfaults compiler"
-    (`#2057 <https://github.com/Araq/Nim/issues/2057>`_)
-  - Fixed "`noSideEffect` not affected by `echo`"
-    (`#2011 <https://github.com/Araq/Nim/issues/2011>`_)
-  - Fixed "Compiling with the cpp backend ignores --passc"
-    (`#1601 <https://github.com/Araq/Nim/issues/1601>`_)
-  - Fixed "Put untyped procedure parameters behind the experimental pragma"
-    (`#1956 <https://github.com/Araq/Nim/issues/1956>`_)
-  - Fixed "generic regression"
-    (`#2073 <https://github.com/Araq/Nim/issues/2073>`_)
-  - Fixed "generic regression"
-    (`#2073 <https://github.com/Araq/Nim/issues/2073>`_)
-  - Fixed "Regression in template lookup with generics"
-    (`#2004 <https://github.com/Araq/Nim/issues/2004>`_)
-  - Fixed "GC's growObj is wrong for edge cases"
-    (`#2070 <https://github.com/Araq/Nim/issues/2070>`_)
-  - Fixed "Compiler internal error when creating an array out of a typeclass"
-    (`#1131 <https://github.com/Araq/Nim/issues/1131>`_)
-  - Fixed "GC's growObj is wrong for edge cases"
-    (`#2070 <https://github.com/Araq/Nim/issues/2070>`_)
-  - Fixed "Invalid Objective-C code generated when calling class method"
-    (`#2068 <https://github.com/Araq/Nim/issues/2068>`_)
-  - Fixed "walkDirRec Error"
-    (`#2116 <https://github.com/Araq/Nim/issues/2116>`_)
-  - Fixed "Typo in code causes compiler SIGSEGV in evalAtCompileTime"
-    (`#2113 <https://github.com/Araq/Nim/issues/2113>`_)
-  - Fixed "Regression on exportc"
-    (`#2118 <https://github.com/Araq/Nim/issues/2118>`_)
-  - Fixed "Error message"
-    (`#2102 <https://github.com/Araq/Nim/issues/2102>`_)
-  - Fixed "hint[path] = off not working in nim.cfg"
-    (`#2103 <https://github.com/Araq/Nim/issues/2103>`_)
-  - Fixed "compiler crashes when getting a tuple from a sequence of generic tuples"
-    (`#2121 <https://github.com/Araq/Nim/issues/2121>`_)
-  - Fixed "nim check hangs with when"
-    (`#2123 <https://github.com/Araq/Nim/issues/2123>`_)
-  - Fixed "static[T] param in nested type resolve/caching issue"
-    (`#2125 <https://github.com/Araq/Nim/issues/2125>`_)
-  - Fixed "repr should display ``\0``"
-    (`#2124 <https://github.com/Araq/Nim/issues/2124>`_)
-  - Fixed "'nim check' never ends in case of recursive dependency "
-    (`#2051 <https://github.com/Araq/Nim/issues/2051>`_)
-  - Fixed "From macros: Error: unhandled exception: sons is not accessible"
-    (`#2167 <https://github.com/Araq/Nim/issues/2167>`_)
-  - Fixed "`fieldPairs` doesn't work inside templates"
-    (`#1902 <https://github.com/Araq/Nim/issues/1902>`_)
-  - Fixed "fields iterator misbehavior on break statement"
-    (`#2134 <https://github.com/Araq/Nim/issues/2134>`_)
-  - Fixed "Fix for compiler not building anymore since #c3244ef1ff"
-    (`#2193 <https://github.com/Araq/Nim/issues/2193>`_)
-  - Fixed "JSON parser fails in cpp output mode"
-    (`#2199 <https://github.com/Araq/Nim/issues/2199>`_)
-  - Fixed "macros.getType mishandles void return"
-    (`#2211 <https://github.com/Araq/Nim/issues/2211>`_)
-  - Fixed "Regression involving templates instantiated within generics"
-    (`#2215 <https://github.com/Araq/Nim/issues/2215>`_)
-  - Fixed ""Error: invalid type" for 'not nil' on generic type."
-    (`#2216 <https://github.com/Araq/Nim/issues/2216>`_)
-  - Fixed "--threads:on breaks async"
-    (`#2074 <https://github.com/Araq/Nim/issues/2074>`_)
-  - Fixed "Type mismatch not always caught, can generate bad code for C backend."
-    (`#2169 <https://github.com/Araq/Nim/issues/2169>`_)
-  - Fixed "Failed C compilation when storing proc to own type in object"
-    (`#2233 <https://github.com/Araq/Nim/issues/2233>`_)
-  - Fixed "Unknown line/column number in constant declaration type conversion error"
-    (`#2252 <https://github.com/Araq/Nim/issues/2252>`_)
-  - Fixed "Adding {.compile.} fails if nimcache already exists."
-    (`#2247 <https://github.com/Araq/Nim/issues/2247>`_)
-  - Fixed "Two different type names generated for a single type (C backend)"
-    (`#2250 <https://github.com/Araq/Nim/issues/2250>`_)
-  - Fixed "Ambigous call when it should not be"
-    (`#2229 <https://github.com/Araq/Nim/issues/2229>`_)
-  - Fixed "Make sure we can load root urls"
-    (`#2227 <https://github.com/Araq/Nim/issues/2227>`_)
-  - Fixed "Failure to slice a string with an int subrange type"
-    (`#794 <https://github.com/Araq/Nim/issues/794>`_)
-  - Fixed "documentation error"
-    (`#2205 <https://github.com/Araq/Nim/issues/2205>`_)
-  - Fixed "Code growth when using `const`"
-    (`#1940 <https://github.com/Araq/Nim/issues/1940>`_)
-  - Fixed "Instances of generic types confuse overload resolution"
-    (`#2220 <https://github.com/Araq/Nim/issues/2220>`_)
-  - Fixed "Compiler error when initializing sdl2's EventType"
-    (`#2316 <https://github.com/Araq/Nim/issues/2316>`_)
-  - Fixed "Parallel disjoint checking can't handle `<`, `items`, or arrays"
-    (`#2287 <https://github.com/Araq/Nim/issues/2287>`_)
-  - Fixed "Strings aren't copied in parallel loop"
-    (`#2286 <https://github.com/Araq/Nim/issues/2286>`_)
-  - Fixed "JavaScript compiler crash with tables"
-    (`#2298 <https://github.com/Araq/Nim/issues/2298>`_)
-  - Fixed "Range checker too restrictive"
-    (`#1845 <https://github.com/Araq/Nim/issues/1845>`_)
-  - Fixed "Failure to slice a string with an int subrange type"
-    (`#794 <https://github.com/Araq/Nim/issues/794>`_)
-  - Fixed "Remind user when compiling in debug mode"
-    (`#1868 <https://github.com/Araq/Nim/issues/1868>`_)
-  - Fixed "Compiler user guide has jumbled options/commands."
-    (`#1819 <https://github.com/Araq/Nim/issues/1819>`_)
-  - Fixed "using `method`: 1 in a objects constructor fails when compiling"
-    (`#1791 <https://github.com/Araq/Nim/issues/1791>`_)
 
 2014-12-29 Version 0.10.2 released
 ==================================
diff --git a/web/question.txt b/web/question.txt
index 0733a2455..c4d997922 100644
--- a/web/question.txt
+++ b/web/question.txt
@@ -16,11 +16,11 @@ General FAQ
   language that tries to give the programmer ultimate power without compromises
   on runtime efficiency.
   This means it focuses on compile-time mechanisms in all their
-  various forms. Beneath a nice infix/indentation based syntax with a 
-  powerful (AST based, hygienic) macro system lies a semantic model that supports 
-  a soft realtime GC on thread local heaps. Asynchronous message passing is used 
-  between threads, so no "stop the world" mechanism is necessary. An unsafe 
-  shared memory heap is also provided for the increased efficiency that results 
+  various forms. Beneath a nice infix/indentation based syntax with a
+  powerful (AST based, hygienic) macro system lies a semantic model that supports
+  a soft realtime GC on thread local heaps. Asynchronous message passing is used
+  between threads, so no "stop the world" mechanism is necessary. An unsafe
+  shared memory heap is also provided for the increased efficiency that results
   from that model.
 
 
@@ -29,8 +29,8 @@ General FAQ
   Why yet another programming language?
   -------------------------------------
 
-  Nim is one of the very few *programmable* statically typed languages, and 
-  one of the even fewer that produces native binaries that require no 
+  Nim is one of the very few *programmable* statically typed languages, and
+  one of the even fewer that produces native binaries that require no
   runtime or interpreter.
 
 
@@ -48,12 +48,12 @@ General FAQ
   What is Nim's take on concurrency?
   ----------------------------------
 
-  Nim primarily focusses on thread local (and garbage collected) heaps and 
-  message passing between threads. Each thread has its own GC, so no 
+  Nim primarily focusses on thread local (and garbage collected) heaps and
+  message passing between threads. Each thread has its own GC, so no
   "stop the world" mechanism is necessary. An unsafe shared memory heap is also
   provided.
 
-  Future versions will additionally include a GC "per thread group" 
+  Future versions will additionally include a GC "per thread group"
   and Nim's type system will be enhanced to accurately model this shared
   memory heap.
 
@@ -74,7 +74,7 @@ General FAQ
   ------------------
 
   The compiler is in development and some important features are still missing.
-  However, the compiler is quite stable already: It is able to compile itself 
+  However, the compiler is quite stable already: It is able to compile itself
   and a substantial body of other code. Until version 1.0.0 is released,
   minor incompatibilities with older versions of the compiler will be introduced.
 
@@ -83,9 +83,9 @@ General FAQ
 
   How fast is Nim?
   ----------------
-  Benchmarks show it to be comparable to C. Some language features (methods, 
+  Benchmarks show it to be comparable to C. Some language features (methods,
   closures, message passing) are not yet as optimized as they could and will be.
-  The only overhead Nim has over C is the GC which has been tuned 
+  The only overhead Nim has over C is the GC which has been tuned
   for years but still needs some work.
 
 
@@ -96,7 +96,7 @@ General FAQ
 
   A JVM backend is almost impossible. The JVM is not expressive enough. It has
   never been designed as a general purpose VM anyway. A CLR backend is possible
-  but would require much work. 
+  but would require much work.
 
 
 .. container:: standout
@@ -112,6 +112,7 @@ General FAQ
   - jEdit: https://github.com/exhu/nimrod-misc/tree/master/jedit
   - TextMate: Available in bundle installer (`Repository <https://github.com/textmate/nim.tmbundle>`_)
   - Sublime Text: Available via Package Control (`Repository <https://github.com/Varriount/NimLime>`_)
+  - LiClipse: http://www.liclipse.com/ (Eclipse based plugin)
 
 
 .. container:: standout
diff --git a/web/ticker.txt b/web/ticker.txt
index 724d29231..4840e4039 100644
--- a/web/ticker.txt
+++ b/web/ticker.txt
@@ -1,13 +1,13 @@
+<a class="news" href="news.html#Z2015-05-04-version-0-11-2-released">
+  <h4>May 4, 2015</h4>
+  <p>Nim version 0.11.2 has been released!</p>
+</a>
+
 <a class="news" href="news.html#Z2014-12-29-version-0-10-2-released">
   <h4>Dec 29, 2014</h4>
   <p>Nim version 0.10.2 has been released!</p>
 </a>
 
-<a class="news" href="news.html#Z2014-12-09-new-website-design">
-  <h4>Dec 9, 2014</h4>
-  <p>The new website design and forum are now online!</p>
-</a>
-
 <a class="news" href="news.html#Z2014-02-11-nimrod-featured-in-dr-dobb-s-journal">
   <h4>Feb 11, 2014</h4>
   <p>Nimrod featured in Dr. Dobb's Journal</p>
diff --git a/web/website.ini b/web/website.ini
index 6266f05bb..bb9f1b204 100644
--- a/web/website.ini
+++ b/web/website.ini
@@ -31,7 +31,7 @@ file: ticker.txt
 [Documentation]
 doc: "endb;intern;apis;lib;manual.txt;tut1;tut2;nimc;overview;filters"
 doc: "tools;niminst;nimgrep;gc;estp;idetools;docgen;koch;backends.txt"
-doc: "nimfix.txt"
+doc: "nimfix.txt;nimsuggest.txt"
 pdf: "manual.txt;lib;tut1;tut2;nimc;niminst;gc"
 srcdoc2: "system.nim"
 srcdoc2: "core/macros;pure/marshal;core/typeinfo;core/unsigned"
@@ -49,7 +49,7 @@ srcdoc2: "pure/httpserver;pure/httpclient;pure/smtp;impure/ssl;pure/fsmonitor"
 srcdoc2: "pure/ropes;pure/unidecode/unidecode;pure/xmldom;pure/xmldomparser"
 srcdoc2: "pure/xmlparser;pure/htmlparser;pure/xmltree;pure/colors;pure/mimetypes"
 srcdoc2: "pure/json;pure/base64;pure/scgi;pure/redis;impure/graphics"
-srcdoc2: "impure/rdstdin"
+srcdoc2: "impure/rdstdin;impure/dialogs"
 srcdoc2: "pure/collections/tables;pure/collections/sets;pure/collections/lists"
 srcdoc2: "pure/collections/intsets;pure/collections/queues;pure/encodings"
 srcdoc2: "pure/events;pure/collections/sequtils;pure/cookies"
@@ -60,7 +60,7 @@ srcdoc2: "packages/docutils/rst;packages/docutils/rstast"
 srcdoc2: "packages/docutils/rstgen;pure/logging;pure/asyncdispatch;pure/asyncnet"
 srcdoc2: "pure/rawsockets;pure/asynchttpserver;pure/net;pure/selectors;pure/future"
 srcdoc2: "pure/asyncfile"
-srcdoc2: "pure/md5"
+srcdoc2: "pure/md5;pure/rationals"
 srcdoc2: "posix/posix"
 srcdoc2: "pure/fenv"
 srcdoc2: "pure/basic2d;pure/basic3d"