summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rw-r--r--.gitmodules3
-rwxr-xr-x[-rw-r--r--]build.sh4
-rw-r--r--compiler/ast.nim27
-rw-r--r--compiler/ccgcalls.nim13
-rw-r--r--compiler/ccgexprs.nim61
-rw-r--r--compiler/ccgstmts.nim76
-rw-r--r--compiler/ccgtypes.nim78
-rw-r--r--compiler/ccgutils.nim2
-rw-r--r--compiler/cgen.nim9
-rw-r--r--compiler/commands.nim4
-rw-r--r--compiler/condsyms.nim149
-rw-r--r--compiler/extccomp.nim109
-rw-r--r--compiler/guards.nim11
-rw-r--r--compiler/installer.ini114
-rw-r--r--compiler/jsgen.nim68
-rw-r--r--compiler/lexer.nim15
-rw-r--r--compiler/lowerings.nim4
-rw-r--r--compiler/main.nim2
-rw-r--r--compiler/modules.nim29
-rw-r--r--compiler/msgs.nim12
-rw-r--r--compiler/nim.nim9
-rw-r--r--compiler/nimfix/nimfix.nim.cfg2
-rw-r--r--compiler/nimsuggest/nimsuggest.nim207
-rw-r--r--compiler/nimsuggest/nimsuggest.nim.cfg2
-rw-r--r--compiler/options.nim22
-rw-r--r--compiler/parampatterns.nim2
-rw-r--r--compiler/parser.nim55
-rw-r--r--compiler/passes.nim6
-rw-r--r--compiler/plugins.nim43
-rw-r--r--compiler/plugins/active.nim13
-rw-r--r--compiler/plugins/locals/locals.nim42
-rw-r--r--compiler/pragmas.nim7
-rw-r--r--compiler/sem.nim6
-rw-r--r--compiler/semdata.nim13
-rw-r--r--compiler/semexprs.nim85
-rw-r--r--compiler/semfold.nim37
-rw-r--r--compiler/seminst.nim4
-rw-r--r--compiler/semmacrosanity.nim8
-rw-r--r--compiler/semmagic.nim38
-rw-r--r--compiler/sempass2.nim14
-rw-r--r--compiler/semstmts.nim15
-rw-r--r--compiler/semtypes.nim9
-rw-r--r--compiler/semtypinst.nim4
-rw-r--r--compiler/sigmatch.nim40
-rw-r--r--compiler/suggest.nim116
-rw-r--r--compiler/transf.nim6
-rw-r--r--compiler/trees.nim84
-rw-r--r--compiler/types.nim45
-rw-r--r--compiler/vm.nim34
-rw-r--r--compiler/vmdef.nim51
-rw-r--r--compiler/vmdeps.nim4
-rw-r--r--compiler/vmgen.nim61
-rw-r--r--compiler/vmmarshal.nim283
-rw-r--r--compiler/vmops.nim2
-rw-r--r--config/nim.cfg3
m---------csources0
-rw-r--r--doc/astspec.txt2
-rw-r--r--doc/grammar.txt2
-rw-r--r--doc/lib.txt51
-rw-r--r--doc/manual/lexing.txt2
-rw-r--r--doc/manual/stmts.txt74
-rw-r--r--doc/manual/syntax.txt17
-rw-r--r--doc/manual/threads.txt4
-rw-r--r--doc/manual/type_bound_ops.txt4
-rw-r--r--doc/nimc.txt40
-rw-r--r--doc/nimsuggest.txt174
-rw-r--r--doc/spawn.txt2
-rw-r--r--doc/tools.txt5
-rw-r--r--doc/tut1.txt76
-rw-r--r--koch.nim76
-rw-r--r--lib/core/macros.nim22
-rw-r--r--lib/impure/db_sqlite.nim2
-rw-r--r--lib/impure/graphics.nim2
-rw-r--r--lib/impure/rdstdin.nim2
-rw-r--r--lib/impure/re.nim59
-rw-r--r--lib/impure/ssl.nim2
-rw-r--r--lib/impure/zipfiles.nim86
-rw-r--r--lib/js/dom.nim2
-rw-r--r--lib/nimbase.h10
-rw-r--r--lib/packages/docutils/rst.nim2
-rw-r--r--lib/packages/docutils/rstgen.nim269
-rw-r--r--lib/posix/termios.nim101
-rw-r--r--lib/pure/actors.nim2
-rw-r--r--lib/pure/algorithm.nim23
-rw-r--r--lib/pure/asyncdispatch.nim115
-rw-r--r--lib/pure/asyncftpclient.nim2
-rw-r--r--lib/pure/asynchttpserver.nim92
-rw-r--r--lib/pure/asyncio.nim2
-rw-r--r--lib/pure/asyncnet.nim120
-rw-r--r--lib/pure/basic3d.nim256
-rw-r--r--lib/pure/collections/LockFreeHash.nim2
-rw-r--r--lib/pure/collections/critbits.nim13
-rw-r--r--lib/pure/collections/intsets.nim13
-rw-r--r--lib/pure/collections/sequtils.nim8
-rw-r--r--lib/pure/collections/sets.nim3
-rw-r--r--lib/pure/collections/tables.nim96
-rw-r--r--lib/pure/concurrency/cpuload.nim2
-rw-r--r--lib/pure/concurrency/threadpool.nim2
-rw-r--r--lib/pure/cookies.nim10
-rw-r--r--lib/pure/encodings.nim2
-rw-r--r--lib/pure/fsmonitor.nim2
-rw-r--r--lib/pure/ftpclient.nim4
-rw-r--r--lib/pure/gentabs.nim53
-rw-r--r--lib/pure/hashes.nim66
-rw-r--r--lib/pure/htmlgen.nim9
-rw-r--r--lib/pure/htmlparser.nim2
-rw-r--r--lib/pure/httpclient.nim18
-rw-r--r--lib/pure/httpserver.nim2
-rw-r--r--lib/pure/json.nim132
-rw-r--r--lib/pure/logging.nim2
-rw-r--r--lib/pure/marshal.nim55
-rw-r--r--lib/pure/math.nim26
-rw-r--r--lib/pure/mersenne.nim2
-rw-r--r--lib/pure/mimetypes.nim4
-rw-r--r--lib/pure/net.nim10
-rw-r--r--lib/pure/oids.nim2
-rw-r--r--lib/pure/os.nim4
-rw-r--r--lib/pure/osproc.nim40
-rw-r--r--lib/pure/parsecsv.nim2
-rw-r--r--lib/pure/parsesql.nim2
-rw-r--r--lib/pure/parseutils.nim8
-rw-r--r--lib/pure/parsexml.nim2
-rw-r--r--lib/pure/pegs.nimfix1770
-rw-r--r--lib/pure/rawsockets.nim4
-rw-r--r--lib/pure/redis.nim2
-rw-r--r--lib/pure/romans.nim9
-rw-r--r--lib/pure/scgi.nim2
-rw-r--r--lib/pure/selectors.nim2
-rw-r--r--lib/pure/sexp.nim697
-rw-r--r--lib/pure/smtp.nim2
-rw-r--r--lib/pure/sockets.nim18
-rw-r--r--lib/pure/strtabs.nim8
-rw-r--r--lib/pure/strutils.nim37
-rw-r--r--lib/pure/subexes.nim18
-rw-r--r--lib/pure/terminal.nim15
-rw-r--r--lib/pure/times.nim73
-rw-r--r--lib/pure/unicode.nim25
-rw-r--r--lib/pure/unidecode/unidecode.nim2
-rw-r--r--lib/pure/uri.nim33
-rw-r--r--lib/pure/xmldomparser.nim2
-rw-r--r--lib/pure/xmlparser.nim2
-rw-r--r--lib/pure/xmltree.nim3
-rw-r--r--lib/system.nim53
-rw-r--r--lib/system/arithm.nim8
-rw-r--r--lib/system/atomics.nim2
-rw-r--r--lib/system/chcks.nim6
-rw-r--r--lib/system/excpt.nim86
-rw-r--r--lib/windows/windows.nim79
-rw-r--r--lib/windows/winlean.nim116
-rw-r--r--lib/wrappers/claro.nim2
-rw-r--r--lib/wrappers/pcre.nim762
-rw-r--r--tests/bind/tnicerrorforsymchoice.nim6
-rw-r--r--tests/ccgbugs/tpartialcs.nim20
-rw-r--r--tests/closure/tinvalidclosure.nim2
-rw-r--r--tests/collections/tcounttable.nim19
-rw-r--r--tests/collections/tsets.nim48
-rw-r--r--tests/collections/ttables.nim16
-rw-r--r--tests/collections/ttablesref.nim18
-rw-r--r--tests/cpp/tcppraise.nim17
-rw-r--r--tests/cpp/tget_subsystem.nim23
-rw-r--r--tests/cpp/tvector_iterator.nim19
-rw-r--r--tests/cpp/tvectorseq.nim38
-rw-r--r--tests/distinct/tdistinct_consts.nim20
-rw-r--r--tests/exception/texceptionbreak.nim20
-rw-r--r--tests/exception/texceptions.nim6
-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/exception/treraise.nim4
-rw-r--r--tests/js/tstringitems.nim24
-rw-r--r--tests/js/tunittests.nim7
-rw-r--r--tests/macros/tgettype.nim20
-rw-r--r--tests/macros/tlexerex.nim16
-rw-r--r--tests/macros/treturnsempty.nim12
-rw-r--r--tests/macros/typesapi2.nim4
-rw-r--r--tests/manyloc/standalone/panicoverride.nim6
-rw-r--r--tests/metatype/ttypedesc3.nim19
-rw-r--r--tests/misc/tunsigned64mod.nim14
-rw-r--r--tests/overload/tspec.nim39
-rw-r--r--tests/parallel/twrong_refcounts.nim53
-rw-r--r--tests/parser/tinvcolonlocation1.nim12
-rw-r--r--tests/parser/tinvcolonlocation2.nim15
-rw-r--r--tests/parser/tinvcolonlocation3.nim12
-rw-r--r--tests/parser/tstrongspaces.nim14
-rw-r--r--tests/parser/ttupleunpack.nim35
-rw-r--r--tests/readme.txt5
-rw-r--r--tests/realtimeGC/cmain.c67
-rw-r--r--tests/realtimeGC/main.nim.cfg6
-rw-r--r--tests/realtimeGC/nmain.nim46
-rw-r--r--tests/realtimeGC/readme.txt21
-rw-r--r--tests/realtimeGC/shared.nim63
-rw-r--r--tests/realtimeGC/shared.nim.cfg5
-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/template/tstmt_semchecked_twice.nim30
-rw-r--r--tests/testament/categories.nim16
-rw-r--r--tests/testament/specs.nim22
-rw-r--r--tests/testament/tester.nim59
-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--tests/types/tisopr.nim41
-rw-r--r--todo.txt21
-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.txt699
-rw-r--r--web/question.txt29
-rw-r--r--web/ticker.txt10
-rw-r--r--web/website.ini6
216 files changed, 6973 insertions, 4286 deletions
diff --git a/.gitignore b/.gitignore
index d804fb8f5..462df4efc 100644
--- a/.gitignore
+++ b/.gitignore
@@ -41,4 +41,3 @@ xcuserdata/
 /testresults.html
 /testresults.json
 testament.db
-/csources/
diff --git a/.gitmodules b/.gitmodules
new file mode 100644
index 000000000..26f35d82c
--- /dev/null
+++ b/.gitmodules
@@ -0,0 +1,3 @@
+[submodule "csources"]
+	path = csources
+	url = ../../nim-lang/csources.git
diff --git a/build.sh b/build.sh
index 139c28359..91e169241 100644..100755
--- a/build.sh
+++ b/build.sh
@@ -2,8 +2,8 @@
 set -e
 set -x
 
-if [ ! -d "csources" ]; then
-	git clone --depth 1 https://github.com/nim-lang/csources.git
+if [ ! -e csources/.git ]; then
+	git submodule update --init --depth 1
 fi
 
 cd "csources"
diff --git a/compiler/ast.nim b/compiler/ast.nim
index 6bfaad527..3798410e8 100644
--- a/compiler/ast.nim
+++ b/compiler/ast.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.
@@ -296,6 +296,7 @@ const
   sfCompileToCpp* = sfInfixCall       # compile the module as C++ code
   sfCompileToObjc* = sfNamedParamCall # compile the module as Objective-C code
   sfExperimental* = sfOverriden       # module uses the .experimental switch
+  sfGoto* = sfOverriden               # var is used for 'goto' code generation
 
 const
   # getting ready for the future expr/stmt merge
@@ -529,19 +530,20 @@ type
   TMagic* = enum # symbols that require compiler magic:
     mNone,
     mDefined, mDefinedInScope, mCompiles,
-    mLow, mHigh, mSizeOf, mTypeTrait, mIs, mOf, mAddr, mTypeOf, mRoof,
+    mLow, mHigh, mSizeOf, mTypeTrait, mIs, mOf, mAddr, mTypeOf, mRoof, mPlugin,
     mEcho, mShallowCopy, mSlurp, mStaticExec,
     mParseExprToAst, mParseStmtToAst, mExpandToAst, mQuoteAst,
     mUnaryLt, mInc, mDec, mOrd, mNew, mNewFinalize, mNewSeq, mLengthOpenArray,
-    mLengthStr, mLengthArray, mLengthSeq, mIncl, mExcl, mCard, mChr, mGCref,
-    mGCunref,
+    mLengthStr, mLengthArray, mLengthSeq, mXLenStr, mXLenSeq,
+    mIncl, mExcl, mCard, mChr,
+    mGCref, mGCunref,
 
     mAddI, mSubI, mMulI, mDivI, mModI, mAddI64, mSubI64, mMulI64,
     mDivI64, mModI64, mSucc, mPred,
     mAddF64, mSubF64, mMulF64, mDivF64,
 
     mShrI, mShlI, mBitandI, mBitorI, mBitxorI, mMinI, mMaxI,
-    mShrI64, mShlI64, mBitandI64, mBitorI64, mBitxorI64, mMinI64, mMaxI64,
+    mShrI64, mShlI64, mBitandI64, mBitorI64, mBitxorI64,
     mMinF64, mMaxF64, mAddU, mSubU, mMulU,
     mDivU, mModU, mEqI, mLeI,
     mLtI,
@@ -550,7 +552,7 @@ type
     mEqEnum, mLeEnum, mLtEnum, mEqCh, mLeCh, mLtCh, mEqB, mLeB, mLtB, mEqRef,
     mEqUntracedRef, mLePtr, mLtPtr, mEqCString, mXor, mEqProc, mUnaryMinusI,
     mUnaryMinusI64, mAbsI, mAbsI64, mNot,
-    mUnaryPlusI, mBitnotI, mUnaryPlusI64,
+    mUnaryPlusI, mBitnotI,
     mBitnotI64, mUnaryPlusF64, mUnaryMinusF64, mAbsF64, mZe8ToI, mZe8ToI64,
     mZe16ToI, mZe16ToI64, mZe32ToI64, mZeIToI64, mToU8, mToU16, mToU32,
     mToFloat, mToBiggestFloat, mToInt, mToBiggestInt, mCharToStr, mBoolToStr,
@@ -589,11 +591,12 @@ type
 const
   ctfeWhitelist* = {mNone, mUnaryLt, mSucc,
     mPred, mInc, mDec, mOrd, mLengthOpenArray,
-    mLengthStr, mLengthArray, mLengthSeq, mIncl, mExcl, mCard, mChr,
+    mLengthStr, mLengthArray, mLengthSeq, mXLenStr, mXLenSeq,
+    mIncl, mExcl, mCard, mChr,
     mAddI, mSubI, mMulI, mDivI, mModI, mAddI64, mSubI64, mMulI64,
     mDivI64, mModI64, mAddF64, mSubF64, mMulF64, mDivF64,
     mShrI, mShlI, mBitandI, mBitorI, mBitxorI, mMinI, mMaxI,
-    mShrI64, mShlI64, mBitandI64, mBitorI64, mBitxorI64, mMinI64, mMaxI64,
+    mShrI64, mShlI64, mBitandI64, mBitorI64, mBitxorI64,
     mMinF64, mMaxF64, mAddU, mSubU, mMulU,
     mDivU, mModU, mEqI, mLeI,
     mLtI,
@@ -602,7 +605,7 @@ const
     mEqEnum, mLeEnum, mLtEnum, mEqCh, mLeCh, mLtCh, mEqB, mLeB, mLtB, mEqRef,
     mEqProc, mEqUntracedRef, mLePtr, mLtPtr, mEqCString, mXor, mUnaryMinusI,
     mUnaryMinusI64, mAbsI, mAbsI64, mNot,
-    mUnaryPlusI, mBitnotI, mUnaryPlusI64,
+    mUnaryPlusI, mBitnotI,
     mBitnotI64, mUnaryPlusF64, mUnaryMinusF64, mAbsF64, mZe8ToI, mZe8ToI64,
     mZe16ToI, mZe16ToI64, mZe32ToI64, mZeIToI64, mToU8, mToU16, mToU32,
     mToFloat, mToBiggestFloat, mToInt, mToBiggestInt, mCharToStr, mBoolToStr,
@@ -795,8 +798,8 @@ type
                               # for enum types a list of symbols
                               # for tyInt it can be the int literal
                               # for procs and tyGenericBody, it's the
-                              # the body of the user-defined type class
                               # formal param list
+                              # for concepts, the concept body
                               # else: unused
     owner*: PSym              # the 'owner' of the type
     sym*: PSym                # types have the sym associated with them
@@ -1170,7 +1173,9 @@ proc newType*(kind: TTypeKind, owner: PSym): PType =
   result.lockLevel = UnspecifiedLockLevel
   when debugIds:
     registerId(result)
-  #if result.id < 2000:
+  #if result.id == 92231:
+  #  echo "KNID ", kind
+  #  writeStackTrace()
   #  messageOut(typeKindToStr[kind] & ' has id: ' & toString(result.id))
 
 proc mergeLoc(a: var TLoc, b: TLoc) =
diff --git a/compiler/ccgcalls.nim b/compiler/ccgcalls.nim
index 8f354d457..2dacc25e9 100644
--- a/compiler/ccgcalls.nim
+++ b/compiler/ccgcalls.nim
@@ -385,18 +385,11 @@ proc genPatternCall(p: BProc; ri: PNode; pat: string; typ: PType): Rope =
       inc j
       inc i
     of '\'':
-      inc i
-      let stars = i
-      while pat[i] == '*': inc i
-      if pat[i] in Digits:
-        let j = pat[i].ord - '0'.ord
-        var t = typ.sons[j]
-        for k in 1..i-stars:
-          if t != nil and t.len > 0:
-            t = if t.kind == tyGenericInst: t.sons[1] else: t.elemType
+      var idx, stars: int
+      if scanCppGenericSlot(pat, i, idx, stars):
+        var t = resolveStarsInCppType(typ, idx, stars)
         if t == nil: result.add(~"void")
         else: result.add(getTypeDesc(p.module, t))
-        inc i
     else:
       let start = i
       while i < pat.len:
diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim
index 11c9d2d50..05a3602d1 100644
--- a/compiler/ccgexprs.nim
+++ b/compiler/ccgexprs.nim
@@ -566,8 +566,6 @@ proc binaryArith(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
       "($4)($1 & $2)",            # BitandI64
       "($4)($1 | $2)",            # BitorI64
       "($4)($1 ^ $2)",            # BitxorI64
-      "(($1 <= $2) ? $1 : $2)", # MinI64
-      "(($1 >= $2) ? $1 : $2)", # MaxI64
       "(($1 <= $2) ? $1 : $2)", # MinF64
       "(($1 >= $2) ? $1 : $2)", # MaxF64
       "($4)((NU$3)($1) + (NU$3)($2))", # AddU
@@ -640,7 +638,6 @@ proc unaryArith(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
     unArithTab: array[mNot..mToBiggestInt, string] = ["!($1)", # Not
       "$1",                   # UnaryPlusI
       "($3)((NU$2) ~($1))",   # BitnotI
-      "$1",                   # UnaryPlusI64
       "($3)((NU$2) ~($1))",   # BitnotI64
       "$1",                   # UnaryPlusF64
       "-($1)",                # UnaryMinusF64
@@ -676,7 +673,7 @@ proc isCppRef(p: BProc; typ: PType): bool {.inline.} =
 
 proc genDeref(p: BProc, e: PNode, d: var TLoc; enforceDeref=false) =
   let mt = mapType(e.sons[0].typ)
-  if (mt in {ctArray, ctPtrToArray} and not enforceDeref):
+  if mt in {ctArray, ctPtrToArray} and not enforceDeref:
     # XXX the amount of hacks for C's arrays is incredible, maybe we should
     # simply wrap them in a struct? --> Losing auto vectorization then?
     #if e[0].kind != nkBracketExpr:
@@ -685,19 +682,29 @@ proc genDeref(p: BProc, e: PNode, d: var TLoc; enforceDeref=false) =
   else:
     var a: TLoc
     initLocExprSingleUse(p, e.sons[0], a)
-    let typ = skipTypes(a.t, abstractInst)
-    case typ.kind
-    of tyRef:
-      d.s = OnHeap
-    of tyVar:
-      d.s = OnUnknown
-      if tfVarIsPtr notin typ.flags and p.module.compileToCpp and
-          e.kind == nkHiddenDeref:
+    if d.k == locNone:
+      let typ = skipTypes(a.t, abstractInst)
+      # dest = *a;  <-- We do not know that 'dest' is on the heap!
+      # It is completely wrong to set 'd.s' here, unless it's not yet
+      # been assigned to.
+      case typ.kind
+      of tyRef:
+        d.s = OnHeap
+      of tyVar:
+        d.s = OnUnknown
+        if tfVarIsPtr notin typ.flags and p.module.compileToCpp and
+            e.kind == nkHiddenDeref:
+          putIntoDest(p, d, e.typ, rdLoc(a))
+          return
+      of tyPtr:
+        d.s = OnUnknown         # BUGFIX!
+      else: internalError(e.info, "genDeref " & $a.t.kind)
+    elif p.module.compileToCpp:
+      let typ = skipTypes(a.t, abstractInst)
+      if typ.kind == tyVar and tfVarIsPtr notin typ.flags and
+           e.kind == nkHiddenDeref:
         putIntoDest(p, d, e.typ, rdLoc(a))
         return
-    of tyPtr:
-      d.s = OnUnknown         # BUGFIX!
-    else: internalError(e.info, "genDeref " & $a.t.kind)
     if enforceDeref and mt == ctPtrToArray:
       # we lie about the type for better C interop: 'ptr array[3,T]' is
       # translated to 'ptr T', but for deref'ing this produces wrong code.
@@ -957,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)
 
@@ -1345,15 +1355,15 @@ proc genArrayLen(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
     else: unaryExpr(p, e, d, "$1Len0")
   of tyCString:
     useStringh(p.module)
-    if op == mHigh: unaryExpr(p, e, d, "(strlen($1)-1)")
-    else: unaryExpr(p, e, d, "strlen($1)")
+    if op == mHigh: unaryExpr(p, e, d, "($1 ? (strlen($1)-1) : -1)")
+    else: unaryExpr(p, e, d, "($1 ? strlen($1) : 0)")
   of tyString, tySequence:
     if not p.module.compileToCpp:
-      if op == mHigh: unaryExpr(p, e, d, "($1->Sup.len-1)")
-      else: unaryExpr(p, e, d, "$1->Sup.len")
+      if op == mHigh: unaryExpr(p, e, d, "($1 ? ($1->Sup.len-1) : -1)")
+      else: unaryExpr(p, e, d, "($1 ? $1->Sup.len : 0)")
     else:
-      if op == mHigh: unaryExpr(p, e, d, "($1->len-1)")
-      else: unaryExpr(p, e, d, "$1->len")
+      if op == mHigh: unaryExpr(p, e, d, "($1 ? ($1->len-1) : -1)")
+      else: unaryExpr(p, e, d, "($1 ? $1->len : 0)")
   of tyArray, tyArrayConstr:
     # YYY: length(sideeffect) is optimized away incorrectly?
     if op == mHigh: putIntoDest(p, d, e.typ, rope(lastOrd(typ)))
@@ -1714,6 +1724,11 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
   of mOrd: genOrd(p, e, d)
   of mLengthArray, mHigh, mLengthStr, mLengthSeq, mLengthOpenArray:
     genArrayLen(p, e, d, op)
+  of mXLenStr, mXLenSeq:
+    if not p.module.compileToCpp:
+      unaryExpr(p, e, d, "($1->Sup.len-1)")
+    else:
+      unaryExpr(p, e, d, "$1->len")
   of mGCref: unaryStmt(p, e, d, "#nimGCref($1);$n")
   of mGCunref: unaryStmt(p, e, d, "#nimGCunref($1);$n")
   of mSetLengthStr: genSetLengthStr(p, e, d)
diff --git a/compiler/ccgstmts.nim b/compiler/ccgstmts.nim
index 1277f7154..6d29b1684 100644
--- a/compiler/ccgstmts.nim
+++ b/compiler/ccgstmts.nim
@@ -175,9 +175,18 @@ proc genBreakState(p: BProc, n: PNode) =
 
 proc genVarPrototypeAux(m: BModule, sym: PSym)
 
+proc genGotoVar(p: BProc; value: PNode) =
+  if value.kind notin {nkCharLit..nkUInt64Lit}:
+    localError(value.info, "'goto' target must be a literal value")
+  else:
+    lineF(p, cpsStmts, "goto NIMSTATE_$#;$n", [value.intVal.rope])
+
 proc genSingleVar(p: BProc, a: PNode) =
   var v = a.sons[0].sym
-  if sfCompileTime in v.flags: return
+  if {sfCompileTime, sfGoto} * v.flags != {}:
+    # translate 'var state {.goto.} = X' into 'goto LX':
+    if sfGoto in v.flags: genGotoVar(p, a.sons[2])
+    return
   var targetProc = p
   if sfGlobal in v.flags:
     if v.flags * {sfImportc, sfExportc} == {sfImportc} and
@@ -365,6 +374,19 @@ proc genReturnStmt(p: BProc, t: PNode) =
     linefmt(p, cpsStmts, "if ($1.status != 0) #popCurrentException();$n", safePoint)
   lineF(p, cpsStmts, "goto BeforeRet;$n", [])
 
+proc genGotoForCase(p: BProc; caseStmt: PNode) =
+  for i in 1 .. <caseStmt.len:
+    startBlock(p)
+    let it = caseStmt.sons[i]
+    for j in 0 .. it.len-2:
+      if it.sons[j].kind == nkRange:
+        localError(it.info, "range notation not available for computed goto")
+        return
+      let val = getOrdValue(it.sons[j])
+      lineF(p, cpsStmts, "NIMSTATE_$#:$n", [val.rope])
+    genStmts(p, it.lastSon)
+    endBlock(p)
+
 proc genComputedGoto(p: BProc; n: PNode) =
   # first pass: Generate array of computed labels:
   var casePos = -1
@@ -529,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:
@@ -737,7 +754,10 @@ proc genCase(p: BProc, t: PNode, d: var TLoc) =
     genCaseGeneric(p, t, d, "if ($1 >= $2 && $1 <= $3) goto $4;$n",
                             "if ($1 == $2) goto $3;$n")
   else:
-    genOrdinalCase(p, t, d)
+    if t.sons[0].kind == nkSym and sfGoto in t.sons[0].sym.flags:
+      genGotoForCase(p, t)
+    else:
+      genOrdinalCase(p, t, d)
 
 proc hasGeneralExceptSection(t: PNode): bool =
   var length = sonsLen(t)
@@ -772,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:
@@ -784,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):
@@ -807,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
@@ -887,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):
@@ -976,12 +999,19 @@ proc genAsmStmt(p: BProc, t: PNode) =
   else:
     lineF(p, cpsStmts, CC[cCompiler].asmStmtFrmt, [s])
 
+proc determineSection(n: PNode): TCFileSection =
+  result = cfsProcHeaders
+  if n.len >= 1 and n.sons[0].kind in {nkStrLit..nkTripleStrLit}:
+    if n.sons[0].strVal.startsWith("/*TYPESECTION*/"): result = cfsTypes
+    elif n.sons[0].strVal.startsWith("/*VARSECTION*/"): result = cfsVars
+
 proc genEmit(p: BProc, t: PNode) =
   var s = genAsmOrEmitStmt(p, t.sons[1])
   if p.prc == nil:
     # top level emit pragma?
-    genCLineDir(p.module.s[cfsProcHeaders], t.info)
-    add(p.module.s[cfsProcHeaders], s)
+    let section = determineSection(t[1])
+    genCLineDir(p.module.s[section], t.info)
+    add(p.module.s[section], s)
   else:
     genLineDir(p, t)
     line(p, cpsStmts, s)
@@ -1065,7 +1095,9 @@ proc asgnFieldDiscriminant(p: BProc, e: PNode) =
 
 proc genAsgn(p: BProc, e: PNode, fastAsgn: bool) =
   genLineDir(p, e)
-  if not fieldDiscriminantCheckNeeded(p, e):
+  if e.sons[0].kind == nkSym and sfGoto in e.sons[0].sym.flags:
+    genGotoVar(p, e.sons[1])
+  elif not fieldDiscriminantCheckNeeded(p, e):
     var a: TLoc
     initLocExpr(p, e.sons[0], a)
     if fastAsgn: incl(a.flags, lfNoDeepCopy)
diff --git a/compiler/ccgtypes.nim b/compiler/ccgtypes.nim
index 8fdabd6cc..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,
@@ -495,6 +496,33 @@ proc getTupleDesc(m: BModule, typ: PType, name: Rope,
   else: add(result, desc)
   add(result, "};" & tnl)
 
+proc scanCppGenericSlot(pat: string, cursor, outIdx, outStars: var int): bool =
+  # A helper proc for handling cppimport patterns, involving numeric
+  # placeholders for generic types (e.g. '0, '**2, etc).
+  # pre: the cursor must be placed at the ' symbol
+  # post: the cursor will be placed after the final digit
+  # false will returned if the input is not recognized as a placeholder
+  inc cursor
+  let begin = cursor
+  while pat[cursor] == '*': inc cursor
+  if pat[cursor] in Digits:
+    outIdx = pat[cursor].ord - '0'.ord
+    outStars = cursor - begin
+    inc cursor
+    return true
+  else:
+    return false
+
+proc resolveStarsInCppType(typ: PType, idx, stars: int): PType =
+  # XXX: we should catch this earlier and report it as a semantic error
+  if idx >= typ.len: internalError "invalid apostrophe type parameter index"
+
+  result = typ.sons[idx]
+  for i in 1..stars:
+    if result != nil and result.len > 0:
+      result = if result.kind == tyGenericInst: result.sons[1]
+               else: result.elemType
+
 proc getTypeDescAux(m: BModule, typ: PType, check: var IntSet): Rope =
   # returns only the type's name
   var t = getUniqueType(typ)
@@ -597,11 +625,33 @@ proc getTypeDescAux(m: BModule, typ: PType, check: var IntSet): Rope =
     if isImportedCppType(t) and typ.kind == tyGenericInst:
       # for instantiated templates we do not go through the type cache as the
       # the type cache is not aware of 'tyGenericInst'.
-      result = getTypeName(t) & "<"
-      for i in 1 .. typ.len-2:
-        if i > 1: result.add(", ")
-        result.add(getTypeDescAux(m, typ.sons[i], check))
-      result.add("> ")
+      let cppName = getTypeName(t)
+      var i = 0
+      var chunkStart = 0
+      while i < cppName.data.len:
+        if cppName.data[i] == '\'':
+          var chunkEnd = <i
+          var idx, stars: int
+          if scanCppGenericSlot(cppName.data, i, idx, stars):
+            result.add cppName.data.substr(chunkStart, chunkEnd)
+            chunkStart = i
+
+            let typeInSlot = resolveStarsInCppType(typ, idx + 1, stars)
+            if typeInSlot == nil or typeInSlot.kind == tyEmpty:
+              result.add(~"void")
+            else:
+              result.add getTypeDescAux(m, typeInSlot, check)
+        else:
+          inc i
+
+      if chunkStart != 0:
+        result.add cppName.data.substr(chunkStart)
+      else:
+        result = cppName & "<"
+        for i in 1 .. typ.len-2:
+          if i > 1: result.add(", ")
+          result.add(getTypeDescAux(m, typ.sons[i], check))
+        result.add("> ")
       # always call for sideeffects:
       assert t.kind != tyTuple
       discard getRecordDesc(m, t, result, check)
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/cgen.nim b/compiler/cgen.nim
index da9c6f653..4b0bac28a 100644
--- a/compiler/cgen.nim
+++ b/compiler/cgen.nim
@@ -676,8 +676,11 @@ proc genProcAux(m: BModule, prc: PSym) =
   closureSetup(p, prc)
   genStmts(p, prc.getBody) # modifies p.locals, p.init, etc.
   var generatedProc: Rope
+  if sfNoReturn in prc.flags:
+    if hasDeclspec in extccomp.CC[extccomp.cCompiler].props:
+      header = "__declspec(noreturn) " & header
   if sfPure in prc.flags:
-    if hasNakedDeclspec in extccomp.CC[extccomp.cCompiler].props:
+    if hasDeclspec in extccomp.CC[extccomp.cCompiler].props:
       header = "__declspec(naked) " & header
     generatedProc = rfmt(nil, "$N$1 {$n$2$3$4}$N$N",
                          header, p.s(cpsLocals), p.s(cpsInit), p.s(cpsStmts))
@@ -720,8 +723,10 @@ proc genProcPrototype(m: BModule, sym: PSym) =
     var header = genProcHeader(m, sym)
     if sym.typ.callConv != ccInline and crossesCppBoundary(m, sym):
       header = "extern \"C\" " & header
-    if sfPure in sym.flags and hasNakedAttribute in CC[cCompiler].props:
+    if sfPure in sym.flags and hasAttribute in CC[cCompiler].props:
       header.add(" __attribute__((naked))")
+    if sfNoReturn in sym.flags and hasAttribute in CC[cCompiler].props:
+      header.add(" __attribute__((noreturn))")
     add(m.s[cfsProcHeaders], rfmt(nil, "$1;$n", header))
 
 proc genProcNoForward(m: BModule, prc: PSym) =
diff --git a/compiler/commands.nim b/compiler/commands.nim
index 5b5f461ef..b6ebb6bcb 100644
--- a/compiler/commands.nim
+++ b/compiler/commands.nim
@@ -319,7 +319,7 @@ proc processSwitch(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) =
     undefSymbol(arg)
   of "symbol":
     expectArg(switch, arg, pass, info)
-    declareSymbol(arg)
+    # deprecated, do nothing
   of "compile":
     expectArg(switch, arg, pass, info)
     if pass in {passCmd2, passPP}: processCompile(arg)
@@ -488,7 +488,6 @@ proc processSwitch(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) =
       if theOS == osNone: localError(info, errUnknownOS, arg)
       elif theOS != platform.hostOS:
         setTarget(theOS, targetCPU)
-        condsyms.initDefines()
   of "cpu":
     expectArg(switch, arg, pass, info)
     if pass in {passCmd1, passPP}:
@@ -496,7 +495,6 @@ proc processSwitch(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) =
       if cpu == cpuNone: localError(info, errUnknownCPU, arg)
       elif cpu != platform.hostCPU:
         setTarget(targetOS, cpu)
-        condsyms.initDefines()
   of "run", "r":
     expectNoArg(switch, arg, pass, info)
     incl(gGlobalOptions, optRun)
diff --git a/compiler/condsyms.nim b/compiler/condsyms.nim
index 7ddf44d4a..ad7d80c85 100644
--- a/compiler/condsyms.nim
+++ b/compiler/condsyms.nim
@@ -9,71 +9,69 @@
 
 # This module handles the conditional symbols.
 
-import 
+import
   strtabs, platform, strutils, idents
 
-# We need to use a PStringTable here as defined symbols are always guaranteed
+# We need to use a StringTableRef here as defined symbols are always guaranteed
 # to be style insensitive. Otherwise hell would break lose.
 var gSymbols: StringTableRef
 
-proc defineSymbol*(symbol: string) = 
-  gSymbols[symbol] = "true"
+const
+  catNone = "false"
 
-proc declareSymbol*(symbol: string) = 
-  gSymbols[symbol] = "unknown"
+proc defineSymbol*(symbol: string) =
+  gSymbols[symbol] = "true"
 
-proc undefSymbol*(symbol: string) = 
-  gSymbols[symbol] = "false"
+proc undefSymbol*(symbol: string) =
+  gSymbols[symbol] = catNone
 
-proc isDefined*(symbol: string): bool = 
+proc isDefined*(symbol: string): bool =
   if gSymbols.hasKey(symbol):
-    result = gSymbols[symbol] == "true"
-  
+    result = gSymbols[symbol] != catNone
+  elif cmpIgnoreStyle(symbol, CPU[targetCPU].name) == 0:
+    result = true
+  elif cmpIgnoreStyle(symbol, platform.OS[targetOS].name) == 0:
+    result = true
+  else:
+    case symbol.normalize
+    of "x86": result = targetCPU == cpuI386
+    of "itanium": result = targetCPU == cpuIa64
+    of "x8664": result = targetCPU == cpuAmd64
+    of "posix", "unix":
+      result = targetOS in {osLinux, osMorphos, osSkyos, osIrix, osPalmos,
+                            osQnx, osAtari, osAix,
+                            osHaiku, osVxWorks, osSolaris, osNetbsd,
+                            osFreebsd, osOpenbsd, osMacosx}
+    of "bsd":
+      result = targetOS in {osNetbsd, osFreebsd, osOpenbsd}
+    of "emulatedthreadvars":
+      result = platform.OS[targetOS].props.contains(ospLacksThreadVars)
+    of "msdos": result = targetOS == osDos
+    of "mswindows", "win32": result = targetOS == osWindows
+    of "macintosh": result = targetOS in {osMacos, osMacosx}
+    of "sunos": result = targetOS == osSolaris
+    of "littleendian": result = CPU[targetCPU].endian == platform.littleEndian
+    of "bigendian": result = CPU[targetCPU].endian == platform.bigEndian
+    of "cpu8": result = CPU[targetCPU].bit == 8
+    of "cpu16": result = CPU[targetCPU].bit == 16
+    of "cpu32": result = CPU[targetCPU].bit == 32
+    of "cpu64": result = CPU[targetCPU].bit == 64
+    of "nimrawsetjmp":
+      result = targetOS in {osSolaris, osNetbsd, osFreebsd, osOpenbsd, osMacosx}
+    else: discard
+
 proc isDefined*(symbol: PIdent): bool = isDefined(symbol.s)
-proc isDeclared*(symbol: PIdent): bool = gSymbols.hasKey(symbol.s)
 
 iterator definedSymbolNames*: string =
   for key, val in pairs(gSymbols):
-    if val == "true": yield key
+    if val != catNone: yield key
 
-proc countDefinedSymbols*(): int = 
+proc countDefinedSymbols*(): int =
   result = 0
   for key, val in pairs(gSymbols):
-    if val == "true": inc(result)
-
-# For ease of bootstrapping, we keep them here and not in the global config
-# file for now:
-const
-  additionalSymbols = """
-    x86 itanium x8664
-    msdos mswindows win32 unix posix sunos bsd macintosh RISCOS hpux
-    mac
-
-    hppa hp9000 hp9000s300 hp9000s700 hp9000s800 hp9000s820 ELATE sparcv9
+    if val != catNone: inc(result)
 
-    ecmascript js nimrodvm nimffi nimdoc cpp objc
-    gcc llvmgcc clang lcc bcc dmc wcc vcc tcc pcc ucc icl
-    boehmgc gcmarkandsweep gcgenerational nogc gcUseBitvectors
-    endb profiler
-    executable guiapp consoleapp library dll staticlib
-
-    quick
-    release debug
-    useWinAnsi useFork useNimRtl useMalloc useRealtimeGC ssl memProfiler
-    nodejs kwin nimfix
-
-    usesysassert usegcassert tinyC useFFI
-    useStdoutAsStdmsg createNimRtl
-    booting fulldebug corruption nimsuperops noSignalHandler useGnuReadline
-    noCaas noDocGen noBusyWaiting nativeStackTrace useNodeIds selftest
-    reportMissedDeadlines avoidTimeMachine useClone ignoreAllocationSize
-    debugExecProcesses pcreDll useLipzipSrc
-    preventDeadlocks UNICODE winUnicode trackGcHeaders posixRealtime
-
-    nimStdSetjmp nimRawSetjmp nimSigSetjmp
-  """.split
-
-proc initDefines*() = 
+proc initDefines*() =
   gSymbols = newStringTable(modeStyleInsensitive)
   defineSymbol("nimrod") # 'nimrod' is always defined
   # for bootstrapping purposes and old code:
@@ -90,58 +88,3 @@ proc initDefines*() =
   defineSymbol("nimalias")
   defineSymbol("nimlocks")
   defineSymbol("nimnode")
-  
-  # add platform specific symbols:
-  for c in low(CPU)..high(CPU):
-    declareSymbol("cpu" & $CPU[c].bit)
-    declareSymbol(normalize(EndianToStr[CPU[c].endian]))
-    declareSymbol(CPU[c].name)
-  for o in low(platform.OS)..high(platform.OS):
-    declareSymbol(platform.OS[o].name)
-
-  for a in additionalSymbols:
-    declareSymbol(a)
-
-  # -----------------------------------------------------------
-  case targetCPU
-  of cpuI386: defineSymbol("x86")
-  of cpuIa64: defineSymbol("itanium")
-  of cpuAmd64: defineSymbol("x8664")
-  else: discard
-  case targetOS
-  of osDos: 
-    defineSymbol("msdos")
-  of osWindows: 
-    defineSymbol("mswindows")
-    defineSymbol("win32")
-  of osLinux, osMorphos, osSkyos, osIrix, osPalmos, osQnx, osAtari, osAix, 
-     osHaiku, osVxWorks:
-    # these are all 'unix-like'
-    defineSymbol("unix")
-    defineSymbol("posix")
-  of osSolaris: 
-    defineSymbol("sunos")
-    defineSymbol("unix")
-    defineSymbol("posix")
-  of osNetbsd, osFreebsd, osOpenbsd: 
-    defineSymbol("unix")
-    defineSymbol("bsd")
-    defineSymbol("posix")
-  of osMacos: 
-    defineSymbol("macintosh")
-  of osMacosx: 
-    defineSymbol("macintosh")
-    defineSymbol("unix")
-    defineSymbol("posix")
-  else: discard
-  defineSymbol("cpu" & $CPU[targetCPU].bit)
-  defineSymbol(normalize(EndianToStr[CPU[targetCPU].endian]))
-  defineSymbol(CPU[targetCPU].name)
-  defineSymbol(platform.OS[targetOS].name)
-  declareSymbol("emulatedthreadvars")
-  if platform.OS[targetOS].props.contains(ospLacksThreadVars):
-    defineSymbol("emulatedthreadvars")
-  case targetOS
-  of osSolaris, osNetbsd, osFreebsd, osOpenbsd, osMacosx:
-    defineSymbol("nimRawSetjmp")
-  else: discard
diff --git a/compiler/extccomp.nim b/compiler/extccomp.nim
index 499d9ae52..186a3884d 100644
--- a/compiler/extccomp.nim
+++ b/compiler/extccomp.nim
@@ -15,9 +15,9 @@
 import
   lists, ropes, os, strutils, osproc, platform, condsyms, options, msgs, crc
 
-type 
-  TSystemCC* = enum 
-    ccNone, ccGcc, ccLLVM_Gcc, ccCLang, ccLcc, ccBcc, ccDmc, ccWcc, ccVcc, 
+type
+  TSystemCC* = enum
+    ccNone, ccGcc, ccLLVM_Gcc, ccCLang, ccLcc, ccBcc, ccDmc, ccWcc, ccVcc,
     ccTcc, ccPcc, ccUcc, ccIcl
   TInfoCCProp* = enum         # properties of the C compiler:
     hasSwitchRange,           # CC allows ranges in switch statements (GNU C)
@@ -26,8 +26,8 @@ type
     hasAssume,                # CC has __assume (Visual C extension)
     hasGcGuard,               # CC supports GC_GUARD to keep stack roots
     hasGnuAsm,                # CC's asm uses the absurd GNU assembler syntax
-    hasNakedDeclspec,         # CC has __declspec(naked)
-    hasNakedAttribute         # CC has __attribute__((naked))
+    hasDeclspec,              # CC has __declspec(X)
+    hasAttribute,             # CC has __attribute__((X))
   TInfoCCProps* = set[TInfoCCProp]
   TInfoCC* = tuple[
     name: string,        # the short name of the compiler
@@ -54,7 +54,7 @@ type
     props: TInfoCCProps] # properties of the C compiler
 
 
-# Configuration settings for various compilers. 
+# Configuration settings for various compilers.
 # When adding new compilers, the cmake sources could be a good reference:
 # http://cmake.org/gitweb?p=cmake.git;a=tree;f=Modules/Platform;
 
@@ -85,7 +85,7 @@ compiler gcc:
     structStmtFmt: "$1 $3 $2 ", # struct|union [packed] $name
     packedPragma: "__attribute__((__packed__))",
     props: {hasSwitchRange, hasComputedGoto, hasCpp, hasGcGuard, hasGnuAsm,
-            hasNakedAttribute})
+            hasAttribute})
 
 # LLVM Frontend for GCC/G++
 compiler llvmGcc:
@@ -127,7 +127,7 @@ compiler vcc:
     asmStmtFrmt: "__asm{$n$1$n}$n",
     structStmtFmt: "$3$n$1 $2",
     packedPragma: "#pragma pack(1)",
-    props: {hasCpp, hasAssume, hasNakedDeclspec})
+    props: {hasCpp, hasAssume, hasDeclspec})
 
 # Intel C/C++ Compiler
 compiler icl:
@@ -136,7 +136,7 @@ compiler icl:
     result = vcc()
   else:
     result = gcc()
-    
+
   result.name = "icl"
   result.compilerExe = "icl"
   result.linkerExe = "icl"
@@ -317,7 +317,7 @@ compiler ucc:
     packedPragma: "", # XXX: not supported yet
     props: {})
 
-const 
+const
   CC*: array[succ(low(TSystemCC))..high(TSystemCC), TInfoCC] = [
     gcc(),
     llvmGcc(),
@@ -346,7 +346,7 @@ var
 proc libNameTmpl(): string {.inline.} =
   result = if targetOS == osWindows: "$1.lib" else: "lib$1.a"
 
-var 
+var
   toLink, toCompile, externalToCompile: TLinkedList
   linkOptions: string = ""
   compileOptions: string = ""
@@ -355,8 +355,8 @@ var
 proc nameToCC*(name: string): TSystemCC =
   ## Returns the kind of compiler referred to by `name`, or ccNone
   ## if the name doesn't refer to any known compiler.
-  for i in countup(succ(ccNone), high(TSystemCC)): 
-    if cmpIgnoreStyle(name, CC[i].name) == 0: 
+  for i in countup(succ(ccNone), high(TSystemCC)):
+    if cmpIgnoreStyle(name, CC[i].name) == 0:
       return i
   result = ccNone
 
@@ -375,8 +375,8 @@ proc getConfigVar(c: TSystemCC, suffix: string): string =
 
   if (platform.hostOS != targetOS or platform.hostCPU != targetCPU) and
       optCompileOnly notin gGlobalOptions:
-    let fullCCname = platform.CPU[targetCPU].name & '.' & 
-                     platform.OS[targetOS].name & '.' & 
+    let fullCCname = platform.CPU[targetCPU].name & '.' &
+                     platform.OS[targetOS].name & '.' &
                      CC[c].name & fullSuffix
     result = getConfigVar(fullCCname)
     if result.len == 0:
@@ -385,7 +385,7 @@ proc getConfigVar(c: TSystemCC, suffix: string): string =
   else:
     result = getConfigVar(CC[c].name & fullSuffix)
 
-proc setCC*(ccname: string) = 
+proc setCC*(ccname: string) =
   cCompiler = nameToCC(ccname)
   if cCompiler == ccNone: rawMessage(errUnknownCcompiler, ccname)
   compileOptions = getConfigVar(cCompiler, ".options.always")
@@ -394,18 +394,18 @@ proc setCC*(ccname: string) =
   for i in countup(low(CC), high(CC)): undefSymbol(CC[i].name)
   defineSymbol(CC[cCompiler].name)
 
-proc addOpt(dest: var string, src: string) = 
+proc addOpt(dest: var string, src: string) =
   if len(dest) == 0 or dest[len(dest)-1] != ' ': add(dest, " ")
   add(dest, src)
 
 proc addLinkOption*(option: string) =
   addOpt(linkOptions, option)
 
-proc addCompileOption*(option: string) = 
-  if strutils.find(compileOptions, option, 0) < 0: 
+proc addCompileOption*(option: string) =
+  if strutils.find(compileOptions, option, 0) < 0:
     addOpt(compileOptions, option)
 
-proc initVars*() = 
+proc initVars*() =
   # we need to define the symbol here, because ``CC`` may have never been set!
   for i in countup(low(CC), high(CC)): undefSymbol(CC[i].name)
   defineSymbol(CC[cCompiler].name)
@@ -414,10 +414,10 @@ proc initVars*() =
   if len(ccompilerpath) == 0:
     ccompilerpath = getConfigVar(cCompiler, ".path")
 
-proc completeCFilePath*(cfile: string, createSubDir: bool = true): string = 
+proc completeCFilePath*(cfile: string, createSubDir: bool = true): string =
   result = completeGeneratedFilePath(cfile, createSubDir)
 
-proc toObjFile*(filename: string): string = 
+proc toObjFile*(filename: string): string =
   # Object file for compilation
   result = changeFileExt(filename, CC[cCompiler].objExt)
 
@@ -449,22 +449,22 @@ proc execExternalProgram*(cmd: string, prettyCmd = "") =
   if execWithEcho(cmd, prettyCmd) != 0:
     rawMessage(errExecutionOfProgramFailed, "")
 
-proc generateScript(projectFile: string, script: Rope) = 
+proc generateScript(projectFile: string, script: Rope) =
   let (dir, name, ext) = splitFile(projectFile)
-  writeRope(script, dir / addFileExt("compile_" & name, 
+  writeRope(script, dir / addFileExt("compile_" & name,
                                      platform.OS[targetOS].scriptExt))
 
-proc getOptSpeed(c: TSystemCC): string = 
+proc getOptSpeed(c: TSystemCC): string =
   result = getConfigVar(c, ".options.speed")
   if result == "":
     result = CC[c].optSpeed   # use default settings from this file
 
-proc getDebug(c: TSystemCC): string = 
+proc getDebug(c: TSystemCC): string =
   result = getConfigVar(c, ".options.debug")
   if result == "":
     result = CC[c].debug      # use default settings from this file
 
-proc getOptSize(c: TSystemCC): string = 
+proc getOptSize(c: TSystemCC): string =
   result = getConfigVar(c, ".options.size")
   if result == "":
     result = CC[c].optSize    # use default settings from this file
@@ -476,7 +476,7 @@ proc noAbsolutePaths: bool {.inline.} =
   # `optGenMapping` is included here for niminst.
   result = gGlobalOptions * {optGenScript, optGenMapping} != {}
 
-const 
+const
   specialFileA = 42
   specialFileB = 42
 
@@ -488,7 +488,7 @@ proc add(s: var string, many: openArray[string]) =
 proc cFileSpecificOptions(cfilename: string): string =
   result = compileOptions
   var trunk = splitFile(cfilename).name
-  if optCDebug in gGlobalOptions: 
+  if optCDebug in gGlobalOptions:
     var key = trunk & ".debug"
     if existsConfigVar(key): addOpt(result, getConfigVar(key))
     else: addOpt(result, getDebug(cCompiler))
@@ -528,17 +528,17 @@ proc getLinkerExe(compiler: TSystemCC): string =
            elif gMixedMode and gCmd != cmdCompileToCpp: CC[compiler].cppCompiler
            else: compiler.getCompilerExe
 
-proc getCompileCFileCmd*(cfilename: string, isExternal = false): string = 
+proc getCompileCFileCmd*(cfilename: string, isExternal = false): string =
   var c = cCompiler
   var options = cFileSpecificOptions(cfilename)
   var exe = getConfigVar(c, ".exe")
   if exe.len == 0: exe = c.getCompilerExe
-  
+
   if needsExeExt(): exe = addFileExt(exe, "exe")
   if optGenDynLib in gGlobalOptions and
       ospNeedsPIC in platform.OS[targetOS].props:
     add(options, ' ' & CC[c].pic)
-  
+
   var includeCmd, compilePattern: string
   if not noAbsolutePaths():
     # compute include paths:
@@ -551,7 +551,7 @@ proc getCompileCFileCmd*(cfilename: string, isExternal = false): string =
   else:
     includeCmd = ""
     compilePattern = c.getCompilerExe
-  
+
   var cfile = if noAbsolutePaths(): extractFilename(cfilename)
               else: cfilename
   var objfile = if not isExternal or noAbsolutePaths():
@@ -580,14 +580,14 @@ proc footprint(filename: string): TCrc32 =
       extccomp.CC[extccomp.cCompiler].name ><
       getCompileCFileCmd(filename, true)
 
-proc externalFileChanged(filename: string): bool = 
+proc externalFileChanged(filename: string): bool =
   if gCmd notin {cmdCompileToC, cmdCompileToCpp, cmdCompileToOC, cmdCompileToLLVM}:
     return false
 
   var crcFile = toGeneratedFile(filename.withPackageName, "crc")
   var currentCrc = int(footprint(filename))
   var f: File
-  if open(f, crcFile, fmRead): 
+  if open(f, crcFile, fmRead):
     var line = newStringOfCap(40)
     if not f.readLine(line): line = "0"
     close(f)
@@ -595,7 +595,7 @@ proc externalFileChanged(filename: string): bool =
     result = oldCrc != currentCrc
   else:
     result = true
-  if result: 
+  if result:
     if open(f, crcFile, fmWrite):
       f.writeln($currentCrc)
       close(f)
@@ -607,22 +607,22 @@ proc addExternalFileToCompile*(filename: string) =
 proc compileCFile(list: TLinkedList, script: var Rope, cmds: var TStringSeq,
                   prettyCmds: var TStringSeq, isExternal: bool) =
   var it = PStrEntry(list.head)
-  while it != nil: 
+  while it != nil:
     inc(fileCounter)          # call the C compiler for the .c file:
     var compileCmd = getCompileCFileCmd(it.data, isExternal)
-    if optCompileOnly notin gGlobalOptions: 
+    if optCompileOnly notin gGlobalOptions:
       add(cmds, compileCmd)
       let (dir, name, ext) = splitFile(it.data)
       add(prettyCmds, "CC: " & name)
-    if optGenScript in gGlobalOptions: 
+    if optGenScript in gGlobalOptions:
       add(script, compileCmd)
       add(script, tnl)
     it = PStrEntry(it.next)
 
 proc callCCompiler*(projectfile: string) =
-  var 
+  var
     linkCmd, buildgui, builddll: string
-  if gGlobalOptions * {optCompileOnly, optGenScript} == {optCompileOnly}: 
+  if gGlobalOptions * {optCompileOnly, optGenScript} == {optCompileOnly}:
     return # speed up that call if only compiling and no script shall be
            # generated
   fileCounter = 0
@@ -634,11 +634,11 @@ proc callCCompiler*(projectfile: string) =
     echo prettyCmds[idx]
   compileCFile(toCompile, script, cmds, prettyCmds, false)
   compileCFile(externalToCompile, script, cmds, prettyCmds, true)
-  if optCompileOnly notin gGlobalOptions: 
+  if optCompileOnly notin gGlobalOptions:
     if gNumberOfProcessors == 0: gNumberOfProcessors = countProcessors()
     var res = 0
-    if gNumberOfProcessors <= 1: 
-      for i in countup(0, high(cmds)): 
+    if gNumberOfProcessors <= 1:
+      for i in countup(0, high(cmds)):
         res = execWithEcho(cmds[i])
         if res != 0: rawMessage(errExecutionOfProgramFailed, [])
     elif optListCmd in gGlobalOptions or gVerbosity > 1:
@@ -668,7 +668,8 @@ proc callCCompiler*(projectfile: string) =
       it = PStrEntry(it.next)
 
     if optGenStaticLib in gGlobalOptions:
-      linkCmd = CC[c].buildLib % ["libfile", (libNameTmpl() % gProjectName),
+      let name = splitFile(gProjectName).name
+      linkCmd = CC[c].buildLib % ["libfile", (libNameTmpl() % name),
                                   "objfiles", objfiles]
     else:
       var linkerExe = getConfigVar(c, ".linkerexe")
@@ -685,13 +686,13 @@ proc callCCompiler*(projectfile: string) =
       else:
         exefile = splitFile(projectfile).name & platform.OS[targetOS].exeExt
         builddll = ""
-      if options.outFile.len > 0: 
+      if options.outFile.len > 0:
         exefile = options.outFile.expandTilde
       if not noAbsolutePaths():
         if not exefile.isAbsolute():
           exefile = joinPath(splitFile(projectfile).dir, exefile)
       exefile = quoteShell(exefile)
-      let linkOptions = getLinkOptions() & " " & 
+      let linkOptions = getLinkOptions() & " " &
                         getConfigVar(cCompiler, ".options.linker")
       linkCmd = quoteShell(linkCmd % ["builddll", builddll,
           "buildgui", buildgui, "options", linkOptions, "objfiles", objfiles,
@@ -714,26 +715,26 @@ proc callCCompiler*(projectfile: string) =
     add(script, tnl)
     generateScript(projectfile, script)
 
-proc genMappingFiles(list: TLinkedList): Rope = 
+proc genMappingFiles(list: TLinkedList): Rope =
   var it = PStrEntry(list.head)
-  while it != nil: 
+  while it != nil:
     addf(result, "--file:r\"$1\"$N", [rope(it.data)])
     it = PStrEntry(it.next)
 
-proc writeMapping*(gSymbolMapping: Rope) = 
-  if optGenMapping notin gGlobalOptions: return 
+proc writeMapping*(gSymbolMapping: Rope) =
+  if optGenMapping notin gGlobalOptions: return
   var code = rope("[C_Files]\n")
   add(code, genMappingFiles(toCompile))
   add(code, genMappingFiles(externalToCompile))
   add(code, "\n[C_Compiler]\nFlags=")
   add(code, strutils.escape(getCompileOptions()))
-  
+
   add(code, "\n[Linker]\nFlags=")
-  add(code, strutils.escape(getLinkOptions() & " " & 
+  add(code, strutils.escape(getLinkOptions() & " " &
                             getConfigVar(cCompiler, ".options.linker")))
 
   add(code, "\n[Environment]\nlibpath=")
   add(code, strutils.escape(libpath))
-  
+
   addf(code, "\n[Symbols]$n$1", [gSymbolMapping])
   writeRope(code, joinPath(gProjectPath, "mapping.txt"))
diff --git a/compiler/guards.nim b/compiler/guards.nim
index cedd2be2b..df2c1dd75 100644
--- a/compiler/guards.nim
+++ b/compiler/guards.nim
@@ -22,7 +22,8 @@ const
   someLt = {mLtI, mLtI64, mLtF64, mLtU, mLtU64, mLtEnum,
             mLtCh, mLtB, mLtPtr, mLtStr}
 
-  someLen = {mLengthOpenArray, mLengthStr, mLengthArray, mLengthSeq}
+  someLen = {mLengthOpenArray, mLengthStr, mLengthArray, mLengthSeq,
+             mXLenStr, mXLenSeq}
 
   someIn = {mInRange, mInSet}
 
@@ -34,8 +35,8 @@ const
   someMul = {mMulI, mMulI64, mMulF64}
   someDiv = {mDivI, mDivI64, mDivF64}
   someMod = {mModI, mModI64}
-  someMax = {mMaxI, mMaxI64, mMaxF64}
-  someMin = {mMinI, mMinI64, mMinF64}
+  someMax = {mMaxI, mMaxF64}
+  someMin = {mMinI, mMinF64}
 
 proc isValue(n: PNode): bool = n.kind in {nkCharLit..nkNilLit}
 proc isLocation(n: PNode): bool = not n.isValue
@@ -122,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
@@ -907,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/jsgen.nim b/compiler/jsgen.nim
index 6c667a3a7..5c7071498 100644
--- a/compiler/jsgen.nim
+++ b/compiler/jsgen.nim
@@ -124,7 +124,7 @@ proc newProc(globals: PGlobals, module: BModule, procDef: PNode,
 
 const
   MappedToObject = {tyObject, tyArray, tyArrayConstr, tyTuple, tyOpenArray,
-    tySet, tyVar, tyRef, tyPtr, tyBigNum, tyVarargs}
+    tySet, tyBigNum, tyVarargs}
 
 proc mapType(typ: PType): TJSTypeKind =
   let t = skipTypes(typ, abstractInst)
@@ -163,7 +163,8 @@ proc mangleName(s: PSym): Rope =
     add(result, rope(s.id))
     s.loc.r = result
 
-proc makeJSString(s: string): Rope = strutils.escape(s).rope
+proc makeJSString(s: string): Rope =
+  (if s.isNil: "null".rope else: strutils.escape(s).rope)
 
 include jstypes
 
@@ -280,8 +281,6 @@ const # magic checked op; magic unchecked op; checked op; unchecked op
     ["", "", "($1 & $2)", "($1 & $2)"], # BitandI64
     ["", "", "($1 | $2)", "($1 | $2)"], # BitorI64
     ["", "", "($1 ^ $2)", "($1 ^ $2)"], # BitxorI64
-    ["nimMin", "nimMin", "nimMin($1, $2)", "nimMin($1, $2)"], # MinI64
-    ["nimMax", "nimMax", "nimMax($1, $2)", "nimMax($1, $2)"], # MaxI64
     ["nimMin", "nimMin", "nimMin($1, $2)", "nimMin($1, $2)"], # MinF64
     ["nimMax", "nimMax", "nimMax($1, $2)", "nimMax($1, $2)"], # MaxF64
     ["addU", "addU", "addU($1, $2)", "addU($1, $2)"], # addU
@@ -325,7 +324,6 @@ const # magic checked op; magic unchecked op; checked op; unchecked op
     ["", "", "!($1)", "!($1)"], # Not
     ["", "", "+($1)", "+($1)"], # UnaryPlusI
     ["", "", "~($1)", "~($1)"], # BitnotI
-    ["", "", "+($1)", "+($1)"], # UnaryPlusI64
     ["", "", "~($1)", "~($1)"], # BitnotI64
     ["", "", "+($1)", "+($1)"], # UnaryPlusF64
     ["", "", "-($1)", "-($1)"], # UnaryMinusF64
@@ -382,8 +380,6 @@ const # magic checked op; magic unchecked op; checked op; unchecked op
     ["", "", "($1 & $2)", "($1 & $2)"], # BitandI64
     ["", "", "($1 | $2)", "($1 | $2)"], # BitorI64
     ["", "", "($1 ^ $2)", "($1 ^ $2)"], # BitxorI64
-    ["nimMin", "nimMin", "nimMin($1, $2)", "nimMin($1, $2)"], # MinI64
-    ["nimMax", "nimMax", "nimMax($1, $2)", "nimMax($1, $2)"], # MaxI64
     ["nimMin", "nimMin", "nimMin($1, $2)", "nimMin($1, $2)"], # MinF64
     ["nimMax", "nimMax", "nimMax($1, $2)", "nimMax($1, $2)"], # MaxF64
     ["addU", "addU", "addU($1, $2)", "addU($1, $2)"], # addU
@@ -427,7 +423,6 @@ const # magic checked op; magic unchecked op; checked op; unchecked op
     ["", "", "not ($1)", "not ($1)"], # Not
     ["", "", "+($1)", "+($1)"], # UnaryPlusI
     ["", "", "~($1)", "~($1)"], # BitnotI
-    ["", "", "+($1)", "+($1)"], # UnaryPlusI64
     ["", "", "~($1)", "~($1)"], # BitnotI64
     ["", "", "+($1)", "+($1)"], # UnaryPlusF64
     ["", "", "-($1)", "-($1)"], # UnaryMinusF64
@@ -937,6 +932,13 @@ proc genArrayAccess(p: PProc, n: PNode, r: var TCompRes) =
   r.address = nil
   r.kind = resExpr
 
+proc isIndirect(v: PSym): bool =
+  result = {sfAddrTaken, sfGlobal} * v.flags != {} and
+    #(mapType(v.typ) != etyObject) and
+    {sfImportc, sfVolatile, sfExportc} * v.flags == {} and
+    v.kind notin {skProc, skConverter, skMethod, skIterator, skClosureIterator,
+                  skConst, skTemp, skLet}
+
 proc genAddr(p: PProc, n: PNode, r: var TCompRes) =
   case n.sons[0].kind
   of nkSym:
@@ -945,12 +947,16 @@ proc genAddr(p: PProc, n: PNode, r: var TCompRes) =
     case s.kind
     of skVar, skLet, skResult:
       r.kind = resExpr
-      if mapType(n.sons[0].typ) == etyObject:
+      let jsType = mapType(n.typ)
+      if jsType == etyObject:
         # make addr() a no-op:
         r.typ = etyNone
-        r.res = s.loc.r
+        if isIndirect(s):
+          r.res = s.loc.r & "[0]"
+        else:
+          r.res = s.loc.r
         r.address = nil
-      elif {sfGlobal, sfAddrTaken} * s.flags != {}:
+      elif {sfGlobal, sfAddrTaken} * s.flags != {} or jsType == etyBaseIndex:
         # for ease of code generation, we do not distinguish between
         # sfAddrTaken and sfGlobal.
         r.typ = etyBaseIndex
@@ -992,7 +998,7 @@ proc genSym(p: PProc, n: PNode, r: var TCompRes) =
       else:
         r.address = s.loc.r
         r.res = s.loc.r & "_Idx"
-    elif k != etyObject and {sfAddrTaken, sfGlobal} * s.flags != {}:
+    elif isIndirect(s):
       r.res = "$1[0]" % [s.loc.r]
     else:
       r.res = s.loc.r
@@ -1046,11 +1052,13 @@ proc genArg(p: PProc, n: PNode, r: var TCompRes) =
 
 proc genArgs(p: PProc, n: PNode, r: var TCompRes) =
   add(r.res, "(")
+  var hasArgs = false
   for i in countup(1, sonsLen(n) - 1):
     let it = n.sons[i]
     if it.typ.isCompileTimeOnly: continue
-    if i > 1: add(r.res, ", ")
+    if hasArgs: add(r.res, ", ")
     genArg(p, it, r)
+    hasArgs = true
   add(r.res, ")")
   r.kind = resExpr
 
@@ -1124,7 +1132,7 @@ proc createVar(p: PProc, typ: PType, indirect: bool): Rope =
   of tyRange, tyGenericInst:
     result = createVar(p, lastSon(typ), indirect)
   of tySet:
-    result = rope("{}")
+    result = putToSeq("{}", indirect)
   of tyBool:
     result = putToSeq("false", indirect)
   of tyArray, tyArrayConstr:
@@ -1144,6 +1152,7 @@ proc createVar(p: PProc, typ: PType, indirect: bool): Rope =
         add(result, createVar(p, e, false))
         inc(i)
       add(result, "]")
+    if indirect: result = "[$1]" % [result]
   of tyTuple:
     result = rope("{")
     for i in 0.. <t.sonsLen:
@@ -1151,6 +1160,7 @@ proc createVar(p: PProc, typ: PType, indirect: bool): Rope =
       addf(result, "Field$1: $2" | "Field$# = $#", [i.rope,
            createVar(p, t.sons[i], false)])
     add(result, "}")
+    if indirect: result = "[$1]" % [result]
   of tyObject:
     result = rope("{")
     var c = 0
@@ -1161,6 +1171,7 @@ proc createVar(p: PProc, typ: PType, indirect: bool): Rope =
       add(result, createRecordVarAux(p, t.n, c))
       t = t.sons[0]
     add(result, "}")
+    if indirect: result = "[$1]" % [result]
   of tyVar, tyPtr, tyRef:
     if mapType(t) == etyBaseIndex:
       result = putToSeq("[null, 0]" | "{nil, 0}", indirect)
@@ -1172,11 +1183,6 @@ proc createVar(p: PProc, typ: PType, indirect: bool): Rope =
     internalError("createVar: " & $t.kind)
     result = nil
 
-proc isIndirect(v: PSym): bool =
-  result = {sfAddrTaken, sfGlobal} * v.flags != {} and
-    (mapType(v.typ) != etyObject) and
-    v.kind notin {skProc, skConverter, skMethod, skIterator, skClosureIterator}
-
 proc genVarInit(p: PProc, v: PSym, n: PNode) =
   var
     a: TCompRes
@@ -1207,7 +1213,7 @@ proc genVarInit(p: PProc, v: PSym, n: PNode) =
     else:
       s = a.res
     if isIndirect(v):
-      addf(p.body, "var $1 = [$2];$n" | "local $1 = {$2};$n", [v.loc.r, s])
+      addf(p.body, "var $1 = /**/[$2];$n" | "local $1 = {$2};$n", [v.loc.r, s])
     else:
       addf(p.body, "var $1 = $2;$n" | "local $1 = $2;$n", [v.loc.r, s])
 
@@ -1239,7 +1245,7 @@ proc genNew(p: PProc, n: PNode) =
   var a: TCompRes
   gen(p, n.sons[1], a)
   var t = skipTypes(n.sons[1].typ, abstractVar).sons[0]
-  addf(p.body, "$1 = $2;$n", [a.res, createVar(p, t, true)])
+  addf(p.body, "$1 = $2;$n", [a.res, createVar(p, t, false)])
 
 proc genNewSeq(p: PProc, n: PNode) =
   var x, y: TCompRes
@@ -1325,14 +1331,17 @@ proc genMagic(p: PProc, n: PNode, r: var TCompRes) =
     # XXX: range checking?
     if not (optOverflowCheck in p.options): unaryExpr(p, n, r, "", "$1 - 1")
     else: unaryExpr(p, n, r, "subInt", "subInt($1, 1)")
-  of mAppendStrCh: binaryExpr(p, n, r, "addChar", "addChar($1, $2)")
+  of mAppendStrCh: binaryExpr(p, n, r, "addChar",
+        "if ($1 != null) { addChar($1, $2); } else { $1 = [$2, 0]; }")
   of mAppendStrStr:
     if skipTypes(n.sons[1].typ, abstractVarRange).kind == tyCString:
-        binaryExpr(p, n, r, "", "$1 += $2")
+        binaryExpr(p, n, r, "", "if ($1 != null) { $1 += $2; } else { $1 = $2; }")
     else:
-      binaryExpr(p, n, r, "", "$1 = ($1.slice(0, -1)).concat($2)")
+      binaryExpr(p, n, r, "",
+        "if ($1 != null) { $1 = ($1.slice(0, -1)).concat($2); } else { $1 = $2;}")
     # XXX: make a copy of $2, because of Javascript's sucking semantics
-  of mAppendSeqElem: binaryExpr(p, n, r, "", "$1.push($2)")
+  of mAppendSeqElem: binaryExpr(p, n, r, "",
+        "if ($1 != null) { $1.push($2); } else { $1 = [$2]; }")
   of mConStrStr: genConStrStr(p, n, r)
   of mEqStr: binaryExpr(p, n, r, "eqStrings", "eqStrings($1, $2)")
   of mLeStr: binaryExpr(p, n, r, "cmpStrings", "(cmpStrings($1, $2) <= 0)")
@@ -1343,14 +1352,17 @@ proc genMagic(p: PProc, n: PNode, r: var TCompRes) =
   of mSizeOf: r.res = rope(getSize(n.sons[1].typ))
   of mChr, mArrToSeq: gen(p, n.sons[1], r)      # nothing to do
   of mOrd: genOrd(p, n, r)
-  of mLengthStr: unaryExpr(p, n, r, "", "($1.length-1)")
+  of mLengthStr: unaryExpr(p, n, r, "", "($1 != null ? $1.length-1 : 0)")
+  of mXLenStr: unaryExpr(p, n, r, "", "$1.length-1")
   of mLengthSeq, mLengthOpenArray, mLengthArray:
+    unaryExpr(p, n, r, "", "($1 != null ? $1.length : 0)")
+  of mXLenSeq:
     unaryExpr(p, n, r, "", "$1.length")
   of mHigh:
     if skipTypes(n.sons[1].typ, abstractVar).kind == tyString:
-      unaryExpr(p, n, r, "", "($1.length-2)")
+      unaryExpr(p, n, r, "", "($1 != null ? ($1.length-2) : -1)")
     else:
-      unaryExpr(p, n, r, "", "($1.length-1)")
+      unaryExpr(p, n, r, "", "($1 != null ? ($1.length-1) : -1)")
   of mInc:
     if optOverflowCheck notin p.options: binaryExpr(p, n, r, "", "$1 += $2")
     else: binaryExpr(p, n, r, "addInt", "$1 = addInt($1, $2)")
diff --git a/compiler/lexer.nim b/compiler/lexer.nim
index 694d6f4d7..8080e0e8c 100644
--- a/compiler/lexer.nim
+++ b/compiler/lexer.nim
@@ -61,7 +61,7 @@ type
     tkComma, tkSemiColon,
     tkColon, tkColonColon, tkEquals, tkDot, tkDotDot,
     tkOpr, tkComment, tkAccent,
-    tkSpaces, tkInfixOpr, tkPrefixOpr, tkPostfixOpr,
+    tkSpaces, tkInfixOpr, tkPrefixOpr, tkPostfixOpr
 
   TTokTypes* = set[TTokType]
 
@@ -221,6 +221,10 @@ proc dispMessage(L: TLexer; info: TLineInfo; msg: TMsgKind; arg: string) =
 proc lexMessage*(L: TLexer, msg: TMsgKind, arg = "") =
   L.dispMessage(getLineInfo(L), msg, arg)
 
+proc lexMessageTok*(L: TLexer, msg: TMsgKind, tok: TToken, arg = "") =
+  var info = newLineInfo(L.fileIdx, tok.line, tok.col)
+  L.dispMessage(info, msg, arg)
+
 proc lexMessagePos(L: var TLexer, msg: TMsgKind, pos: int, arg = "") =
   var info = newLineInfo(L.fileIdx, L.lineNumber, pos - L.lineStart)
   L.dispMessage(info, msg, arg)
@@ -863,6 +867,15 @@ proc rawGetTok*(L: var TLexer, tok: var TToken) =
     of '`':
       tok.tokType = tkAccent
       inc(L.bufpos)
+    of '_':
+      inc(L.bufpos)
+      if L.buf[L.bufpos] notin SymChars:
+        tok.tokType = tkSymbol
+        tok.ident = getIdent("_")
+      else:
+        tok.literal = $c
+        tok.tokType = tkInvalid
+        lexMessage(L, errInvalidToken, c & " (\\" & $(ord(c)) & ')')
     of '\"':
       # check for extended raw string literal:
       var rawMode = L.bufpos > 0 and L.buf[L.bufpos-1] in SymChars
diff --git a/compiler/lowerings.nim b/compiler/lowerings.nim
index 0b4f97ead..b6b01d558 100644
--- a/compiler/lowerings.nim
+++ b/compiler/lowerings.nim
@@ -15,6 +15,10 @@ const
 import ast, astalgo, types, idents, magicsys, msgs, options
 from trees import getMagic
 
+proc newDeref*(n: PNode): PNode {.inline.} =
+  result = newNodeIT(nkHiddenDeref, n.info, n.typ.sons[0])
+  addSon(result, n)
+
 proc newTupleAccess*(tup: PNode, i: int): PNode =
   result = newNodeIT(nkBracketExpr, tup.info, tup.typ.skipTypes(
                      abstractInst).sons[i])
diff --git a/compiler/main.nim b/compiler/main.nim
index 0c80c19b7..a01b6fe4f 100644
--- a/compiler/main.nim
+++ b/compiler/main.nim
@@ -63,7 +63,7 @@ proc commandCompileToC =
   compileProject()
   cgenWriteModules()
   if gCmd != cmdRun:
-    extccomp.callCCompiler(if gProjectName == "-": "stdinfile" else: changeFileExt(gProjectFull, ""))
+    extccomp.callCCompiler(changeFileExt(gProjectFull, ""))
 
   if isServing:
     # caas will keep track only of the compilation commands
diff --git a/compiler/modules.nim b/compiler/modules.nim
index a2b739efc..2fa46f356 100644
--- a/compiler/modules.nim
+++ b/compiler/modules.nim
@@ -10,8 +10,8 @@
 ## implements the module handling
 
 import
-  ast, astalgo, magicsys, crc, rodread, msgs, cgendata, sigmatch, options, 
-  idents, os, lexer, idgen, passes, syntaxes
+  ast, astalgo, magicsys, crc, rodread, msgs, cgendata, sigmatch, options,
+  idents, os, lexer, idgen, passes, syntaxes, llstream
 
 type
   TNeedRecompile* = enum Maybe, No, Yes, Probing, Recompiled
@@ -39,12 +39,12 @@ template crc(x: PSym): expr =
 
 proc crcChanged(fileIdx: int32): bool =
   internalAssert fileIdx >= 0 and fileIdx < gMemCacheData.len
-  
+
   template updateStatus =
     gMemCacheData[fileIdx].crcStatus = if result: crcHasChanged
                                        else: crcNotChanged
     # echo "TESTING CRC: ", fileIdx.toFilename, " ", result
-  
+
   case gMemCacheData[fileIdx].crcStatus:
   of crcHasChanged:
     result = true
@@ -96,7 +96,7 @@ proc checkDepMem(fileIdx: int32): TNeedRecompile =
   if optForceFullMake in gGlobalOptions or
      crcChanged(fileIdx):
        markDirty
-  
+
   if gMemCacheData[fileIdx].deps != nil:
     gMemCacheData[fileIdx].needsRecompile = Probing
     for dep in gMemCacheData[fileIdx].deps:
@@ -104,30 +104,30 @@ proc checkDepMem(fileIdx: int32): TNeedRecompile =
       if d in {Yes, Recompiled}:
         # echo fileIdx.toFilename, " depends on ", dep.toFilename, " ", d
         markDirty
-  
+
   gMemCacheData[fileIdx].needsRecompile = No
   return No
 
 proc newModule(fileIdx: int32): PSym =
   # We cannot call ``newSym`` here, because we have to circumvent the ID
-  # mechanism, which we do in order to assign each module a persistent ID. 
+  # mechanism, which we do in order to assign each module a persistent ID.
   new(result)
   result.id = - 1             # for better error checking
   result.kind = skModule
   let filename = fileIdx.toFullPath
   result.name = getIdent(splitFile(filename).name)
-  if result.name.s != "-" and not isNimIdentifier(result.name.s):
+  if not isNimIdentifier(result.name.s):
     rawMessage(errInvalidModuleName, result.name.s)
-  
+
   result.info = newLineInfo(fileIdx, 1, 1)
   result.owner = newSym(skPackage, getIdent(getPackageName(filename)), nil,
                         result.info)
   result.position = fileIdx
-  
+
   growCache gMemCacheData, fileIdx
   growCache gCompiledModules, fileIdx
   gCompiledModules[result.position] = result
-  
+
   incl(result.flags, sfUsed)
   initStrTable(result.tab)
   strTableAdd(result.tab, result) # a module knows itself
@@ -143,12 +143,15 @@ proc compileModule*(fileIdx: int32, flags: TSymFlags): PSym =
     result.flags = result.flags + flags
     if gCmd in {cmdCompileToC, cmdCompileToCpp, cmdCheck, cmdIdeTools}:
       rd = handleSymbolFile(result)
-      if result.id < 0: 
+      if result.id < 0:
         internalError("handleSymbolFile should have set the module\'s ID")
         return
     else:
       result.id = getID()
-    processModule(result, nil, rd)
+    if sfMainModule in flags and gProjectIsStdin:
+      processModule(result, llStreamOpen(stdin), rd)
+    else:
+      processModule(result, nil, rd)
     if optCaasEnabled in gGlobalOptions:
       gMemCacheData[fileIdx].compiledAt = gLastCmdTime
       gMemCacheData[fileIdx].needsRecompile = Recompiled
diff --git a/compiler/msgs.nim b/compiler/msgs.nim
index 3f5c4763e..041a181be 100644
--- a/compiler/msgs.nim
+++ b/compiler/msgs.nim
@@ -738,7 +738,7 @@ proc writeContext(lastinfo: TLineInfo) =
     if msgContext[i] != lastinfo and msgContext[i] != info:
       msgWriteln(PosContextFormat % [toMsgFilename(msgContext[i]),
                                      coordToStr(msgContext[i].line),
-                                     coordToStr(msgContext[i].col),
+                                     coordToStr(msgContext[i].col+1),
                                      getMessageStr(errInstantiationFrom, "")])
     info = msgContext[i]
 
@@ -781,7 +781,7 @@ proc formatMsg*(info: TLineInfo, msg: TMsgKind, arg: string): string =
              of hintMin..hintMax: PosHintFormat
              else: PosErrorFormat
   result = frmt % [toMsgFilename(info), coordToStr(info.line),
-                   coordToStr(info.col), getMessageStr(msg, arg)]
+                   coordToStr(info.col+1), getMessageStr(msg, arg)]
 
 proc liMessage(info: TLineInfo, msg: TMsgKind, arg: string,
                eh: TErrorHandling) =
@@ -804,8 +804,11 @@ proc liMessage(info: TLineInfo, msg: TMsgKind, arg: string,
     ignoreMsg = optHints notin gOptions or msg notin gNotes
     frmt = PosHintFormat
     inc(gHintCounter)
+  # NOTE: currently line info line numbers start with 1,
+  # but column numbers start with 0, however most editors expect
+  # first column to be 1, so we need to +1 here
   let s = frmt % [toMsgFilename(info), coordToStr(info.line),
-                  coordToStr(info.col), getMessageStr(msg, arg)]
+                  coordToStr(info.col+1), getMessageStr(msg, arg)]
   if not ignoreMsg and not ignoreMsgBecauseOfIdeTools(msg):
     msgWriteln(s)
     if optPrintSurroundingSrc and msg in errMin..errMax:
@@ -827,6 +830,9 @@ proc localError*(info: TLineInfo, msg: TMsgKind, arg = "") =
 proc localError*(info: TLineInfo, arg: string) =
   liMessage(info, errGenerated, arg, doNothing)
 
+proc localError*(info: TLineInfo, format: string, params: openarray[string]) =
+  localError(info, format % params)
+
 proc message*(info: TLineInfo, msg: TMsgKind, arg = "") =
   liMessage(info, msg, arg, doNothing)
 
diff --git a/compiler/nim.nim b/compiler/nim.nim
index b8ba2c6da..89db22e8f 100644
--- a/compiler/nim.nim
+++ b/compiler/nim.nim
@@ -38,7 +38,12 @@ proc handleCmdLine() =
   else:
     # Process command line arguments:
     processCmdLine(passCmd1, "")
-    if gProjectName != "":
+    if gProjectName == "-":
+      gProjectName = "stdinfile"
+      gProjectFull = "stdinfile"
+      gProjectPath = getCurrentDir()
+      gProjectIsStdin = true
+    elif gProjectName != "":
       try:
         gProjectFull = canonicalizePath(gProjectName)
       except OSError:
@@ -61,8 +66,6 @@ proc handleCmdLine() =
         if gCmd == cmdRun:
           tccgen.run(commands.arguments)
       if optRun in gGlobalOptions:
-        if gProjectName == "-":
-          gProjectFull = "stdinfile"
         if gCmd == cmdCompileToJS:
           var ex: string
           if options.outFile.len > 0:
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..2c785d118 100644
--- a/compiler/nimsuggest/nimsuggest.nim
+++ b/compiler/nimsuggest/nimsuggest.nim
@@ -9,9 +9,17 @@
 
 ## Nimsuggest is a tool that helps to give editors IDE like capabilities.
 
-import strutils, os, parseopt, parseUtils
+import strutils, os, parseopt, parseutils, sequtils, net
+# Do NOT import suggest. It will lead to wierd bugs with
+# suggestionResultHook, because suggest.nim is included by sigmatch.
+# So we import that one instead.
 import options, commands, modules, sem, passes, passaux, msgs, nimconf,
-  extccomp, condsyms, lists, net, rdstdin
+  extccomp, condsyms, lists, net, rdstdin, sexp, sigmatch, ast
+
+when defined(windows):
+  import winlean
+else:
+  import posix
 
 const Usage = """
 Nimsuggest - Tool to give every editor IDE like capabilities for Nim
@@ -23,17 +31,20 @@ Options:
   --address:HOST          binds to that address, by default ""
   --stdin                 read commands from stdin and write results to
                           stdout instead of using sockets
+  --epc                   use emacs epc mode
 
 The server then listens to the connection and takes line-based commands.
 
 In addition, all command line options of Nim that do not affect code generation
 are supported.
 """
+type
+  Mode = enum mstdin, mtcp, mepc
 
 var
   gPort = 6000.Port
   gAddress = ""
-  gUseStdin: bool
+  gMode: Mode
 
 const
   seps = {':', ';', ' ', '\t'}
@@ -42,6 +53,9 @@ const
          "type 'debug' to toggle debug mode on/off\n" &
          "type 'terse' to toggle terse mode on/off"
 
+type
+  EUnexpectedCommand = object of Exception
+
 proc parseQuoted(cmd: string; outp: var string; start: int): int =
   var i = start
   i += skipWhitespace(cmd, i)
@@ -51,7 +65,95 @@ proc parseQuoted(cmd: string; outp: var string; start: int): int =
     i += parseUntil(cmd, outp, seps, i)
   result = i
 
-proc action(cmd: string) =
+proc sexp(s: IdeCmd): SexpNode = sexp($s)
+
+proc sexp(s: TSymKind): SexpNode = sexp($s)
+
+proc sexp(s: Suggest): SexpNode =
+  # If you change the oder here, make sure to change it over in
+  # nim-mode.el too.
+  result = convertSexp([
+    s.section,
+    s.symkind,
+    s.qualifiedPath.map(newSString),
+    s.filePath,
+    s.forth,
+    s.line,
+    s.column,
+    s.doc
+  ])
+
+proc sexp(s: seq[Suggest]): SexpNode =
+  result = newSList()
+  for sug in s:
+    result.add(sexp(sug))
+
+proc listEPC(): SexpNode =
+  let
+    argspecs = sexp("file line column dirtyfile".split(" ").map(newSSymbol))
+    docstring = sexp("line starts at 1, column at 0, dirtyfile is optional")
+  result = newSList()
+  for command in ["sug", "con", "def", "use"]:
+    let
+      cmd = sexp(command)
+      methodDesc = newSList()
+    methodDesc.add(cmd)
+    methodDesc.add(argspecs)
+    methodDesc.add(docstring)
+    result.add(methodDesc)
+
+proc execute(cmd: IdeCmd, file, dirtyfile: string, line, col: int) =
+  gIdeCmd = cmd
+  if cmd == ideUse:
+    modules.resetAllModules()
+  var isKnownFile = true
+  let dirtyIdx = file.fileInfoIdx(isKnownFile)
+
+  if dirtyfile.len != 0: msgs.setDirtyFile(dirtyIdx, dirtyfile)
+  else: msgs.setDirtyFile(dirtyIdx, nil)
+
+  resetModule dirtyIdx
+  if dirtyIdx != gProjectMainIdx:
+    resetModule gProjectMainIdx
+
+  gTrackPos = newLineInfo(dirtyIdx, line, col)
+  gErrorCounter = 0
+  if not isKnownFile:
+    compileProject()
+  compileProject(dirtyIdx)
+
+proc executeEPC(cmd: IdeCmd, args: SexpNode) =
+  let
+    file = args[0].getStr
+    line = args[1].getNum
+    column = args[2].getNum
+  var dirtyfile = ""
+  if len(args) > 3:
+    dirtyfile = args[3].getStr(nil)
+  execute(cmd, file, dirtyfile, int(line), int(column))
+
+proc returnEPC(socket: var Socket, uid: BiggestInt, s: SexpNode, return_symbol = "return") =
+  let response = $convertSexp([newSSymbol(return_symbol), uid, s])
+  socket.send(toHex(len(response), 6))
+  socket.send(response)
+
+proc connectToNextFreePort(server: Socket, host: string, start = 30000): int =
+  result = start
+  while true:
+    try:
+      server.bindaddr(Port(result), host)
+      return
+    except OsError:
+      when defined(windows):
+        let checkFor = WSAEADDRINUSE.OSErrorCode
+      else:
+        let checkFor = EADDRINUSE.OSErrorCode
+      if osLastError() != checkFor:
+        raise getCurrentException()
+      else:
+        result += 1
+
+proc parseCmdLine(cmd: string) =
   template toggle(sw) =
     if sw in gGlobalOptions:
       excl(gGlobalOptions, sw)
@@ -69,9 +171,7 @@ proc action(cmd: string) =
   of "sug": gIdeCmd = ideSug
   of "con": gIdeCmd = ideCon
   of "def": gIdeCmd = ideDef
-  of "use":
-    modules.resetAllModules()
-    gIdeCmd = ideUse
+  of "use": gIdeCmd = ideUse
   of "quit": quit()
   of "debug": toggle optIdeDebug
   of "terse": toggle optIdeTerse
@@ -82,40 +182,24 @@ 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)
 
-  var isKnownFile = true
-  if orig.len == 0: err()
-  let dirtyIdx = orig.fileInfoIdx(isKnownFile)
-
-  if dirtyfile.len != 0: msgs.setDirtyFile(dirtyIdx, dirtyfile)
-  else: msgs.setDirtyFile(dirtyIdx, nil)
-
-  resetModule dirtyIdx
-  if dirtyIdx != gProjectMainIdx:
-    resetModule gProjectMainIdx
-  gTrackPos = newLineInfo(dirtyIdx, line, col)
-  #echo dirtyfile, gDirtyBufferIdx, " project ", gProjectMainIdx
-  gErrorCounter = 0
-  if not isKnownFile:
-    compileProject(dirtyIdx)
-  else:
-    compileProject()
+  execute(gIdeCmd, orig, dirtyfile, line, col-1)
 
 proc serve() =
-  # do not stop after the first error:
-  msgs.gErrorMax = high(int)
-  if gUseStdin:
+  case gMode:
+  of mstdin:
     echo Help
     var line = ""
     while readLineFromStdin("> ", line):
-      action line
+      parseCmdLine line
       echo ""
       flushFile(stdout)
-  else:
+  of mtcp:
     var server = newSocket()
     server.bindAddr(gPort, gAddress)
     var inp = "".TaintedString
@@ -129,10 +213,55 @@ proc serve() =
       accept(server, stdoutSocket)
 
       stdoutSocket.readLine(inp)
-      action inp.string
+      parseCmdLine inp.string
 
       stdoutSocket.send("\c\L")
       stdoutSocket.close()
+  of mepc:
+    var server = newSocket()
+    let port = connectToNextFreePort(server, "localhost")
+    var inp = "".TaintedString
+    server.listen()
+    echo(port)
+    var client = newSocket()
+    # Wait for connection
+    accept(server, client)
+    while true:
+      var sizeHex = ""
+      if client.recv(sizeHex, 6) != 6:
+        raise newException(ValueError, "didn't get all the hexbytes")
+      var size = 0
+      if parseHex(sizeHex, size) == 0:
+        raise newException(ValueError, "invalid size hex: " & $sizeHex)
+      var messageBuffer = ""
+      if client.recv(messageBuffer, size) != size:
+        raise newException(ValueError, "didn't get all the bytes")
+      let
+        message = parseSexp($messageBuffer)
+        messageType = message[0].getSymbol
+      case messageType:
+      of "call":
+        var results: seq[Suggest] = @[]
+        suggestionResultHook = proc (s: Suggest) =
+          results.add(s)
+
+        let
+          uid = message[1].getNum
+          cmd = parseIdeCmd(message[2].getSymbol)
+          args = message[3]
+        executeEPC(cmd, args)
+        returnEPC(client, uid, sexp(results))
+      of "return":
+        raise newException(EUnexpectedCommand, "no return expected")
+      of "return-error":
+        raise newException(EUnexpectedCommand, "no return expected")
+      of "epc-error":
+        stderr.writeln("recieved epc error: " & $messageBuffer)
+        raise newException(IOError, "epc error")
+      of "methods":
+        returnEPC(client, message[1].getNum, listEPC())
+      else:
+        raise newException(EUnexpectedCommand, "unexpected call: " & messageType)
 
 proc mainCommand =
   registerPass verbosePass
@@ -146,6 +275,9 @@ proc mainCommand =
     # current path is always looked first for modules
     prependStr(searchPaths, gProjectPath)
 
+  # do not stop after the first error:
+  msgs.gErrorMax = high(int)
+  compileProject()
   serve()
 
 proc processCmdLine*(pass: TCmdLinePass, cmd: string) =
@@ -156,9 +288,16 @@ proc processCmdLine*(pass: TCmdLinePass, cmd: string) =
     of cmdEnd: break 
     of cmdLongoption, cmdShortOption: 
       case p.key.normalize
-      of "port": gPort = parseInt(p.val).Port
-      of "address": gAddress = p.val
-      of "stdin": gUseStdin = true
+      of "port":
+        gPort = parseInt(p.val).Port
+        gMode = mtcp
+      of "address":
+        gAddress = p.val
+        gMode = mtcp
+      of "stdin": gMode = mstdin
+      of "epc":
+        gMode = mepc
+        gVerbosity = 0          # Port number gotta be first.
       else: processSwitch(pass, p)
     of cmdArgument:
       options.gProjectName = unixToNativePath(p.key)
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..b3060a180 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.
@@ -83,11 +83,11 @@ type                          # please make sure we have under 32 options
   TGCMode* = enum             # the selected GC
     gcNone, gcBoehm, gcMarkAndSweep, gcRefc, gcV2, gcGenerational
 
-  TIdeCmd* = enum
+  IdeCmd* = enum
     ideNone, ideSug, ideCon, ideDef, ideUse
 
 var
-  gIdeCmd*: TIdeCmd
+  gIdeCmd*: IdeCmd
 
 const
   ChecksOptions* = {optObjCheck, optFieldCheck, optRangeCheck, optNilCheck,
@@ -149,6 +149,7 @@ var
   gProjectName* = "" # holds a name like 'nimrod'
   gProjectPath* = "" # holds a path like /home/alice/projects/nimrod/compiler/
   gProjectFull* = "" # projectPath/projectName
+  gProjectIsStdin* = false # whether we're compiling from stdin
   gProjectMainIdx*: int32 # the canonical path id of the main module
   nimcacheDir* = ""
   command* = "" # the main command (e.g. cc, check, scan, etc)
@@ -395,3 +396,18 @@ template cnimdbg*: expr = p.module.module.fileIdx == gProjectMainIdx
 template pnimdbg*: expr = p.lex.fileIdx == gProjectMainIdx
 template lnimdbg*: expr = L.fileIdx == gProjectMainIdx
 
+proc parseIdeCmd*(s: string): IdeCmd =
+  case s:
+  of "sug": ideSug
+  of "con": ideCon
+  of "def": ideDef
+  of "use": ideUse
+  else: ideNone
+
+proc `$`*(c: IdeCmd): string =
+  case c:
+  of ideSug: "sug"
+  of ideCon: "con"
+  of ideDef: "def"
+  of ideUse: "use"
+  of ideNone: "none"
diff --git a/compiler/parampatterns.nim b/compiler/parampatterns.nim
index 3f67005b9..b7fe269df 100644
--- a/compiler/parampatterns.nim
+++ b/compiler/parampatterns.nim
@@ -190,6 +190,8 @@ proc isAssignable*(owner: PSym, n: PNode): TAssignableResult =
         result = arLocalLValue
       else:
         result = arLValue
+    elif n.sym.kind == skParam and n.sym.typ.kind == tyVar:
+      result = arLValue
     elif n.sym.kind == skType:
       let t = n.sym.typ.skipTypes({tyTypeDesc})
       if t.kind == tyVar: result = arStrange
diff --git a/compiler/parser.nim b/compiler/parser.nim
index d2831ea46..0d2ba7cfc 100644
--- a/compiler/parser.nim
+++ b/compiler/parser.nim
@@ -91,7 +91,7 @@ proc closeParser(p: var TParser) =
 
 proc parMessage(p: TParser, msg: TMsgKind, arg = "") =
   ## Produce and emit the parser message `arg` to output.
-  lexMessage(p.lex, msg, arg)
+  lexMessageTok(p.lex, msg, p.tok, arg)
 
 proc parMessage(p: TParser, msg: TMsgKind, tok: TToken) =
   ## Produce and emit a parser message to output about the token `tok`
@@ -154,7 +154,7 @@ proc eat(p: var TParser, tokType: TTokType) =
   if p.tok.tokType == tokType:
     getTok(p)
   else:
-    lexMessage(p.lex, errTokenExpected, TokTypeToStr[tokType])
+    lexMessageTok(p.lex, errTokenExpected, p.tok, TokTypeToStr[tokType])
 
 proc parLineInfo(p: TParser): TLineInfo =
   ## Retrieve the line information associated with the parser's current state.
@@ -212,7 +212,8 @@ proc getPrecedence(tok: TToken, strongSpaces: bool): int =
     let relevantChar = tok.ident.s[0]
 
     # arrow like?
-    if L > 1 and tok.ident.s[L-1] == '>': return considerStrongSpaces(1)
+    if L > 1 and tok.ident.s[L-1] == '>' and
+      tok.ident.s[L-2] in {'-', '~', '='}: return considerStrongSpaces(1)
 
     template considerAsgn(value: expr) =
       result = if tok.ident.s[L-1] == '=': 1 else: value
@@ -388,7 +389,6 @@ proc exprList(p: var TParser, endTok: TTokType, result: PNode) =
     if p.tok.tokType != tkComma: break
     getTok(p)
     optInd(p, a)
-  eat(p, endTok)
 
 proc dotExpr(p: var TParser, a: PNode): PNode =
   #| dotExpr = expr '.' optInd symbol
@@ -944,8 +944,7 @@ proc parseDoBlock(p: var TParser): PNode =
   getTok(p)
   let params = parseParamList(p, retColon=false)
   let pragmas = optPragmas(p)
-  eat(p, tkColon)
-  skipComment(p, result)
+  colcom(p, result)
   result = newProcNode(nkDo, info, parseStmt(p),
                        params = params,
                        pragmas = pragmas)
@@ -1139,9 +1138,11 @@ proc parseMacroColon(p: var TParser, x: PNode): PNode =
     result = makeCall(result)
     getTok(p)
     skipComment(p, result)
+    let stmtList = newNodeP(nkStmtList, p)
     if p.tok.tokType notin {tkOf, tkElif, tkElse, tkExcept}:
       let body = parseStmt(p)
-      addSon(result, makeStmtList(body))
+      stmtList.add body
+      #addSon(result, makeStmtList(body))
     while sameInd(p):
       var b: PNode
       case p.tok.tokType
@@ -1153,19 +1154,22 @@ proc parseMacroColon(p: var TParser, x: PNode): PNode =
         getTok(p)
         optInd(p, b)
         addSon(b, parseExpr(p))
-        eat(p, tkColon)
       of tkExcept:
         b = newNodeP(nkExceptBranch, p)
         exprList(p, tkColon, b)
-        skipComment(p, b)
       of tkElse:
         b = newNodeP(nkElse, p)
         getTok(p)
-        eat(p, tkColon)
       else: break
+      eat(p, tkColon)
       addSon(b, parseStmt(p))
-      addSon(result, b)
+      addSon(stmtList, b)
       if b.kind == nkElse: break
+    if stmtList.len == 1 and stmtList[0].kind == nkStmtList:
+      # to keep backwards compatibility (see tests/vm/tstringnil)
+      result.add stmtList[0]
+    else:
+      result.add stmtList
 
 proc parseExprStmt(p: var TParser): PNode =
   #| exprStmt = simpleExpr
@@ -1310,8 +1314,7 @@ proc parseIfOrWhen(p: var TParser, kind: TNodeKind): PNode =
     var branch = newNodeP(nkElifBranch, p)
     optInd(p, branch)
     addSon(branch, parseExpr(p))
-    eat(p, tkColon)
-    skipComment(p, branch)
+    colcom(p, branch)
     addSon(branch, parseStmt(p))
     skipComment(p, branch)
     addSon(result, branch)
@@ -1319,8 +1322,7 @@ proc parseIfOrWhen(p: var TParser, kind: TNodeKind): PNode =
   if p.tok.tokType == tkElse and sameOrNoInd(p):
     var branch = newNodeP(nkElse, p)
     eat(p, tkElse)
-    eat(p, tkColon)
-    skipComment(p, branch)
+    colcom(p, branch)
     addSon(branch, parseStmt(p))
     addSon(result, branch)
 
@@ -1368,13 +1370,11 @@ proc parseCase(p: var TParser): PNode =
       getTok(p)
       optInd(p, b)
       addSon(b, parseExpr(p))
-      eat(p, tkColon)
     of tkElse:
       b = newNodeP(nkElse, p)
       getTok(p)
-      eat(p, tkColon)
     else: break
-    skipComment(p, b)
+    colcom(p, b)
     addSon(b, parseStmt(p))
     addSon(result, b)
     if b.kind == nkElse: break
@@ -1391,8 +1391,7 @@ proc parseTry(p: var TParser; isExpr: bool): PNode =
   #|            (optInd 'finally' colcom stmt)?
   result = newNodeP(nkTryStmt, p)
   getTok(p)
-  eat(p, tkColon)
-  skipComment(p, result)
+  colcom(p, result)
   addSon(result, parseStmt(p))
   var b: PNode = nil
   while sameOrNoInd(p) or isExpr:
@@ -1402,10 +1401,9 @@ proc parseTry(p: var TParser; isExpr: bool): PNode =
       exprList(p, tkColon, b)
     of tkFinally:
       b = newNodeP(nkFinally, p)
-      getTokNoInd(p)
-      eat(p, tkColon)
+      getTok(p)
     else: break
-    skipComment(p, b)
+    colcom(p, b)
     addSon(b, parseStmt(p))
     addSon(result, b)
     if b.kind == nkFinally: break
@@ -1414,7 +1412,7 @@ proc parseTry(p: var TParser; isExpr: bool): PNode =
 proc parseExceptBlock(p: var TParser, kind: TNodeKind): PNode =
   #| exceptBlock = 'except' colcom stmt
   result = newNodeP(kind, p)
-  getTokNoInd(p)
+  getTok(p)
   colcom(p, result)
   addSon(result, parseStmt(p))
 
@@ -1447,7 +1445,7 @@ proc parseStaticOrDefer(p: var TParser; k: TNodeKind): PNode =
   #| staticStmt = 'static' colcom stmt
   #| deferStmt = 'defer' colcom stmt
   result = newNodeP(k, p)
-  getTokNoInd(p)
+  getTok(p)
   colcom(p, result)
   addSon(result, parseStmt(p))
 
@@ -1628,7 +1626,7 @@ proc parseEnum(p: var TParser): PNode =
         p.tok.tokType == tkEof:
       break
   if result.len <= 1:
-    lexMessage(p.lex, errIdentifierExpected, prettyTok(p.tok))
+    lexMessageTok(p.lex, errIdentifierExpected, p.tok, prettyTok(p.tok))
 
 proc parseObjectPart(p: var TParser): PNode
 proc parseObjectWhen(p: var TParser): PNode =
@@ -1686,9 +1684,8 @@ proc parseObjectCase(p: var TParser): PNode =
     of tkElse:
       b = newNodeP(nkElse, p)
       getTok(p)
-      eat(p, tkColon)
     else: break
-    skipComment(p, b)
+    colcom(p, b)
     var fields = parseObjectPart(p)
     if fields.kind == nkEmpty:
       parMessage(p, errIdentifierExpected, p.tok)
@@ -1884,7 +1881,7 @@ proc simpleStmt(p: var TParser): PNode =
 
 proc complexOrSimpleStmt(p: var TParser): PNode =
   #| complexOrSimpleStmt = (ifStmt | whenStmt | whileStmt
-  #|                     | tryStmt | finallyStmt | exceptStmt | forStmt
+  #|                     | tryStmt | forStmt
   #|                     | blockStmt | staticStmt | deferStmt | asmStmt
   #|                     | 'proc' routine
   #|                     | 'method' routine
diff --git a/compiler/passes.nim b/compiler/passes.nim
index 129d8ad47..e031dae10 100644
--- a/compiler/passes.nim
+++ b/compiler/passes.nim
@@ -170,11 +170,7 @@ proc processModule(module: PSym, stream: PLLStream, rd: PRodReader) =
     openPasses(a, module)
     if stream == nil:
       let filename = fileIdx.toFullPathConsiderDirty
-      if module.name.s == "-":
-        module.name.s = "stdinfile"
-        s = llStreamOpen(stdin)
-      else:
-        s = llStreamOpen(filename, fmRead)
+      s = llStreamOpen(filename, fmRead)
       if s == nil:
         rawMessage(errCannotOpenFile, filename)
         return
diff --git a/compiler/plugins.nim b/compiler/plugins.nim
new file mode 100644
index 000000000..1c9b7b77b
--- /dev/null
+++ b/compiler/plugins.nim
@@ -0,0 +1,43 @@
+#
+#
+#           The Nim Compiler
+#        (c) Copyright 2015 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+## Plugin support for the Nim compiler. Right now there are no plugins and they
+## need to be build with the compiler, no DLL support.
+
+import ast, semdata, idents
+
+type
+  Transformation* = proc (c: PContext; n: PNode): PNode {.nimcall.}
+  Plugin = ref object
+    fn, module, package: PIdent
+    t: Transformation
+    next: Plugin
+
+proc pluginMatches(p: Plugin; s: PSym): bool =
+  if s.name.id != p.fn.id: return false
+  let module = s.owner
+  if module == nil or module.kind != skModule or
+      module.name.id != p.module.id: return false
+  let package = module.owner
+  if package == nil or package.kind != skPackage or
+      package.name.id != p.package.id: return false
+  return true
+
+var head: Plugin
+
+proc getPlugin*(fn: PSym): Transformation =
+  var it = head
+  while it != nil:
+    if pluginMatches(it, fn): return it.t
+    it = it.next
+
+proc registerPlugin*(package, module, fn: string; t: Transformation) =
+  let oldHead = head
+  head = Plugin(fn: getIdent(fn), module: getIdent(module),
+                 package: getIdent(package), t: t, next: oldHead)
diff --git a/compiler/plugins/active.nim b/compiler/plugins/active.nim
new file mode 100644
index 000000000..e9c11c2ea
--- /dev/null
+++ b/compiler/plugins/active.nim
@@ -0,0 +1,13 @@
+#
+#
+#           The Nim Compiler
+#        (c) Copyright 2015 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+## Include file that imports all plugins that are active.
+
+import
+  locals.locals
diff --git a/compiler/plugins/locals/locals.nim b/compiler/plugins/locals/locals.nim
new file mode 100644
index 000000000..d89149f33
--- /dev/null
+++ b/compiler/plugins/locals/locals.nim
@@ -0,0 +1,42 @@
+#
+#
+#           The Nim Compiler
+#        (c) Copyright 2015 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+## The builtin 'system.locals' implemented as a plugin.
+
+import plugins, ast, astalgo, magicsys, lookups, semdata, lowerings
+
+proc semLocals(c: PContext, n: PNode): PNode =
+  var counter = 0
+  var tupleType = newTypeS(tyTuple, c)
+  result = newNodeIT(nkPar, n.info, tupleType)
+  tupleType.n = newNodeI(nkRecList, n.info)
+  # for now we skip openarrays ...
+  for scope in walkScopes(c.currentScope):
+    if scope == c.topLevelScope: break
+    for it in items(scope.symbols):
+      # XXX parameters' owners are wrong for generics; this caused some pain
+      # for closures too; we should finally fix it.
+      #if it.owner != c.p.owner: return result
+      if it.kind in skLocalVars and
+          it.typ.skipTypes({tyGenericInst, tyVar}).kind notin
+            {tyVarargs, tyOpenArray, tyTypeDesc, tyStatic, tyExpr, tyStmt, tyEmpty}:
+
+        var field = newSym(skField, it.name, getCurrOwner(), n.info)
+        field.typ = it.typ.skipTypes({tyGenericInst, tyVar})
+        field.position = counter
+        inc(counter)
+
+        addSon(tupleType.n, newSymNode(field))
+        addSonSkipIntLit(tupleType, field.typ)
+
+        var a = newSymNode(it, result.info)
+        if it.typ.skipTypes({tyGenericInst}).kind == tyVar: a = newDeref(a)
+        result.add(a)
+
+registerPlugin("stdlib", "system", "locals", semLocals)
diff --git a/compiler/pragmas.nim b/compiler/pragmas.nim
index ec594069e..c048d78e9 100644
--- a/compiler/pragmas.nim
+++ b/compiler/pragmas.nim
@@ -60,7 +60,7 @@ const
   varPragmas* = {wImportc, wExportc, wVolatile, wRegister, wThreadVar, wNodecl,
     wMagic, wHeader, wDeprecated, wCompilerproc, wDynlib, wExtern,
     wImportCpp, wImportObjC, wError, wNoInit, wCompileTime, wGlobal,
-    wGensym, wInject, wCodegenDecl, wGuard}
+    wGensym, wInject, wCodegenDecl, wGuard, wGoto}
   constPragmas* = {wImportc, wExportc, wHeader, wDeprecated, wMagic, wNodecl,
     wExtern, wImportCpp, wImportObjC, wError, wGensym, wInject}
   letPragmas* = varPragmas
@@ -843,6 +843,11 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: int,
             invalidPragma(it)
           else:
             sym.guard = pragmaGuard(c, it, sym.kind)
+        of wGoto:
+          if sym == nil or sym.kind notin {skVar, skLet}:
+            invalidPragma(it)
+          else:
+            sym.flags.incl sfGoto
         of wInjectStmt:
           if it.kind != nkExprColonExpr:
             localError(it.info, errExprExpected)
diff --git a/compiler/sem.nim b/compiler/sem.nim
index 7eabaf491..346a17df1 100644
--- a/compiler/sem.nim
+++ b/compiler/sem.nim
@@ -16,7 +16,7 @@ import
   procfind, lookups, rodread, pragmas, passes, semdata, semtypinst, sigmatch,
   intsets, transf, vmdef, vm, idgen, aliases, cgmeth, lambdalifting,
   evaltempl, patterns, parampatterns, sempass2, nimfix.pretty, semmacrosanity,
-  semparallel, lowerings
+  semparallel, lowerings, plugins, plugins.active
 
 when defined(nimfix):
   import nimfix.prettybase
@@ -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/semdata.nim b/compiler/semdata.nim
index cf7a52ff5..345a8c0d1 100644
--- a/compiler/semdata.nim
+++ b/compiler/semdata.nim
@@ -118,7 +118,6 @@ proc newOptionEntry*(): POptionEntry
 proc newLib*(kind: TLibKind): PLib
 proc addToLib*(lib: PLib, sym: PSym)
 proc makePtrType*(c: PContext, baseType: PType): PType
-proc makeVarType*(c: PContext, baseType: PType): PType
 proc newTypeS*(kind: TTypeKind, c: PContext): PType
 proc fillTypeS*(dest: PType, kind: TTypeKind, c: PContext)
 
@@ -213,9 +212,12 @@ proc makePtrType(c: PContext, baseType: PType): PType =
   result = newTypeS(tyPtr, c)
   addSonSkipIntLit(result, baseType.assertNotNil)
 
-proc makeVarType(c: PContext, baseType: PType): PType =
-  result = newTypeS(tyVar, c)
-  addSonSkipIntLit(result, baseType.assertNotNil)
+proc makeVarType*(c: PContext, baseType: PType): PType =
+  if baseType.kind == tyVar:
+    result = baseType
+  else:
+    result = newTypeS(tyVar, c)
+    addSonSkipIntLit(result, baseType.assertNotNil)
 
 proc makeTypeDesc*(c: PContext, typ: PType): PType =
   result = newTypeS(tyTypeDesc, c)
@@ -247,6 +249,7 @@ proc makeAndType*(c: PContext, t1, t2: PType): PType =
   propagateToOwner(result, t1)
   propagateToOwner(result, t2)
   result.flags.incl((t1.flags + t2.flags) * {tfHasStatic})
+  result.flags.incl tfHasMeta
 
 proc makeOrType*(c: PContext, t1, t2: PType): PType =
   result = newTypeS(tyOr, c)
@@ -254,12 +257,14 @@ proc makeOrType*(c: PContext, t1, t2: PType): PType =
   propagateToOwner(result, t1)
   propagateToOwner(result, t2)
   result.flags.incl((t1.flags + t2.flags) * {tfHasStatic})
+  result.flags.incl tfHasMeta
 
 proc makeNotType*(c: PContext, t1: PType): PType =
   result = newTypeS(tyNot, c)
   result.sons = @[t1]
   propagateToOwner(result, t1)
   result.flags.incl(t1.flags * {tfHasStatic})
+  result.flags.incl tfHasMeta
 
 proc nMinusOne*(n: PNode): PNode =
   result = newNode(nkCall, n.info, @[
diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim
index c5bfbfa92..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)
@@ -389,7 +389,7 @@ proc isOpImpl(c: PContext, n: PNode): PNode =
     maybeLiftType(t2, c, n.info)
     var m: TCandidate
     initCandidate(c, m, t2)
-    let match = typeRel(m, t2, t1) != isNone
+    let match = typeRel(m, t2, t1) >= isSubtype # isNone
     result = newIntNode(nkIntLit, ord(match))
 
   result.typ = n.typ
@@ -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 52931bc2b..da24005c2 100644
--- a/compiler/semfold.nim
+++ b/compiler/semfold.nim
@@ -118,6 +118,9 @@ proc makeRange(typ: PType, first, last: BiggestInt): PType =
   let lowerNode = newIntNode(nkIntLit, minA)
   if typ.kind == tyInt and minA == maxA:
     result = getIntLitType(lowerNode)
+  elif typ.kind in {tyUint, tyUInt64}:
+    # these are not ordinal types, so you get no subrange type for these:
+    result = typ
   else:
     var n = newNode(nkRange)
     addSon(n, lowerNode)
@@ -135,8 +138,9 @@ proc makeRangeF(typ: PType, first, last: BiggestFloat): PType =
   addSonSkipIntLit(result, skipTypes(typ, {tyRange}))
 
 proc getIntervalType*(m: TMagic, n: PNode): PType =
-  # Nimrod requires interval arithmetic for ``range`` types. Lots of tedious
+  # Nim requires interval arithmetic for ``range`` types. Lots of tedious
   # work but the feature is very nice for reducing explicit conversions.
+  const ordIntLit = {nkIntLit..nkUInt64Lit}
   result = n.typ
 
   template commutativeOp(opr: expr) {.immediate.} =
@@ -208,15 +212,15 @@ proc getIntervalType*(m: TMagic, n: PNode): PType =
     var a = n.sons[1]
     var b = n.sons[2]
     # symmetrical:
-    if b.kind notin {nkIntLit..nkUInt32Lit}: swap(a, b)
-    if b.kind in {nkIntLit..nkUInt32Lit}:
+    if b.kind notin ordIntLit: swap(a, b)
+    if b.kind in ordIntLit:
       let x = b.intVal|+|1
       if (x and -x) == x and x >= 0:
         result = makeRange(a.typ, 0, b.intVal)
   of mModU:
     let a = n.sons[1]
     let b = n.sons[2]
-    if b.kind in {nkIntLit..nkUInt32Lit}:
+    if a.kind in ordIntLit:
       if b.intVal >= 0:
         result = makeRange(a.typ, 0, b.intVal-1)
       else:
@@ -232,9 +236,9 @@ proc getIntervalType*(m: TMagic, n: PNode): PType =
         result = makeRange(a.typ, b.intVal+1, -(b.intVal+1))
   of mDivI, mDivI64, mDivU:
     binaryOp(`|div|`)
-  of mMinI, mMinI64:
+  of mMinI:
     commutativeOp(min)
-  of mMaxI, mMaxI64:
+  of mMaxI:
     commutativeOp(max)
   else: discard
 
@@ -282,10 +286,14 @@ 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: 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: result = newIntNodeT(sonsLen(a), n) # BUGFIX
-  of mUnaryPlusI, mUnaryPlusI64, mUnaryPlusF64: result = a # throw `+` away
+  of mLengthSeq, mLengthOpenArray, mXLenSeq:
+    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)
   of mToInt, mToBiggestInt: result = newIntNodeT(system.toInt(getFloat(a)), n)
@@ -305,10 +313,10 @@ proc evalOp(m: TMagic, n, a, b, c: PNode): PNode =
   of mAddI, mAddI64: result = newIntNodeT(getInt(a) + getInt(b), n)
   of mSubI, mSubI64: result = newIntNodeT(getInt(a) - getInt(b), n)
   of mMulI, mMulI64: result = newIntNodeT(getInt(a) * getInt(b), n)
-  of mMinI, mMinI64:
+  of mMinI:
     if getInt(a) > getInt(b): result = newIntNodeT(getInt(b), n)
     else: result = newIntNodeT(getInt(a), n)
-  of mMaxI, mMaxI64:
+  of mMaxI:
     if getInt(a) > getInt(b): result = newIntNodeT(getInt(a), n)
     else: result = newIntNodeT(getInt(b), n)
   of mShlI, mShlI64:
@@ -426,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 & ')')
 
@@ -519,7 +528,7 @@ proc rangeCheck(n: PNode, value: BiggestInt) =
 proc foldConv*(n, a: PNode; check = false): PNode =
   # XXX range checks?
   case skipTypes(n.typ, abstractRange).kind
-  of tyInt..tyInt64:
+  of tyInt..tyInt64, tyUInt..tyUInt64:
     case skipTypes(a.typ, abstractRange).kind
     of tyFloat..tyFloat64:
       result = newIntNodeT(int(getFloat(a)), n)
@@ -646,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/semmagic.nim b/compiler/semmagic.nim
index de7700be6..0a7846f1d 100644
--- a/compiler/semmagic.nim
+++ b/compiler/semmagic.nim
@@ -54,7 +54,7 @@ proc evalTypeTrait(trait: PNode, operand: PType, context: PSym): PNode =
     result.typ = newType(tyString, context)
     result.info = trait.info
   of "arity":
-    result = newIntNode(nkIntLit, typ.n.len-1)
+    result = newIntNode(nkIntLit, typ.len - ord(typ.kind==tyProc))
     result.typ = newType(tyInt, context)
     result.info = trait.info
   else:
@@ -101,34 +101,6 @@ proc semBindSym(c: PContext, n: PNode): PNode =
   else:
     localError(n.sons[1].info, errUndeclaredIdentifier, sl.strVal)
 
-proc semLocals(c: PContext, n: PNode): PNode =
-  var counter = 0
-  var tupleType = newTypeS(tyTuple, c)
-  result = newNodeIT(nkPar, n.info, tupleType)
-  tupleType.n = newNodeI(nkRecList, n.info)
-  # for now we skip openarrays ...
-  for scope in walkScopes(c.currentScope):
-    if scope == c.topLevelScope: break
-    for it in items(scope.symbols):
-      # XXX parameters' owners are wrong for generics; this caused some pain
-      # for closures too; we should finally fix it.
-      #if it.owner != c.p.owner: return result
-      if it.kind in skLocalVars and
-          it.typ.skipTypes({tyGenericInst, tyVar}).kind notin
-            {tyVarargs, tyOpenArray, tyTypeDesc, tyStatic, tyExpr, tyStmt, tyEmpty}:
-
-        var field = newSym(skField, it.name, getCurrOwner(), n.info)
-        field.typ = it.typ.skipTypes({tyGenericInst, tyVar})
-        field.position = counter
-        inc(counter)
-
-        addSon(tupleType.n, newSymNode(field))
-        addSonSkipIntLit(tupleType, field.typ)
-
-        var a = newSymNode(it, result.info)
-        if it.typ.skipTypes({tyGenericInst}).kind == tyVar: a = newDeref(a)
-        result.add(a)
-
 proc semShallowCopy(c: PContext, n: PNode, flags: TExprFlags): PNode
 
 proc isStrangeArray(t: PType): bool =
@@ -161,7 +133,6 @@ proc magicsAfterOverloadResolution(c: PContext, n: PNode,
   of mHigh, mLow: result = semLowHigh(c, n, n[0].sym.magic)
   of mShallowCopy: result = semShallowCopy(c, n, flags)
   of mNBindSym: result = semBindSym(c, n)
-  of mLocals: result = semLocals(c, n)
   of mProcCall:
     result = n
     result.typ = n[1].typ
@@ -196,4 +167,11 @@ proc magicsAfterOverloadResolution(c: PContext, n: PNode,
         result.add newSymNode(createMagic("-", mSubI), n.info)
         result.add lenExprB
         result.add n.sons[1]
+  of mPlugin:
+    let plugin = getPlugin(n[0].sym)
+    if plugin.isNil:
+      localError(n.info, "cannot find plugin " & n[0].sym.name.s)
+      result = n
+    else:
+      result = plugin(c, n)
   else: result = n
diff --git a/compiler/sempass2.nim b/compiler/sempass2.nim
index 5a243afa0..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
@@ -714,8 +712,8 @@ proc track(tracked: PEffects, n: PNode) =
   of nkVarSection, nkLetSection:
     for child in n:
       let last = lastSon(child)
+      if last.kind != nkEmpty: track(tracked, last)
       if child.kind == nkIdentDefs and last.kind != nkEmpty:
-        track(tracked, last)
         for i in 0 .. child.len-3:
           initVar(tracked, child.sons[i], volatileCheck=false)
           addAsgnFact(tracked.guards, child.sons[i], last)
diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim
index a8463cbed..c355a5bf1 100644
--- a/compiler/semstmts.nim
+++ b/compiler/semstmts.nim
@@ -102,10 +102,6 @@ proc semDestructorCheck(c: PContext, n: PNode, flags: TExprFlags) {.inline.} =
         c.p.owner.kind notin {skTemplate, skMacro}:
       localError(n.info, errGenerated, "value expected, but got a type")
 
-proc newDeref(n: PNode): PNode {.inline.} =
-  result = newNodeIT(nkHiddenDeref, n.info, n.typ.sons[0])
-  addSon(result, n)
-
 proc semExprBranch(c: PContext, n: PNode): PNode =
   result = semExpr(c, n)
   if result.typ != nil:
@@ -373,6 +369,11 @@ proc addToVarSection(c: PContext; result: var PNode; orig, identDefs: PNode) =
   else:
     result.add identDefs
 
+proc isDiscardUnderscore(v: PSym): bool =
+  if v.name.s == "_":
+    v.flags.incl(sfGenSym)
+    result = true
+
 proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode =
   var b: PNode
   result = copyNode(n)
@@ -436,7 +437,8 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode =
 
     for j in countup(0, length-3):
       var v = semIdentDef(c, a.sons[j], symkind)
-      if sfGenSym notin v.flags: addInterfaceDecl(c, v)
+      if sfGenSym notin v.flags and not isDiscardUnderscore(v):
+        addInterfaceDecl(c, v)
       when oKeepVariableNames:
         if c.inUnrolledContext > 0: v.flags.incl(sfShadowed)
         else:
@@ -551,7 +553,8 @@ proc semForVars(c: PContext, n: PNode): PNode =
       if getCurrOwner().kind == skModule: incl(v.flags, sfGlobal)
       v.typ = iter.sons[i]
       n.sons[i] = newSymNode(v)
-      if sfGenSym notin v.flags: addForVarDecl(c, v)
+      if sfGenSym notin v.flags and not isDiscardUnderscore(v):
+        addForVarDecl(c, v)
   inc(c.p.nestedLoopCounter)
   n.sons[length-1] = semStmt(c, n.sons[length-1])
   dec(c.p.nestedLoopCounter)
diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim
index 4a45da2f9..8c7bd7243 100644
--- a/compiler/semtypes.nim
+++ b/compiler/semtypes.nim
@@ -261,7 +261,8 @@ proc semArray(c: PContext, n: PNode, prev: PType): PType =
       if not isOrdinalType(indx):
         localError(n.sons[1].info, errOrdinalTypeExpected)
       elif enumHasHoles(indx):
-        localError(n.sons[1].info, errEnumXHasHoles, indx.sym.name.s)
+        localError(n.sons[1].info, errEnumXHasHoles,
+                   typeToString(indx.skipTypes({tyRange})))
     base = semTypeNode(c, n.sons[2], nil)
     addSonSkipIntLit(result, base)
   else:
@@ -628,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,
@@ -834,7 +835,7 @@ proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode,
       cp.kind = tyUserTypeClassInst
       return addImplicitGeneric(cp)
 
-    for i in 1 .. (paramType.sons.len - 2):
+    for i in 1 .. paramType.len-2:
       var lifted = liftingWalk(paramType.sons[i])
       if lifted != nil:
         paramType.sons[i] = lifted
@@ -847,7 +848,7 @@ proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode,
       result.shouldHaveMeta
 
   of tyGenericInvocation:
-    for i in 1 .. <paramType.sonsLen:
+    for i in 1 .. <paramType.len:
       let lifted = liftingWalk(paramType.sons[i])
       if lifted != nil: paramType.sons[i] = lifted
     when false:
diff --git a/compiler/semtypinst.nim b/compiler/semtypinst.nim
index 914b92fc8..c5caf8b92 100644
--- a/compiler/semtypinst.nim
+++ b/compiler/semtypinst.nim
@@ -233,7 +233,9 @@ proc instCopyType*(cl: var TReplTypeVars, t: PType): PType =
   # XXX: relying on allowMetaTypes is a kludge
   result = copyType(t, t.owner, cl.allowMetaTypes)
   result.flags.incl tfFromGeneric
-  result.flags.excl tfInstClearedFlags
+  if not (t.kind in tyMetaTypes or
+         (t.kind == tyStatic and t.n == nil)):
+    result.flags.excl tfInstClearedFlags
 
 proc handleGenericInvocation(cl: var TReplTypeVars, t: PType): PType =
   # tyGenericInvocation[A, tyGenericInvocation[A, B]]
diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim
index faa84de15..7ea2c3d6f 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
@@ -1108,8 +1112,10 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
       localError(f.n.info, errTypeExpected)
       result = isNone
 
+  of tyNone:
+    if a.kind == tyNone: result = isEqual
   else:
-    internalAssert false
+    internalError " unknown type kind " & $f.kind
 
 proc cmpTypes*(c: PContext, f, a: PType): TTypeRelation =
   var m: TCandidate
@@ -1194,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)
@@ -1284,7 +1281,10 @@ proc paramTypesMatchAux(m: var TCandidate, f, argType: PType,
     result = implicitConv(nkHiddenStdConv, f, arg, m, c)
   of isSubtype:
     inc(m.subtypeMatches)
-    result = implicitConv(nkHiddenSubConv, f, arg, m, c)
+    if f.kind == tyTypeDesc:
+      result = arg
+    else:
+      result = implicitConv(nkHiddenSubConv, f, arg, m, c)
   of isSubrange:
     inc(m.subtypeMatches)
     if f.kind == tyVar:
@@ -1307,7 +1307,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)
@@ -1322,7 +1322,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}:
@@ -1468,9 +1468,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
 
@@ -1576,6 +1574,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/suggest.nim b/compiler/suggest.nim
index 6b168670c..659f1fa16 100644
--- a/compiler/suggest.nim
+++ b/compiler/suggest.nim
@@ -15,57 +15,79 @@ import algorithm, sequtils
 
 const
   sep = '\t'
-  sectionSuggest = "sug"
-  sectionDef = "def"
-  sectionContext = "con"
-  sectionUsage = "use"
+
+type
+  Suggest* = object
+    section*: IdeCmd
+    qualifiedPath*: seq[string]
+    filePath*: string
+    line*: int                   # Starts at 1
+    column*: int                 # Starts at 0
+    doc*: string           # Not escaped (yet)
+    symkind*: TSymKind
+    forth*: string               # XXX TODO object on symkind
+
+var
+  suggestionResultHook*: proc (result: Suggest) {.closure.}
 
 #template sectionSuggest(): expr = "##begin\n" & getStackTrace() & "##end\n"
 
 template origModuleName(m: PSym): string = m.name.s
 
-proc symToStr(s: PSym, isLocal: bool, section: string, li: TLineInfo): string = 
-  result = section
-  result.add(sep)
+proc symToSuggest(s: PSym, isLocal: bool, section: string, li: TLineInfo): Suggest = 
+  result.section = parseIdeCmd(section)
   if optIdeTerse in gGlobalOptions:
-    if s.kind in routineKinds:
-      result.add renderTree(s.ast, {renderNoBody, renderNoComments,
-                                    renderDocComments, renderNoPragmas})
-    else:
-      result.add s.name.s
-    result.add(sep)
-    result.add(toFullPath(li))
-    result.add(sep)
-    result.add($toLinenumber(li))
-    result.add(sep)
-    result.add($toColumn(li))
+    result.symkind = s.kind
+    result.filePath = toFullPath(li)
+    result.line = toLinenumber(li)
+    result.column = toColumn(li)
   else:
-    result.add($s.kind)
-    result.add(sep)
+    result.symkind = s.kind
+    result.qualifiedPath = @[]
     if not isLocal and s.kind != skModule:
       let ow = s.owner
       if ow.kind != skModule and ow.owner != nil:
         let ow2 = ow.owner
-        result.add(ow2.origModuleName)
-        result.add('.')
-      result.add(ow.origModuleName)
-      result.add('.')
-    result.add(s.name.s)
-    result.add(sep)
+        result.qualifiedPath.add(ow2.origModuleName)
+      result.qualifiedPath.add(ow.origModuleName)
+    result.qualifiedPath.add(s.name.s)
+
     if s.typ != nil: 
-      result.add(typeToString(s.typ))
-    result.add(sep)
-    result.add(toFullPath(li))
-    result.add(sep)
-    result.add($toLinenumber(li))
-    result.add(sep)
-    result.add($toColumn(li))
-    result.add(sep)
+      result.forth = typeToString(s.typ)
+    else:
+      result.forth = ""
+    result.filePath = toFullPath(li)
+    result.line = toLinenumber(li)
+    result.column = toColumn(li)
     when not defined(noDocgen):
-      result.add(s.extractDocComment.escape)
+      result.doc = s.extractDocComment
+
+proc `$`(suggest: Suggest): string = 
+  result = $suggest.section
+  result.add(sep)
+  result.add($suggest.symkind)
+  result.add(sep)
+  result.add(suggest.qualifiedPath.join("."))
+  result.add(sep)
+  result.add(suggest.forth)
+  result.add(sep)
+  result.add(suggest.filePath)
+  result.add(sep)
+  result.add($suggest.line)
+  result.add(sep)
+  result.add($suggest.column)
+  result.add(sep)
+  when not defined(noDocgen):
+    result.add(suggest.doc.escape)
 
-proc symToStr(s: PSym, isLocal: bool, section: string): string = 
-  result = symToStr(s, isLocal, section, s.info)
+proc symToSuggest(s: PSym, isLocal: bool, section: string): Suggest = 
+  result = symToSuggest(s, isLocal, section, s.info)
+
+proc suggestResult(s: Suggest) =
+  if not isNil(suggestionResultHook):
+    suggestionResultHook(s)
+  else:
+    suggestWriteln($(s))
 
 proc filterSym(s: PSym): bool {.inline.} =
   result = s.kind != skModule
@@ -84,7 +106,7 @@ proc fieldVisible*(c: PContext, f: PSym): bool {.inline.} =
 
 proc suggestField(c: PContext, s: PSym, outputs: var int) = 
   if filterSym(s) and fieldVisible(c, s):
-    suggestWriteln(symToStr(s, isLocal=true, sectionSuggest))
+    suggestResult(symToSuggest(s, isLocal=true, $ideSug))
     inc outputs
 
 template wholeSymTab(cond, section: expr) {.immediate.} =
@@ -97,7 +119,7 @@ template wholeSymTab(cond, section: expr) {.immediate.} =
     for item in entries:
       let it {.inject.} = item
       if cond:
-        suggestWriteln(symToStr(it, isLocal = isLocal, section))
+        suggestResult(symToSuggest(it, isLocal = isLocal, section))
         inc outputs
 
 proc suggestSymList(c: PContext, list: PNode, outputs: var int) = 
@@ -140,7 +162,7 @@ proc argsFit(c: PContext, candidate: PSym, n, nOrig: PNode): bool =
 
 proc suggestCall(c: PContext, n, nOrig: PNode, outputs: var int) = 
   wholeSymTab(filterSym(it) and nameFits(c, it, n) and argsFit(c, it, n, nOrig),
-              sectionContext)
+              $ideCon)
 
 proc typeFits(c: PContext, s: PSym, firstArg: PType): bool {.inline.} = 
   if s.typ != nil and sonsLen(s.typ) > 1 and s.typ.sons[1] != nil:
@@ -157,7 +179,7 @@ proc typeFits(c: PContext, s: PSym, firstArg: PType): bool {.inline.} =
 
 proc suggestOperations(c: PContext, n: PNode, typ: PType, outputs: var int) =
   assert typ != nil
-  wholeSymTab(filterSymNoOpr(it) and typeFits(c, it, typ), sectionSuggest)
+  wholeSymTab(filterSymNoOpr(it) and typeFits(c, it, typ), $ideSug)
 
 proc suggestEverything(c: PContext, n: PNode, outputs: var int) =
   # do not produce too many symbols:
@@ -166,7 +188,7 @@ proc suggestEverything(c: PContext, n: PNode, outputs: var int) =
     if scope == c.topLevelScope: isLocal = false
     for it in items(scope.symbols):
       if filterSym(it):
-        suggestWriteln(symToStr(it, isLocal = isLocal, sectionSuggest))
+        suggestResult(symToSuggest(it, isLocal = isLocal, $ideSug))
         inc outputs
     if scope == c.topLevelScope: break
 
@@ -181,12 +203,12 @@ proc suggestFieldAccess(c: PContext, n: PNode, outputs: var int) =
         # all symbols accessible, because we are in the current module:
         for it in items(c.topLevelScope.symbols):
           if filterSym(it): 
-            suggestWriteln(symToStr(it, isLocal=false, sectionSuggest))
+            suggestResult(symToSuggest(it, isLocal=false, $ideSug))
             inc outputs
       else: 
         for it in items(n.sym.tab): 
           if filterSym(it): 
-            suggestWriteln(symToStr(it, isLocal=false, sectionSuggest))
+            suggestResult(symToSuggest(it, isLocal=false, $ideSug))
             inc outputs
     else:
       # fallback:
@@ -263,16 +285,16 @@ var
 proc findUsages(info: TLineInfo; s: PSym) =
   if usageSym == nil and isTracked(info, s.name.s.len):
     usageSym = s
-    suggestWriteln(symToStr(s, isLocal=false, sectionUsage))
+    suggestResult(symToSuggest(s, isLocal=false, $ideUse))
   elif s == usageSym:
     if lastLineInfo != info:
-      suggestWriteln(symToStr(s, isLocal=false, sectionUsage, info))
+      suggestResult(symToSuggest(s, isLocal=false, $ideUse, info))
     lastLineInfo = info
 
 proc findDefinition(info: TLineInfo; s: PSym) =
   if s.isNil: return
   if isTracked(info, s.name.s.len):
-    suggestWriteln(symToStr(s, isLocal=false, sectionDef))
+    suggestResult(symToSuggest(s, isLocal=false, $ideDef))
     suggestQuit()
 
 proc ensureIdx[T](x: var T, y: int) =
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/trees.nim b/compiler/trees.nim
index 86a1139a0..2c631af99 100644
--- a/compiler/trees.nim
+++ b/compiler/trees.nim
@@ -9,40 +9,40 @@
 
 # tree helper routines
 
-import 
+import
   ast, astalgo, lexer, msgs, strutils, wordrecg
 
-proc hasSon(father, son: PNode): bool = 
-  for i in countup(0, sonsLen(father) - 1): 
-    if father.sons[i] == son: 
+proc hasSon(father, son: PNode): bool =
+  for i in countup(0, sonsLen(father) - 1):
+    if father.sons[i] == son:
       return true
   result = false
 
-proc cyclicTreeAux(n, s: PNode): bool = 
-  if n == nil: 
+proc cyclicTreeAux(n, s: PNode): bool =
+  if n == nil:
     return false
-  if hasSon(s, n): 
+  if hasSon(s, n):
     return true
   var m = sonsLen(s)
   addSon(s, n)
-  if not (n.kind in {nkEmpty..nkNilLit}): 
-    for i in countup(0, sonsLen(n) - 1): 
-      if cyclicTreeAux(n.sons[i], s): 
+  if not (n.kind in {nkEmpty..nkNilLit}):
+    for i in countup(0, sonsLen(n) - 1):
+      if cyclicTreeAux(n.sons[i], s):
         return true
   result = false
   delSon(s, m)
 
-proc cyclicTree*(n: PNode): bool = 
+proc cyclicTree*(n: PNode): bool =
   var s = newNodeI(nkEmpty, n.info)
   result = cyclicTreeAux(n, s)
 
-proc exprStructuralEquivalent*(a, b: PNode): bool = 
+proc exprStructuralEquivalent*(a, b: PNode): bool =
   result = false
-  if a == b: 
+  if a == b:
     result = true
-  elif (a != nil) and (b != nil) and (a.kind == b.kind): 
+  elif (a != nil) and (b != nil) and (a.kind == b.kind):
     case a.kind
-    of nkSym: 
+    of nkSym:
       # don't go nuts here: same symbol as string is enough:
       result = a.sym.name.id == b.sym.name.id
     of nkIdent: result = a.ident.id == b.ident.id
@@ -50,12 +50,12 @@ proc exprStructuralEquivalent*(a, b: PNode): bool =
     of nkFloatLit..nkFloat64Lit: result = a.floatVal == b.floatVal
     of nkStrLit..nkTripleStrLit: result = a.strVal == b.strVal
     of nkEmpty, nkNilLit, nkType: result = true
-    else: 
-      if sonsLen(a) == sonsLen(b): 
-        for i in countup(0, sonsLen(a) - 1): 
-          if not exprStructuralEquivalent(a.sons[i], b.sons[i]): return 
+    else:
+      if sonsLen(a) == sonsLen(b):
+        for i in countup(0, sonsLen(a) - 1):
+          if not exprStructuralEquivalent(a.sons[i], b.sons[i]): return
         result = true
-  
+
 proc sameTree*(a, b: PNode): bool =
   result = false
   if a == b:
@@ -66,7 +66,7 @@ proc sameTree*(a, b: PNode): bool =
     if a.info.col != b.info.col:
       return                  #if a.info.fileIndex <> b.info.fileIndex then exit;
     case a.kind
-    of nkSym: 
+    of nkSym:
       # don't go nuts here: same symbol as string is enough:
       result = a.sym.name.id == b.sym.name.id
     of nkIdent: result = a.ident.id == b.ident.id
@@ -75,15 +75,15 @@ proc sameTree*(a, b: PNode): bool =
     of nkStrLit..nkTripleStrLit: result = a.strVal == b.strVal
     of nkEmpty, nkNilLit, nkType: result = true
     else:
-      if sonsLen(a) == sonsLen(b): 
-        for i in countup(0, sonsLen(a) - 1): 
-          if not sameTree(a.sons[i], b.sons[i]): return 
+      if sonsLen(a) == sonsLen(b):
+        for i in countup(0, sonsLen(a) - 1):
+          if not sameTree(a.sons[i], b.sons[i]): return
         result = true
-  
-proc getProcSym*(call: PNode): PSym = 
+
+proc getProcSym*(call: PNode): PSym =
   result = call.sons[0].sym
 
-proc getOpSym*(op: PNode): PSym = 
+proc getOpSym*(op: PNode): PSym =
   if op.kind notin {nkCall, nkHiddenCallConv, nkCommand, nkCallStrLit}:
     result = nil
   else:
@@ -91,25 +91,25 @@ proc getOpSym*(op: PNode): PSym =
     elif op.sons[0].kind == nkSym: result = op.sons[0].sym
     else: result = nil
 
-proc getMagic*(op: PNode): TMagic = 
+proc getMagic*(op: PNode): TMagic =
   case op.kind
   of nkCallKinds:
     case op.sons[0].kind
     of nkSym: result = op.sons[0].sym.magic
     else: result = mNone
   else: result = mNone
-  
-proc treeToSym*(t: PNode): PSym = 
+
+proc treeToSym*(t: PNode): PSym =
   result = t.sym
 
-proc isConstExpr*(n: PNode): bool = 
+proc isConstExpr*(n: PNode): bool =
   result = (n.kind in
-      {nkCharLit..nkInt64Lit, nkStrLit..nkTripleStrLit, 
+      {nkCharLit..nkInt64Lit, nkStrLit..nkTripleStrLit,
        nkFloatLit..nkFloat64Lit, nkNilLit}) or (nfAllConst in n.flags)
 
 proc isDeepConstExpr*(n: PNode): bool =
   case n.kind
-  of nkCharLit..nkInt64Lit, nkStrLit..nkTripleStrLit, 
+  of nkCharLit..nkInt64Lit, nkStrLit..nkTripleStrLit,
       nkFloatLit..nkFloat64Lit, nkNilLit:
     result = true
   of nkExprEqExpr, nkExprColonExpr, nkHiddenStdConv, nkHiddenSubConv:
@@ -122,33 +122,33 @@ proc isDeepConstExpr*(n: PNode): bool =
     result = n.typ.isNil or n.typ.skipTypes({tyGenericInst, tyDistinct}).kind != tyObject
   else: discard
 
-proc flattenTreeAux(d, a: PNode, op: TMagic) = 
+proc flattenTreeAux(d, a: PNode, op: TMagic) =
   if (getMagic(a) == op):     # a is a "leaf", so add it:
     for i in countup(1, sonsLen(a) - 1): # BUGFIX
       flattenTreeAux(d, a.sons[i], op)
-  else: 
+  else:
     addSon(d, copyTree(a))
-  
-proc flattenTree*(root: PNode, op: TMagic): PNode = 
+
+proc flattenTree*(root: PNode, op: TMagic): PNode =
   result = copyNode(root)
   if getMagic(root) == op:
     # BUGFIX: forget to copy prc
     addSon(result, copyNode(root.sons[0]))
     flattenTreeAux(result, root, op)
 
-proc swapOperands*(op: PNode) = 
+proc swapOperands*(op: PNode) =
   var tmp = op.sons[1]
   op.sons[1] = op.sons[2]
   op.sons[2] = tmp
 
-proc isRange*(n: PNode): bool {.inline.} = 
-  if n.kind == nkInfix:
+proc isRange*(n: PNode): bool {.inline.} =
+  if n.kind in nkCallKinds:
     if n[0].kind == nkIdent and n[0].ident.id == ord(wDotDot) or
-        n[0].kind in {nkClosedSymChoice, nkOpenSymChoice} and 
+        n[0].kind in {nkClosedSymChoice, nkOpenSymChoice} and
         n[0][1].sym.name.id == ord(wDotDot):
       result = true
 
-proc whichPragma*(n: PNode): TSpecialWord = 
+proc whichPragma*(n: PNode): TSpecialWord =
   let key = if n.kind == nkExprColonExpr: n.sons[0] else: n
   if key.kind == nkIdent: result = whichKeyword(key.ident)
 
diff --git a/compiler/types.nim b/compiler/types.nim
index 153c26a42..e205f5722 100644
--- a/compiler/types.nim
+++ b/compiler/types.nim
@@ -541,6 +541,9 @@ proc typeToString(typ: PType, prefer: TPreferedDesc = preferName): string =
   of tyProc:
     result = if tfIterator in t.flags: "iterator (" else: "proc ("
     for i in countup(1, sonsLen(t) - 1):
+      if t.n != nil and i < t.n.len and t.n[i].kind == nkSym:
+        add(result, t.n[i].sym.name.s)
+        add(result, ": ")
       add(result, typeToString(t.sons[i]))
       if i < sonsLen(t) - 1: add(result, ", ")
     add(result, ')')
@@ -1436,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 3b5c8e7f3..e49bed522 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
@@ -1043,7 +1039,14 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
       decodeB(rkNode)
       let newLen = regs[rb].intVal.int
       if regs[ra].node.isNil: stackTrace(c, tos, pc, errNilAccess)
-      else: setLen(regs[ra].node.sons, newLen)
+      else:
+        let oldLen = regs[ra].node.len
+        setLen(regs[ra].node.sons, newLen)
+        if oldLen < newLen:
+          # XXX This is still not entirely correct
+          # set to default value:
+          for i in oldLen .. <newLen:
+            regs[ra].node.sons[i] = newNodeI(nkEmpty, c.debug[pc])
     of opcSwap:
       let rb = instr.regB
       if regs[ra].kind == regs[rb].kind:
@@ -1118,7 +1121,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
       decodeB(rkInt)
       let a = regs[rb].node
       case a.kind
-      of nkCharLit..nkInt64Lit: regs[ra].intVal = a.intVal
+      of nkCharLit..nkUInt64Lit: regs[ra].intVal = a.intVal
       else: stackTrace(c, tos, pc, errFieldXNotFound, "intVal")
     of opcNFloatVal:
       decodeB(rkFloat)
@@ -1273,7 +1276,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
     of opcNSetIntVal:
       decodeB(rkNode)
       var dest = regs[ra].node
-      if dest.kind in {nkCharLit..nkInt64Lit} and
+      if dest.kind in {nkCharLit..nkUInt64Lit} and
          regs[rb].kind in {rkInt}:
         dest.intVal = regs[rb].intVal
       else:
@@ -1362,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 90b9f2517..047009f01 100644
--- a/compiler/vmdef.nim
+++ b/compiler/vmdef.nim
@@ -16,7 +16,7 @@ const
   byteExcess* = 128 # we use excess-K for immediates
   wordExcess* = 32768
 
-  MaxLoopIterations* = 500_000 # max iterations of all loops
+  MaxLoopIterations* = 1500_000 # max iterations of all loops
 
 
 type
@@ -29,7 +29,7 @@ type
     opcRet,         # return
     opcYldYoid,     # yield with no value
     opcYldVal,      # yield with a value
-    
+
     opcAsgnInt,
     opcAsgnStr,
     opcAsgnFloat,
@@ -48,8 +48,8 @@ type
     opcWrDeref,
     opcWrStrIdx,
     opcLdStrIdx, # a = b[c]
-    
-    opcAddInt, 
+
+    opcAddInt,
     opcAddImmInt,
     opcSubInt,
     opcSubImmInt,
@@ -58,36 +58,37 @@ type
 
     opcIncl, opcInclRange, opcExcl, opcCard, opcMulInt, opcDivInt, opcModInt,
     opcAddFloat, opcSubFloat, opcMulFloat, opcDivFloat, opcShrInt, opcShlInt,
-    opcBitandInt, opcBitorInt, opcBitxorInt, opcAddu, opcSubu, opcMulu, 
-    opcDivu, opcModu, opcEqInt, opcLeInt, opcLtInt, opcEqFloat, 
-    opcLeFloat, opcLtFloat, opcLeu, opcLtu, opcEqRef, opcEqNimrodNode, opcXor, 
-    opcNot, opcUnaryMinusInt, opcUnaryMinusFloat, opcBitnotInt, 
+    opcBitandInt, opcBitorInt, opcBitxorInt, opcAddu, opcSubu, opcMulu,
+    opcDivu, opcModu, opcEqInt, opcLeInt, opcLtInt, opcEqFloat,
+    opcLeFloat, opcLtFloat, opcLeu, opcLtu, opcEqRef, opcEqNimrodNode, opcXor,
+    opcNot, opcUnaryMinusInt, opcUnaryMinusFloat, opcBitnotInt,
     opcEqStr, opcLeStr, opcLtStr, opcEqSet, opcLeSet, opcLtSet,
     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,
     opcAddStrStr,
     opcAddSeqElem,
     opcRangeChck,
-    
+
     opcNAdd,
     opcNAddMultiple,
-    opcNKind, 
-    opcNIntVal, 
-    opcNFloatVal, 
-    opcNSymbol, 
+    opcNKind,
+    opcNIntVal,
+    opcNFloatVal,
+    opcNSymbol,
     opcNIdent,
     opcNGetType,
     opcNStrVal,
-    
+
     opcNSetIntVal,
     opcNSetFloatVal, opcNSetSymbol, opcNSetIdent, opcNSetType, opcNSetStrVal,
     opcNNewNimNode, opcNCopyNimNode, opcNCopyNimTree, opcNDel, opcGenSym,
-    
+
     opcSlurp,
     opcGorge,
     opcParseExprToAst,
@@ -100,7 +101,7 @@ type
     opcEqIdent,
     opcStrToIdent,
     opcIdentToStr,
-    
+
     opcEcho,
     opcIndCall, # dest = call regStart, n; where regStart = fn, arg1, ...
     opcIndCallAsgn, # dest = call regStart, n; where regStart = fn, arg1, ...
@@ -110,7 +111,7 @@ type
     opcNSetChild,
     opcCallSite,
     opcNewStr,
-  
+
     opcTJmp,  # jump Bx if A != 0
     opcFJmp,  # jump Bx if A == 0
     opcJmp,   # jump Bx
@@ -132,7 +133,8 @@ type
     opcLdImmInt,  # dest = immediate value
     opcNBindSym,
     opcSetType,   # dest.typ = types[Bx]
-    opcTypeTrait
+    opcTypeTrait,
+    opcMarshalLoad, opcMarshalStore
 
   TBlock* = object
     label*: PSym
@@ -178,13 +180,13 @@ type
     slots*: pointer
     currentException*: PNode
   VmCallback* = proc (args: VmArgs) {.closure.}
-  
+
   PCtx* = ref TCtx
   TCtx* = object of passes.TPassContext # code gen context
     code*: seq[TInstr]
     debug*: seq[TLineInfo]  # line info for every instruction; kept separate
                             # to not slow down interpretation
-    globals*: PNode         # 
+    globals*: PNode         #
     constants*: PNode       # constant data
     types*: seq[PType]      # some instructions reference types (e.g. 'except')
     currentExceptionA*, currentExceptionB*: PNode
@@ -203,7 +205,7 @@ type
   TPosition* = distinct int
 
   PEvalContext* = PCtx
-  
+
 proc newCtx*(module: PSym): PCtx =
   PCtx(code: @[], debug: @[],
     globals: newNode(nkStmtListExpr), constants: newNode(nkStmtList), types: @[],
@@ -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/vmdeps.nim b/compiler/vmdeps.nim
index 6148ed319..21ee4967b 100644
--- a/compiler/vmdeps.nim
+++ b/compiler/vmdeps.nim
@@ -144,7 +144,9 @@ proc mapTypeToAst(t: PType, info: TLineInfo; allowRecursion=false): PNode =
   of tyIter: result = mapTypeToBracket("iter", t, info)
   of tyProxy: result = atomicType"error"
   of tyBuiltInTypeClass: result = mapTypeToBracket("builtinTypeClass", t, info)
-  of tyUserTypeClass: result = mapTypeToBracket("userTypeClass", t, info)
+  of tyUserTypeClass:
+    result = mapTypeToBracket("concept", t, info)
+    result.add t.n.copyTree
   of tyCompositeTypeClass: result = mapTypeToBracket("compositeTypeClass", t, info)
   of tyAnd: result = mapTypeToBracket("and", t, info)
   of tyOr: result = mapTypeToBracket("or", t, info)
diff --git a/compiler/vmgen.nim b/compiler/vmgen.nim
index c3013852d..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)
@@ -742,9 +746,9 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest) =
     c.gABC(n, opcNewStr, dest, tmp)
     c.freeTemp(tmp)
     # XXX buggy
-  of mLengthOpenArray, mLengthArray, mLengthSeq:
+  of mLengthOpenArray, mLengthArray, mLengthSeq, mXLenSeq:
     genUnaryABI(c, n, dest, opcLenSeq)
-  of mLengthStr:
+  of mLengthStr, mXLenStr:
     genUnaryABI(c, n, dest, opcLenStr)
   of mIncl, mExcl:
     unused(n, dest)
@@ -791,7 +795,7 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest) =
     genUnaryABC(c, n, dest, opcUnaryMinusInt)
     genNarrow(c, n, dest)
   of mUnaryMinusF64: genUnaryABC(c, n, dest, opcUnaryMinusFloat)
-  of mUnaryPlusI, mUnaryPlusI64, mUnaryPlusF64: gen(c, n.sons[1], dest)
+  of mUnaryPlusI, mUnaryPlusF64: gen(c, n.sons[1], dest)
   of mBitnotI, mBitnotI64:
     genUnaryABC(c, n, dest, opcBitnotInt)
     genNarrowU(c, n, dest)
@@ -1008,7 +1012,7 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest) =
     if dest < 0: dest = c.getTemp(n.typ)
     c.gABC(n, opcCallSite, dest)
   of mNGenSym: genBinaryABC(c, n, dest, opcGenSym)
-  of mMinI, mMaxI, mMinI64, mMaxI64, mAbsF64, mMinF64, mMaxF64, mAbsI,
+  of mMinI, mMaxI, mAbsF64, mMinF64, mMaxF64, mAbsI,
      mAbsI64, mDotDot:
     c.genCall(n, dest)
   of mExpandToAst:
@@ -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,
@@ -1364,7 +1384,7 @@ proc getNullValue(typ: PType, info: TLineInfo): PNode =
   of tyCString, tyString:
     result = newNodeIT(nkStrLit, info, t)
   of tyVar, tyPointer, tyPtr, tySequence, tyExpr,
-     tyStmt, tyTypeDesc, tyStatic, tyRef:
+     tyStmt, tyTypeDesc, tyStatic, tyRef, tyNil:
     result = newNodeIT(nkNilLit, info, t)
   of tyProc:
     if t.callConv != ccClosure:
@@ -1391,7 +1411,7 @@ proc getNullValue(typ: PType, info: TLineInfo): PNode =
       addSon(result, getNullValue(t.sons[i], info))
   of tySet:
     result = newNodeIT(nkCurly, info, t)
-  else: internalError("getNullValue: " & $t.kind)
+  else: internalError(info, "getNullValue: " & $t.kind)
 
 proc ldNullOpcode(t: PType): TOpcode =
   if fitsRegister(t): opcLdNullReg else: opcLdNull
@@ -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)
@@ -1610,7 +1648,8 @@ proc gen(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags = {}) =
     genBreak(c, n)
   of nkTryStmt: genTry(c, n, dest)
   of nkStmtList:
-    unused(n, dest)
+    #unused(n, dest)
+    # XXX Fix this bug properly, lexim triggers it
     for x in n: gen(c, x)
   of nkStmtListExpr:
     let L = n.len-1
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/compiler/vmops.nim b/compiler/vmops.nim
index 502ad8ecc..1023d4783 100644
--- a/compiler/vmops.nim
+++ b/compiler/vmops.nim
@@ -10,7 +10,7 @@
 # Unforunately this cannot be a module yet:
 #import vmdeps, vm
 from math import sqrt, ln, log10, log2, exp, round, arccos, arcsin,
-  arctan, arctan2, cos, cosh, hypot, sinh, sin, tan, tanh, pow, trunc, 
+  arctan, arctan2, cos, cosh, hypot, sinh, sin, tan, tanh, pow, trunc,
   floor, ceil, fmod
 
 from os import getEnv, existsEnv, dirExists, fileExists
diff --git a/config/nim.cfg b/config/nim.cfg
index ccb9977db..0c3ffef4e 100644
--- a/config/nim.cfg
+++ b/config/nim.cfg
@@ -78,6 +78,7 @@ path="$lib/pure/unidecode"
     gcc.options.linker = "-ldl"
     gcc.cpp.options.linker = "-ldl"
     clang.options.linker = "-ldl"
+    clang.cpp.options.linker = "-ldl"
     tcc.options.linker = "-ldl"
   @end
   @if bsd or haiku:
@@ -96,7 +97,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/csources b/csources
new file mode 160000
+Subproject 15724e2e1f3e7749d508dfcd995e84fea285080
diff --git a/doc/astspec.txt b/doc/astspec.txt
index 4c27272e2..68bb9f1cd 100644
--- a/doc/astspec.txt
+++ b/doc/astspec.txt
@@ -23,7 +23,7 @@ contains:
       case kind: NimNodeKind           ## the node's kind
       of nnkNone, nnkEmpty, nnkNilLit:
         discard                        ## node contains no additional fields
-      of nnkCharLit..nnkInt64Lit:
+      of nnkCharLit..nnkUInt64Lit:
         intVal: biggestInt             ## the int literal
       of nnkFloatLit..nnkFloat64Lit:
         floatVal: biggestFloat         ## the float literal
diff --git a/doc/grammar.txt b/doc/grammar.txt
index b53515495..72dc6c974 100644
--- a/doc/grammar.txt
+++ b/doc/grammar.txt
@@ -179,7 +179,7 @@ simpleStmt = ((returnStmt | raiseStmt | yieldStmt | discardStmt | breakStmt
            | continueStmt | pragmaStmt | importStmt | exportStmt | fromStmt
            | includeStmt | commentStmt) / exprStmt) COMMENT?
 complexOrSimpleStmt = (ifStmt | whenStmt | whileStmt
-                    | tryStmt | finallyStmt | exceptStmt | forStmt
+                    | tryStmt | forStmt
                     | blockStmt | staticStmt | deferStmt | asmStmt
                     | 'proc' routine
                     | 'method' routine
diff --git a/doc/lib.txt b/doc/lib.txt
index 385e7a91a..f43228151 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.
@@ -325,6 +325,10 @@ Parsers
 * `rstgen <rstgen.html>`_
   This module implements a generator of HTML/Latex from reStructuredText.
 
+* `sexp <sexp.html>`_
+  High performance sexp parser and generator, mainly for communication
+  with emacs.
+
 
 XML Processing
 --------------
@@ -346,7 +350,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 +385,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 +457,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 +513,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 +572,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/manual/lexing.txt b/doc/manual/lexing.txt
index e2f006f04..df6d85636 100644
--- a/doc/manual/lexing.txt
+++ b/doc/manual/lexing.txt
@@ -289,7 +289,7 @@ Numerical constants are of a single type and have the form::
   INT32_LIT = INT_LIT ['\''] ('i' | 'I') '32'
   INT64_LIT = INT_LIT ['\''] ('i' | 'I') '64'
 
-  UINT8_LIT = INT_LIT ['\''] ('u' | 'U')
+  UINT_LIT = INT_LIT ['\''] ('u' | 'U')
   UINT8_LIT = INT_LIT ['\''] ('u' | 'U') '8'
   UINT16_LIT = INT_LIT ['\''] ('u' | 'U') '16'
   UINT32_LIT = INT_LIT ['\''] ('u' | 'U') '32'
diff --git a/doc/manual/stmts.txt b/doc/manual/stmts.txt
index 5b1284872..5e47110e9 100644
--- a/doc/manual/stmts.txt
+++ b/doc/manual/stmts.txt
@@ -2,7 +2,7 @@ Statements and expressions
 ==========================
 
 Nim uses the common statement/expression paradigm: Statements do not
-produce a value in contrast to expressions. However, some expressions are 
+produce a value in contrast to expressions. However, some expressions are
 statements.
 
 Statements are separated into `simple statements`:idx: and
@@ -16,9 +16,9 @@ statements always have to be intended. The details can be found in the grammar.
 Statement list expression
 -------------------------
 
-Statements can also occur in an expression context that looks 
+Statements can also occur in an expression context that looks
 like ``(stmt1; stmt2; ...; ex)``. This is called
-an statement list expression or ``(;)``. The type 
+an statement list expression or ``(;)``. The type
 of ``(stmt1; stmt2; ...; ex)`` is the type of ``ex``. All the other statements
 must be of type ``void``. (One can use ``discard`` to produce a ``void`` type.)
 ``(;)`` does not introduce a new scope.
@@ -30,24 +30,24 @@ Discard statement
 Example:
 
 .. code-block:: nim
-  proc p(x, y: int): int = 
+  proc p(x, y: int): int =
     result = x + y
 
   discard p(3, 4) # discard the return value of `p`
 
 The ``discard`` statement evaluates its expression for side-effects and
-throws the expression's resulting value away. 
+throws the expression's resulting value away.
 
 Ignoring the return value of a procedure without using a discard statement is
 a static error.
 
 The return value can be ignored implicitly if the called proc/iterator has
-been declared with the `discardable`:idx: pragma: 
+been declared with the `discardable`:idx: pragma:
 
 .. code-block:: nim
-  proc p(x, y: int): int {.discardable.} = 
+  proc p(x, y: int): int {.discardable.} =
     result = x + y
-    
+
   p(3, 4) # now valid
 
 An empty ``discard`` statement is often used as a null statement:
@@ -98,11 +98,11 @@ T = enum                        cast[T](0); this may be an invalid value
 
 
 The implicit initialization can be avoided for optimization reasons with the
-`noinit`:idx: pragma: 
+`noinit`:idx: pragma:
 
 .. code-block:: nim
   var
-    a {.noInit.}: array [0..1023, char] 
+    a {.noInit.}: array [0..1023, char]
 
 If a proc is annotated with the ``noinit`` pragma this refers to its implicit
 ``result`` variable:
@@ -113,13 +113,13 @@ If a proc is annotated with the ``noinit`` pragma this refers to its implicit
 
 The implicit initialization can be also prevented by the `requiresInit`:idx:
 type pragma. The compiler requires an explicit initialization then. However
-it does a `control flow analysis`:idx: to prove the variable has been 
+it does a `control flow analysis`:idx: to prove the variable has been
 initialized and does not rely on syntactic properties:
 
 .. code-block:: nim
   type
     MyObject = object {.requiresInit.}
-    
+
   proc p() =
     # the following is valid:
     var x: MyObject
@@ -129,11 +129,12 @@ initialized and does not rely on syntactic properties:
       x = a()
     use x
 
+
 let statement
 -------------
 
 A ``let`` statement declares new local and global `single assignment`:idx:
-variables and binds a value to them. The syntax is the same as that of the ``var`` 
+variables and binds a value to them. The syntax is the same as that of the ``var``
 statement, except that the keyword ``var`` is replaced by the keyword ``let``.
 Let variables are not l-values and can thus not be passed to ``var`` parameters
 nor can their address be taken. They cannot be assigned new values.
@@ -141,6 +142,19 @@ nor can their address be taken. They cannot be assigned new values.
 For let variables the same pragmas are available as for ordinary variables.
 
 
+Tuple unpacking
+---------------
+
+In a ``var`` or ``let`` statement tuple unpacking can be performed. The special
+identifier ``_`` can be used to ignore some parts of the tuple:
+
+.. code-block:: nim
+    proc returnsTuple(): (int, int, int) = (4, 2, 3)
+
+    let (x, _, z) = returnsTuple()
+
+
+
 Const section
 -------------
 
@@ -157,33 +171,33 @@ have no side-effect can be used in constant expressions too:
     constEval = contains("abc", 'b') # computed at compile time!
 
 
-The rules for compile-time computability are: 
+The rules for compile-time computability are:
 
 1. Literals are compile-time computable.
 2. Type conversions are compile-time computable.
 3. Procedure calls of the form ``p(X)`` are compile-time computable if
-   ``p`` is a proc without side-effects (see the `noSideEffect pragma`_ 
-   for details) and if ``X`` is a (possibly empty) list of compile-time 
+   ``p`` is a proc without side-effects (see the `noSideEffect pragma`_
+   for details) and if ``X`` is a (possibly empty) list of compile-time
    computable arguments.
 
 
-Constants cannot be of type ``ptr``, ``ref``, ``var`` or ``object``, nor can 
+Constants cannot be of type ``ptr``, ``ref``, ``var`` or ``object``, nor can
 they contain such a type.
 
 
 Static statement/expression
 ---------------------------
 
-A static statement/expression can be used to enforce compile 
+A static statement/expression can be used to enforce compile
 time evaluation explicitly. Enforced compile time evaluation can even evaluate
-code that has side effects: 
+code that has side effects:
 
 .. code-block::
 
   static:
     echo "echo at compile time"
 
-It's a static error if the compiler cannot perform the evaluation at compile 
+It's a static error if the compiler cannot perform the evaluation at compile
 time.
 
 The current implementation poses some restrictions for compile time
@@ -217,7 +231,7 @@ the ``:`` are executed. This goes on until the last ``elif``. If all
 conditions fail, the ``else`` part is executed. If there is no ``else``
 part, execution continues with the statement after the ``if`` statement.
 
-The scoping for an ``if`` statement is slightly subtle to support an important 
+The scoping for an ``if`` statement is slightly subtle to support an important
 use case. A new scope starts for the ``if``/``elif`` condition and ends after
 the corresponding *then* block:
 
@@ -229,7 +243,7 @@ the corresponding *then* block:
   else:
     # 'm' not declared here
 
-In the example the scopes have been enclosed in ``{|  |}``. 
+In the example the scopes have been enclosed in ``{|  |}``.
 
 
 Case statement
@@ -244,7 +258,7 @@ Example:
     echo("permission denied")
   of "go-for-a-walk":     echo("please yourself")
   else:                   echo("unknown command")
-  
+
   # indentation of the branches is also allowed; and so is an optional colon
   # after the selecting expression:
   case readline(stdin):
@@ -252,15 +266,15 @@ Example:
       echo("permission denied")
     of "go-for-a-walk":     echo("please yourself")
     else:                   echo("unknown command")
-  
+
 
 The ``case`` statement is similar to the if statement, but it represents
 a multi-branch selection. The expression after the keyword ``case`` is
 evaluated and if its value is in a *slicelist* the corresponding statements
 (after the ``of`` keyword) are executed. If the value is not in any
 given *slicelist* the ``else`` part is executed. If there is no ``else``
-part and not all possible values that ``expr`` can hold occur in a 
-``slicelist``, a static error occurs. This holds only for expressions of 
+part and not all possible values that ``expr`` can hold occur in a
+``slicelist``, a static error occurs. This holds only for expressions of
 ordinal types. "All possible values" of ``expr`` are determined by ``expr``'s
 type. To suppress the static error an ``else`` part with an
 empty ``discard`` statement should be used.
@@ -281,7 +295,7 @@ expanded into a list of its elements:
     of SymChars, '_': echo "an identifier"
     of '0'..'9': echo "a number"
     else: echo "other"
-  
+
   # is equivalent to:
   proc classify(s: string) =
     case s[0]
@@ -580,14 +594,14 @@ A table constructor is syntactic sugar for an array constructor:
 
 .. code-block:: nim
   {"key1": "value1", "key2", "key3": "value2"}
-  
+
   # is the same as:
   [("key1", "value1"), ("key2", "value2"), ("key3", "value2")]
 
 
-The empty table can be written ``{:}`` (in contrast to the empty set 
+The empty table can be written ``{:}`` (in contrast to the empty set
 which is ``{}``) which is thus another way to write as the empty array
-constructor ``[]``. This slightly unusal way of supporting tables 
+constructor ``[]``. This slightly unusal way of supporting tables
 has lots of advantages:
 
 * The order of the (key,value)-pairs is preserved, thus it is easy to
diff --git a/doc/manual/syntax.txt b/doc/manual/syntax.txt
index cf44eb588..24644bce2 100644
--- a/doc/manual/syntax.txt
+++ b/doc/manual/syntax.txt
@@ -15,8 +15,6 @@ Associativity
 Binary operators whose first character is ``^`` are right-associative, all
 other binary operators are left-associative.
 
-Operators ending in ``>`` but longer than a single character are 
-called `arrow like`:idx:.
 
 
 Precedence
@@ -33,9 +31,12 @@ as ``(@x).abc`` whereas ``$x.abc`` is parsed as ``$(x.abc)``.
 For binary operators that are not keywords the precedence is determined by the
 following rules:
 
+Operators ending in either ``->``, ``~>`` or ``=>`` are called
+`arrow like`:idx:, and have the lowest precedence of all operators.
+
 If the operator ends with ``=`` and its first character is none of 
 ``<``, ``>``, ``!``, ``=``, ``~``, ``?``, it is an *assignment operator* which
-has the lowest precedence.
+has the second lowest precedence.
 
 Otherwise precedence is determined by the first character.
 
@@ -43,14 +44,14 @@ Otherwise precedence is determined by the first character.
 Precedence level    Operators                                      First character     Terminal symbol
 ================  ===============================================  ==================  ===============
  10 (highest)                                                      ``$  ^``            OP10
-  9               ``*    /    div   mod   shl  shr  %``            ``* % \  /``        OP9
-  8               ``+    -``                                       ``+  ~  |``         OP8
+  9               ``*    /    div   mod   shl  shr  %``            ``*  %  \  /``      OP9
+  8               ``+    -``                                       ``+  -  ~  |``      OP8
   7               ``&``                                            ``&``               OP7
   6               ``..``                                           ``.``               OP6
-  5               ``==  <= < >= > !=  in notin is isnot not of``   ``= <  > !``        OP5
+  5               ``==  <= < >= > !=  in notin is isnot not of``   ``=  <  >  !``      OP5
   4               ``and``                                                              OP4
   3               ``or xor``                                                           OP3
-  2                                                                ``@  : ?``          OP2
+  2                                                                ``@  :  ?``         OP2
   1               *assignment operator* (like ``+=``, ``*=``)                          OP1
   0 (lowest)      *arrow like operator* (like ``->``, ``=>``)                          OP0
 ================  ===============================================  ==================  ===============
@@ -67,7 +68,7 @@ is still parsed as ``1 + (3 * 4)``, but ``1+3 * 4`` is parsed as ``(1+3) * 4``:
 
 .. code-block:: nim
   #! strongSpaces
-  if foo+4 * 4 == 8 and b&c | 9  ++
+  if foo+4 * 4 == 8  and  b&c | 9  ++
       bar:
     echo ""
   # is parsed as
diff --git a/doc/manual/threads.txt b/doc/manual/threads.txt
index fc3040c87..f2b79a34f 100644
--- a/doc/manual/threads.txt
+++ b/doc/manual/threads.txt
@@ -37,7 +37,7 @@ that contains GC'ed memory (``string``, ``seq``, ``ref`` or a closure) either
 directly or indirectly through a call to a GC unsafe proc.
 
 The `gcsafe`:idx: annotation can be used to mark a proc to be gcsafe,
-otherwise this property is inferred by the compiler. Note that ``noSideEfect``
+otherwise this property is inferred by the compiler. Note that ``noSideEffect``
 implies ``gcsafe``. The only way to create a thread is via ``spawn`` or
 ``createThead``. ``spawn`` is usually the preferable method. Either way
 the invoked proc must not use ``var`` parameters nor must any of its parameters
@@ -146,7 +146,7 @@ wait on multiple flow variables at the same time:
 
   # wait until 2 out of 3 servers received the update:
   proc main =
-    var responses = newSeq[RawFlowVar](3)
+    var responses = newSeq[FlowVarBase](3)
     for i in 0..2:
       responses[i] = spawn tellServer(Update, "key", "value")
     var index = awaitAny(responses)
diff --git a/doc/manual/type_bound_ops.txt b/doc/manual/type_bound_ops.txt
index efa5578d4..c707979fe 100644
--- a/doc/manual/type_bound_ops.txt
+++ b/doc/manual/type_bound_ops.txt
@@ -127,8 +127,8 @@ The signature has to be:
 .. code-block:: nim
   proc `=deepCopy`(x: T): T
 
-This mechanism is used by most data structures that support shared memory like
-channels to implement thread safe automatic memory management.
+This mechanism will be used by most data structures that support shared memory
+like channels to implement thread safe automatic memory management.
 
 The builtin ``deepCopy`` can even clone closures and their environments. See
 the documentation of `spawn`_ for details.
diff --git a/doc/nimc.txt b/doc/nimc.txt
index 831fce567..fb1873539 100644
--- a/doc/nimc.txt
+++ b/doc/nimc.txt
@@ -386,6 +386,25 @@ Example:
 As can be seen from the example, to Nim symbols can be referred via backticks.
 Use two backticks to produce a single verbatim backtick.
 
+For a toplevel emit statement the section where in the generated C/C++ file
+the code should be emitted can be influenced via the
+prefixes ``/*TYPESECTION*/`` or ``/*VARSECTION*/``:
+
+.. code-block:: Nim
+  {.emit: """/*TYPESECTION*/
+  struct Vector3 {
+  public:
+    Vector3(): x(5) {}
+    Vector3(float x_): x(x_) {}
+    float x;
+  };
+  """.}
+
+  type Vector3 {.importcpp: "Vector3", nodecl} = object
+    x: cfloat
+
+  proc constructVector3(a: cfloat): Vector3 {.importcpp: "Vector3(@)", nodecl}
+
 
 ImportCpp pragma
 ----------------
@@ -506,7 +525,7 @@ For example:
 .. code-block:: nim
 
   type Input {.importcpp: "System::Input".} = object
-  proc getSubsystem*[T](): ptr T {.importcpp: "SystemManager::getSubsystem<'*0>()".}
+  proc getSubsystem*[T](): ptr T {.importcpp: "SystemManager::getSubsystem<'*0>()", nodecl.}
 
   let x: ptr Input = getSubsystem[Input]()
 
@@ -596,6 +615,25 @@ Produces:
   x[6] = 91.4;
 
 
+- If more precise control is needed, the apostrophe ``'`` can be used in the
+  supplied pattern to denote the concrete type parameters of the generic type.
+  See the usage of the apostrophe operator in proc patterns for more details.
+
+.. code-block:: nim
+
+  type
+    VectorIterator {.importcpp: "std::vector<'0>::iterator".} [T] = object
+
+  var x: VectorIterator[cint]
+
+
+Produces:
+
+.. code-block:: C
+
+  std::vector<int>::iterator x;
+
+
 ImportObjC pragma
 -----------------
 Similar to the `importc pragma for C <manual.html#importc-pragma>`_, the
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/spawn.txt b/doc/spawn.txt
index fb2f851c7..36bd02e96 100644
--- a/doc/spawn.txt
+++ b/doc/spawn.txt
@@ -33,7 +33,7 @@ variables at the same time:
   
   # wait until 2 out of 3 servers received the update:
   proc main =
-    var responses = newSeq[RawFlowVar](3)
+    var responses = newSeq[FlowVarBase](3)
     for i in 0..2:
       responses[i] = spawn tellServer(Update, "key", "value")
     var index = awaitAny(responses)
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..1fa495054 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
 
@@ -1303,7 +1303,7 @@ type conversions in this context:
 
   myWriteln(stdout, 123, "abc", 4.0)
   # is transformed by the compiler to:
-  myWriteln(stdout, [$123, $"def", $4.0])
+  myWriteln(stdout, [$123, $"abc", $4.0])
 
 In this example `$ <system.html#$>`_ is applied to any argument that is passed
 to the parameter ``a``. Note that `$ <system.html#$>`_ applied to strings is a
@@ -1325,7 +1325,7 @@ define operators which accept Slice objects to define ranges.
     b = "Slices are useless."
 
   echo a[7..12] # --> 'a prog'
-  b[11.. -2] = "useful"
+  b[11.. ^2] = "useful"
   echo b # --> 'Slices are useful.'
 
 In the previous example slices are used to modify a part of a string, and even
@@ -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 508d7e007..55019b544 100644
--- a/koch.nim
+++ b/koch.nim
@@ -81,7 +81,7 @@ proc exec(cmd: string, errorcode: int = QuitFailure) =
   echo(cmd)
   if execShellCmd(cmd) != 0: quit("FAILURE", errorcode)
 
-proc tryExec(cmd: string): bool = 
+proc tryExec(cmd: string): bool =
   echo(cmd)
   result = execShellCmd(cmd) == 0
 
@@ -96,7 +96,7 @@ proc copyExe(source, dest: string) =
 const
   compileNimInst = "-d:useLibzipSrc tools/niminst/niminst"
 
-proc csource(args: string) = 
+proc csource(args: string) =
   exec("$4 cc $1 -r $3 --var:version=$2 --var:mingw=none csource --main:compiler/nim.nim compiler/installer.ini $1" %
        [args, VersionAsString, compileNimInst, findNim()])
 
@@ -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,14 +119,14 @@ 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)
-  # produce 'nimrod_debug.exe':
-  exec "nim c compiler" / "nim.nim"
-  copyExe("compiler/nim".exe, "bin/nim_debug".exe)
+  #buildTool("tools/nimgrep", args)
+  # produce '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) = 
+proc install(args: string) =
   exec("$# cc -r $# --var:version=$# --var:mingw=none --main:compiler/nim.nim scripts compiler/installer.ini" %
        [findNim(), compileNimInst, VersionAsString])
   exec("sh ./install.sh $#" % args)
@@ -139,12 +145,10 @@ proc pdf(args="") =
 
 # -------------- boot ---------------------------------------------------------
 
-proc findStartNim: string = 
+proc findStartNim: string =
   # we try several things before giving up:
   # * bin/nim
   # * $PATH/nim
-  # * bin/nimrod
-  # * $PATH/nimrod
   # If these fail, we try to build nim with the "build.(sh|bat)" script.
   var nim = "nim".exe
   result = "bin" / nim
@@ -152,34 +156,27 @@ proc findStartNim: string =
   for dir in split(getEnv("PATH"), PathSep):
     if existsFile(dir / nim): return dir / nim
 
-  # try the old "nimrod.exe":
-  var nimrod = "nimrod".exe
-  result = "bin" / nimrod
-  if existsFile(result): return
-  for dir in split(getEnv("PATH"), PathSep):
-    if existsFile(dir / nim): return dir / nimrod
-
   when defined(Posix):
     const buildScript = "build.sh"
-    if existsFile(buildScript): 
+    if existsFile(buildScript):
       if tryExec("./" & buildScript): return "bin" / nim
   else:
     const buildScript = "build.bat"
-    if existsFile(buildScript): 
+    if existsFile(buildScript):
       if tryExec(buildScript): return "bin" / nim
 
   echo("Found no nim compiler and every attempt to build one failed!")
   quit("FAILURE")
 
-proc thVersion(i: int): string = 
+proc thVersion(i: int): string =
   result = ("compiler" / "nim" & $i).exe
-  
+
 proc boot(args: string) =
   var output = "compiler" / "nim".exe
   var finalDest = "bin" / "nim".exe
   # default to use the 'c' command:
   let bootOptions = if args.len == 0 or args.startsWith("-"): "c" else: ""
-  
+
   copyExe(findStartNim(), 0.thVersion)
   for i in 0..2:
     echo "iteration: ", i+1
@@ -204,7 +201,7 @@ const
     ".bzrignore", "nim", "nim.exe", "koch", "koch.exe", ".gitignore"
   ]
 
-proc cleanAux(dir: string) = 
+proc cleanAux(dir: string) =
   for kind, path in walkDir(dir):
     case kind
     of pcFile:
@@ -215,25 +212,25 @@ proc cleanAux(dir: string) =
           removeFile(path)
     of pcDir:
       case splitPath(path).tail
-      of "nimcache": 
+      of "nimcache":
         echo "removing dir: ", path
         removeDir(path)
       of "dist", ".git", "icons": discard
       else: cleanAux(path)
     else: discard
 
-proc removePattern(pattern: string) = 
-  for f in walkFiles(pattern): 
+proc removePattern(pattern: string) =
+  for f in walkFiles(pattern):
     echo "removing: ", f
     removeFile(f)
 
-proc clean(args: string) = 
+proc clean(args: string) =
   if existsFile("koch.dat"): removeFile("koch.dat")
   removePattern("web/*.html")
   removePattern("doc/*.html")
   cleanAux(getCurrentDir())
   for kind, path in walkDir(getCurrentDir() / "build"):
-    if kind == pcDir: 
+    if kind == pcDir:
       echo "removing dir: ", path
       removeDir(path)
 
@@ -276,7 +273,7 @@ when defined(withUpdate):
                    "Local branch must be ahead of it. Exiting...")
       else:
         quit("An error has occurred.")
-      
+
     else:
       echo("No repo or executable found!")
       when defined(haveZipLib):
@@ -293,7 +290,7 @@ when defined(withUpdate):
           quit("Error reading archive.")
       else:
         quit("No failback available. Exiting...")
-    
+
     echo("Starting update...")
     boot(args)
     echo("Update complete!")
@@ -317,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 --------------------------------------------------------
@@ -346,8 +345,8 @@ proc temp(args: string) =
   copyExe(output, finalDest)
   if args.len > 0: exec(finalDest & " " & args)
 
-proc showHelp() = 
-  quit(HelpText % [VersionAsString & spaces(44-len(VersionAsString)), 
+proc showHelp() =
+  quit(HelpText % [VersionAsString & spaces(44-len(VersionAsString)),
                    CompileDate, CompileTime], QuitSuccess)
 
 var op = initOptParser()
@@ -366,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/core/macros.nim b/lib/core/macros.nim
index 5583748e0..7e6e4ccc9 100644
--- a/lib/core/macros.nim
+++ b/lib/core/macros.nim
@@ -88,7 +88,9 @@ type
     ntyBigNum,
     ntyConst, ntyMutable, ntyVarargs,
     ntyIter,
-    ntyError
+    ntyError,
+    ntyBuiltinTypeClass, ntyConcept, ntyConceptInst, ntyComposite,
+    ntyAnd, ntyOr, ntyNot
 
   TNimTypeKinds* {.deprecated.} = set[NimTypeKind]
   NimSymKind* = enum
@@ -162,6 +164,7 @@ proc kind*(n: NimNode): NimNodeKind {.magic: "NKind", noSideEffect.}
   ## returns the `kind` of the node `n`.
 
 proc intVal*(n: NimNode): BiggestInt {.magic: "NIntVal", noSideEffect.}
+proc boolVal*(n: NimNode): bool {.compileTime, noSideEffect.} = n.intVal != 0
 proc floatVal*(n: NimNode): BiggestFloat {.magic: "NFloatVal", noSideEffect.}
 proc symbol*(n: NimNode): NimSym {.magic: "NSymbol", noSideEffect.}
 proc ident*(n: NimNode): NimIdent {.magic: "NIdent", noSideEffect.}
@@ -174,6 +177,12 @@ proc getType*(n: NimNode): NimNode {.magic: "NGetType", noSideEffect.}
   ## resolve recursive types, you have to call 'getType' again. To see what
   ## kind of type it is, call `typeKind` on getType's result.
 
+proc getType*(n: typedesc): NimNode {.magic: "NGetType", noSideEffect.}
+  ## Returns the Nim type node for given type. This can be used to turn macro
+  ## typedesc parameter into proper NimNode representing type, since typedesc
+  ## are an exception in macro calls - they are not mapped implicitly to
+  ## NimNode like any other arguments.
+
 proc typeKind*(n: NimNode): NimTypeKind {.magic: "NGetType", noSideEffect.}
   ## Returns the type kind of the node 'n' that should represent a type, that
   ## means the node should have been obtained via `getType`.
@@ -355,6 +364,12 @@ proc expectLen*(n: NimNode, len: int) {.compileTime.} =
   ## macros that check its number of arguments.
   if n.len != len: error("macro expects a node with " & $len & " children")
 
+proc newTree*(kind: NimNodeKind,
+              children: varargs[NimNode]): NimNode {.compileTime.} =
+  ## produces a new node with children.
+  result = newNimNode(kind)
+  result.add(children)
+
 proc newCall*(theProc: NimNode,
               args: varargs[NimNode]): NimNode {.compileTime.} =
   ## produces a new call node. `theProc` is the proc that is called with
@@ -389,6 +404,11 @@ proc newLit*(i: BiggestInt): NimNode {.compileTime.} =
   result = newNimNode(nnkIntLit)
   result.intVal = i
 
+proc newLit*(b: bool): NimNode {.compileTime.} =
+  ## produces a new boolean literal node.
+  result = newNimNode(nnkIntLit)
+  result.intVal = ord(b)
+
 proc newLit*(f: BiggestFloat): NimNode {.compileTime.} =
   ## produces a new float literal node.
   result = newNimNode(nnkFloatLit)
diff --git a/lib/impure/db_sqlite.nim b/lib/impure/db_sqlite.nim
index 4be692f39..8536ab6f2 100644
--- a/lib/impure/db_sqlite.nim
+++ b/lib/impure/db_sqlite.nim
@@ -205,7 +205,7 @@ proc setEncoding*(connection: TDbConn, encoding: string): bool {.
   exec(connection, sql"PRAGMA encoding = ?", [encoding])
   result = connection.getValue(sql"PRAGMA encoding") == encoding
 
-when isMainModule:
+when not defined(testing) and isMainModule:
   var db = open("db.sql", "", "", "")
   exec(db, sql"create table tbl1(one varchar(10), two smallint)", [])
   exec(db, sql"insert into tbl1 values('hello!',10)", [])
diff --git a/lib/impure/graphics.nim b/lib/impure/graphics.nim
index dfadb46ee..814c0ebe1 100644
--- a/lib/impure/graphics.nim
+++ b/lib/impure/graphics.nim
@@ -499,7 +499,7 @@ template withEvents*(surf: PSurface, event: expr, actions: stmt): stmt {.
 if sdl.init(sdl.INIT_VIDEO) < 0: raiseEGraphics()
 if sdl_ttf.init() < 0: raiseEGraphics()
 
-when isMainModule:
+when not defined(testing) and isMainModule:
   var surf = newScreenSurface(800, 600)
 
   surf.fillSurface(colWhite)
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 91381bda3..279f8aadd 100644
--- a/lib/impure/re.nim
+++ b/lib/impure/re.nim
@@ -7,8 +7,11 @@
 #    distribution, for details about the copyright.
 #
 
-## Regular expression support for Nim. Consider using the pegs module
-## instead.
+## Regular expression support for Nim. Consider using the pegs module instead.
+##
+## There is an alternative regular expressions library with a more unified API:
+## `nre <https://github.com/flaviut/nre>`_. It may be added to the standard
+## library in the future, instead of `re`.
 ##
 ## **Note:** The 're' proc defaults to the **extended regular expression
 ## syntax** which lets you use whitespace freely to make your regexes readable.
@@ -41,11 +44,11 @@ type
     reExtended = 3,      ## ignore whitespace and ``#`` comments
     reStudy = 4          ## study the expression (may be omitted if the
                          ## expression will be used only once)
-
-  RegexDesc = object
-    h: PPcre
-    e: ptr TExtra
-
+  
+  RegexDesc = object 
+    h: ptr Pcre
+    e: ptr ExtraData
+  
   Regex* = ref RegexDesc ## a compiled regular expression
 
   RegexError* = object of ValueError
@@ -60,7 +63,7 @@ proc raiseInvalidRegex(msg: string) {.noinline, noreturn.} =
   e.msg = msg
   raise e
 
-proc rawCompile(pattern: string, flags: cint): PPcre =
+proc rawCompile(pattern: string, flags: cint): ptr Pcre =
   var
     msg: cstring
     offset: cint
@@ -84,7 +87,7 @@ proc re*(s: string, flags = {reExtended, reStudy}): Regex =
   result.h = rawCompile(s, cast[cint](flags - {reStudy}))
   if reStudy in flags:
     var msg: cstring
-    result.e = pcre.study(result.h, 0, msg)
+    result.e = pcre.study(result.h, 0, addr msg)
     if not isNil(msg): raiseInvalidRegex($msg)
 
 proc matchOrFind(s: string, pattern: Regex, matches: var openArray[string],
@@ -143,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
@@ -413,22 +416,28 @@ proc escapeRe*(s: string): string =
       result.add(toHex(ord(c), 2))
 
 const ## common regular expressions
-  reIdentifier* = r"\b[a-zA-Z_]+[a-zA-Z_0-9]*\b"  ## describes an identifier
-  reNatural* = r"\b\d+\b" ## describes a natural number
-  reInteger* = r"\b[-+]?\d+\b" ## describes an integer
-  reHex* = r"\b0[xX][0-9a-fA-F]+\b" ## describes a hexadecimal number
-  reBinary* = r"\b0[bB][01]+\b" ## describes a binary number (example: 0b11101)
-  reOctal* = r"\b0[oO][0-7]+\b" ## describes an octal number (example: 0o777)
-  reFloat* = r"\b[-+]?[0-9]*\.?[0-9]+([eE][-+]?[0-9]+)?\b"
+  reIdentifier* {.deprecated.} = r"\b[a-zA-Z_]+[a-zA-Z_0-9]*\b"
+    ## describes an identifier
+  reNatural* {.deprecated.} = r"\b\d+\b"
+    ## describes a natural number
+  reInteger* {.deprecated.} = r"\b[-+]?\d+\b"
+    ## describes an integer
+  reHex* {.deprecated.} = r"\b0[xX][0-9a-fA-F]+\b"
+    ## describes a hexadecimal number
+  reBinary* {.deprecated.} = r"\b0[bB][01]+\b"
+    ## describes a binary number (example: 0b11101)
+  reOctal* {.deprecated.} = r"\b0[oO][0-7]+\b"
+    ## describes an octal number (example: 0o777)
+  reFloat* {.deprecated.} = r"\b[-+]?[0-9]*\.?[0-9]+([eE][-+]?[0-9]+)?\b"
     ## describes a floating point number
-  reEmail* = r"\b[a-zA-Z0-9!#$%&'*+/=?^_`{|}~\-]+(?:\. &" &
-             r"[a-zA-Z0-9!#$%&'*+/=?^_`{|}~-]+)" &
-             r"*@(?:[a-zA-Z0-9](?:[a-zA-Z0-9-]*[a-zA-Z0-9])?\.)+" &
-             r"(?:[a-zA-Z]{2}|com|org|" &
-             r"net|gov|mil|biz|info|mobi|name|aero|jobs|museum)\b"
+  reEmail* {.deprecated.} = r"\b[a-zA-Z0-9!#$%&'*+/=?^_`{|}~\-]+(?:\. &" &
+                            r"[a-zA-Z0-9!#$%&'*+/=?^_`{|}~-]+)*@" &
+                            r"(?:[a-zA-Z0-9](?:[a-zA-Z0-9-]*[a-zA-Z0-9])?\.)+" &
+                            r"(?:[a-zA-Z]{2}|com|org|net|gov|mil|biz|" &
+                            r"info|mobi|name|aero|jobs|museum)\b"
     ## describes a common email address
-  reURL* = r"\b(http(s)?|ftp|gopher|telnet|file|notes|ms\-help):" &
-           r"((//)|(\\\\))+[\w\d:#@%/;$()~_?\+\-\=\\\.\&]*\b"
+  reURL* {.deprecated.} = r"\b(http(s)?|ftp|gopher|telnet|file|notes|ms-help)" &
+                          r":((//)|(\\\\))+[\w\d:#@%/;$()~_?\+\-\=\\\.\&]*\b"
     ## describes an URL
 
 when isMainModule:
diff --git a/lib/impure/ssl.nim b/lib/impure/ssl.nim
index bb7cfc0d3..d318a1979 100644
--- a/lib/impure/ssl.nim
+++ b/lib/impure/ssl.nim
@@ -82,7 +82,7 @@ proc close*(sock: TSecureSocket) =
     ERR_print_errors_fp(stderr)
     raiseOSError(osLastError())
 
-when isMainModule:
+when not defined(testing) and isMainModule:
   var s: TSecureSocket
   echo connect(s, "smtp.gmail.com", 465)
   
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/packages/docutils/rst.nim b/lib/packages/docutils/rst.nim
index a4d095e68..2ee94ba13 100644
--- a/lib/packages/docutils/rst.nim
+++ b/lib/packages/docutils/rst.nim
@@ -564,7 +564,7 @@ proc fixupEmbeddedRef(n, a, b: PRstNode) =
 
 proc parsePostfix(p: var TRstParser, n: PRstNode): PRstNode =
   result = n
-  if isInlineMarkupEnd(p, "_"):
+  if isInlineMarkupEnd(p, "_") or isInlineMarkupEnd(p, "__"):
     inc(p.idx)
     if p.tok[p.idx-2].symbol == "`" and p.tok[p.idx-3].symbol == ">":
       var a = newRstNode(rnInner)
diff --git a/lib/packages/docutils/rstgen.nim b/lib/packages/docutils/rstgen.nim
index da05be9bf..9e96d8a63 100644
--- a/lib/packages/docutils/rstgen.nim
+++ b/lib/packages/docutils/rstgen.nim
@@ -34,14 +34,14 @@ type
   TOutputTarget* = enum ## which document type to generate
     outHtml,            # output is HTML
     outLatex            # output is Latex
-  
-  TTocEntry = object 
+
+  TTocEntry = object
     n*: PRstNode
     refname*, header*: string
 
-  TMetaEnum* = enum 
+  TMetaEnum* = enum
     metaNone, metaTitle, metaSubtitle, metaAuthor, metaVersion
-    
+
   TRstGenerator* = object of RootObj
     target*: TOutputTarget
     config*: StringTableRef
@@ -60,7 +60,7 @@ type
     seenIndexTerms: Table[string, int] ## \
     ## Keeps count of same text index terms to generate different identifiers
     ## for hyperlinks. See renderIndexTerm proc for details.
-  
+
   PDoc = var TRstGenerator ## Alias to type less.
 
   CodeBlockParams = object ## Stores code block params.
@@ -136,7 +136,7 @@ proc initRstGenerator*(g: var TRstGenerator, target: TOutputTarget,
     g.currentSection = "Module " & fileParts.name
   g.seenIndexTerms = initTable[string, int]()
   g.msgHandler = msgHandler
-  
+
   let s = config["split.item.toc"]
   if s != "": g.splitAfter = parseInt(s)
   for i in low(g.meta)..high(g.meta): g.meta[i] = ""
@@ -147,23 +147,23 @@ proc writeIndexFile*(g: var TRstGenerator, outfile: string) =
   ## You previously need to add entries to the index with the `setIndexTerm()
   ## <#setIndexTerm>`_ proc. If the index is empty the file won't be created.
   if g.theIndex.len > 0: writeFile(outfile, g.theIndex)
-  
-proc addXmlChar(dest: var string, c: char) = 
+
+proc addXmlChar(dest: var string, c: char) =
   case c
   of '&': add(dest, "&amp;")
   of '<': add(dest, "&lt;")
   of '>': add(dest, "&gt;")
   of '\"': add(dest, "&quot;")
   else: add(dest, c)
-  
-proc addRtfChar(dest: var string, c: char) = 
+
+proc addRtfChar(dest: var string, c: char) =
   case c
   of '{': add(dest, "\\{")
   of '}': add(dest, "\\}")
   of '\\': add(dest, "\\\\")
   else: add(dest, c)
-  
-proc addTexChar(dest: var string, c: char) = 
+
+proc addTexChar(dest: var string, c: char) =
   case c
   of '_': add(dest, "\\_")
   of '{': add(dest, "\\symbol{123}")
@@ -183,54 +183,54 @@ proc addTexChar(dest: var string, c: char) =
 
 var splitter*: string = "<wbr />"
 
-proc escChar*(target: TOutputTarget, dest: var string, c: char) {.inline.} = 
+proc escChar*(target: TOutputTarget, dest: var string, c: char) {.inline.} =
   case target
   of outHtml:  addXmlChar(dest, c)
   of outLatex: addTexChar(dest, c)
-  
-proc nextSplitPoint*(s: string, start: int): int = 
+
+proc nextSplitPoint*(s: string, start: int): int =
   result = start
-  while result < len(s) + 0: 
+  while result < len(s) + 0:
     case s[result]
-    of '_': return 
-    of 'a'..'z': 
-      if result + 1 < len(s) + 0: 
-        if s[result + 1] in {'A'..'Z'}: return 
+    of '_': return
+    of 'a'..'z':
+      if result + 1 < len(s) + 0:
+        if s[result + 1] in {'A'..'Z'}: return
     else: discard
     inc(result)
   dec(result)                 # last valid index
-  
-proc esc*(target: TOutputTarget, s: string, splitAfter = -1): string = 
+
+proc esc*(target: TOutputTarget, s: string, splitAfter = -1): string =
   result = ""
-  if splitAfter >= 0: 
+  if splitAfter >= 0:
     var partLen = 0
     var j = 0
-    while j < len(s): 
+    while j < len(s):
       var k = nextSplitPoint(s, j)
-      if (splitter != " ") or (partLen + k - j + 1 > splitAfter): 
+      if (splitter != " ") or (partLen + k - j + 1 > splitAfter):
         partLen = 0
         add(result, splitter)
       for i in countup(j, k): escChar(target, result, s[i])
       inc(partLen, k - j + 1)
       j = k + 1
-  else: 
+  else:
     for i in countup(0, len(s) - 1): escChar(target, result, s[i])
 
 
 proc disp(target: TOutputTarget, xml, tex: string): string =
-  if target != outLatex: result = xml 
+  if target != outLatex: result = xml
   else: result = tex
-  
-proc dispF(target: TOutputTarget, xml, tex: string, 
-           args: varargs[string]): string = 
-  if target != outLatex: result = xml % args 
+
+proc dispF(target: TOutputTarget, xml, tex: string,
+           args: varargs[string]): string =
+  if target != outLatex: result = xml % args
   else: result = tex % args
-  
-proc dispA(target: TOutputTarget, dest: var string, 
+
+proc dispA(target: TOutputTarget, dest: var string,
            xml, tex: string, args: varargs[string]) =
   if target != outLatex: addf(dest, xml, args)
   else: addf(dest, tex, args)
-  
+
 proc `or`(x, y: string): string {.inline.} =
   result = if x.isNil: y else: x
 
@@ -248,7 +248,7 @@ proc renderRstToOut*(d: var TRstGenerator, n: PRstNode, result: var string)
   ##   renderRstToOut(gen, rst, generatedHTML)
   ##   echo generatedHTML
 
-proc renderAux(d: PDoc, n: PRstNode, result: var string) = 
+proc renderAux(d: PDoc, n: PRstNode, result: var string) =
   for i in countup(0, len(n)-1): renderRstToOut(d, n.sons[i], result)
 
 proc renderAux(d: PDoc, n: PRstNode, frmtA, frmtB: string, result: var string) =
@@ -347,7 +347,7 @@ proc renderIndexTerm*(d: PDoc, n: PRstNode, result: var string) =
   var term = ""
   renderAux(d, n, term)
   setIndexTerm(d, id, term, d.currentSection)
-  dispA(d.target, result, "<span id=\"$1\">$2</span>", "$2\\label{$1}", 
+  dispA(d.target, result, "<span id=\"$1\">$2</span>", "$2\\label{$1}",
         [id, term])
 
 type
@@ -656,7 +656,7 @@ proc mergeIndexes*(dir: string): string =
     result.add("<h2>API symbols</h2>\n")
     result.add(generateSymbolIndex(symbols))
 
-  
+
 # ----------------------------------------------------------------------------
 
 proc stripTOCHTML(s: string): string =
@@ -677,7 +677,7 @@ proc stripTOCHTML(s: string): string =
     result.delete(first, last)
     first = result.find('<', first)
 
-proc renderHeadline(d: PDoc, n: PRstNode, result: var string) = 
+proc renderHeadline(d: PDoc, n: PRstNode, result: var string) =
   var tmp = ""
   for i in countup(0, len(n) - 1): renderRstToOut(d, n.sons[i], tmp)
   d.currentSection = tmp
@@ -700,9 +700,9 @@ proc renderHeadline(d: PDoc, n: PRstNode, result: var string) =
       "id=\"$2\" href=\"#$2\">$3</a></h$1>", "\\rsth$4{$3}\\label{$2}\n",
       [$n.level, d.tocPart[length].refname, tmp, $chr(n.level - 1 + ord('A'))])
   else:
-    dispA(d.target, result, "\n<h$1 id=\"$2\">$3</h$1>", 
+    dispA(d.target, result, "\n<h$1 id=\"$2\">$3</h$1>",
                             "\\rsth$4{$3}\\label{$2}\n", [
-        $n.level, refname, tmp, 
+        $n.level, refname, tmp,
         $chr(n.level - 1 + ord('A'))])
 
   # Generate index entry using spaces to indicate TOC level for the output HTML.
@@ -710,7 +710,7 @@ proc renderHeadline(d: PDoc, n: PRstNode, result: var string) =
   setIndexTerm(d, refname, tmp.stripTOCHTML,
     spaces(max(0, n.level)) & tmp)
 
-proc renderOverline(d: PDoc, n: PRstNode, result: var string) = 
+proc renderOverline(d: PDoc, n: PRstNode, result: var string) =
   if d.meta[metaTitle].len == 0:
     for i in countup(0, len(n)-1):
       renderRstToOut(d, n.sons[i], d.meta[metaTitle])
@@ -723,14 +723,14 @@ proc renderOverline(d: PDoc, n: PRstNode, result: var string) =
     var tmp = ""
     for i in countup(0, len(n) - 1): renderRstToOut(d, n.sons[i], tmp)
     d.currentSection = tmp
-    dispA(d.target, result, "<h$1 id=\"$2\"><center>$3</center></h$1>", 
+    dispA(d.target, result, "<h$1 id=\"$2\"><center>$3</center></h$1>",
                    "\\rstov$4{$3}\\label{$2}\n", [$n.level,
         rstnodeToRefname(n), tmp, $chr(n.level - 1 + ord('A'))])
-  
 
-proc renderTocEntry(d: PDoc, e: TTocEntry, result: var string) = 
+
+proc renderTocEntry(d: PDoc, e: TTocEntry, result: var string) =
   dispA(d.target, result,
-    "<li><a class=\"reference\" id=\"$1_toc\" href=\"#$1\">$2</a></li>\n", 
+    "<li><a class=\"reference\" id=\"$1_toc\" href=\"#$1\">$2</a></li>\n",
     "\\item\\label{$1_toc} $2\\ref{$1}\n", [e.refname, e.header])
 
 proc renderTocEntries*(d: var TRstGenerator, j: var int, lvl: int,
@@ -759,33 +759,33 @@ proc renderImage(d: PDoc, n: PRstNode, result: var string) =
   var options = ""
   var s = getFieldValue(n, "scale")
   if s.valid: dispA(d.target, options, " scale=\"$1\"", " scale=$1", [strip(s)])
-  
+
   s = getFieldValue(n, "height")
   if s.valid: dispA(d.target, options, " height=\"$1\"", " height=$1", [strip(s)])
-  
+
   s = getFieldValue(n, "width")
   if s.valid: dispA(d.target, options, " width=\"$1\"", " width=$1", [strip(s)])
-  
+
   s = getFieldValue(n, "alt")
   if s.valid: dispA(d.target, options, " alt=\"$1\"", "", [strip(s)])
-  
+
   s = getFieldValue(n, "align")
   if s.valid: dispA(d.target, options, " align=\"$1\"", "", [strip(s)])
-  
+
   if options.len > 0: options = dispF(d.target, "$1", "[$1]", [options])
 
   let arg = getArgument(n)
   if arg.valid:
-    dispA(d.target, result, "<img src=\"$1\"$2 />", "\\includegraphics$2{$1}", 
+    dispA(d.target, result, "<img src=\"$1\"$2 />", "\\includegraphics$2{$1}",
           [arg, options])
   if len(n) >= 3: renderRstToOut(d, n.sons[2], result)
-  
+
 proc renderSmiley(d: PDoc, n: PRstNode, result: var string) =
   dispA(d.target, result,
-    """<img src="$1" width="15" 
+    """<img src="$1" width="15"
         height="17" hspace="2" vspace="2" class="smiley" />""",
     "\\includegraphics{$1}", [d.config["doc.smiley_format"] % n.text])
-  
+
 proc parseCodeBlockField(d: PDoc, n: PRstNode, params: var CodeBlockParams) =
   ## Parses useful fields which can appear before a code block.
   ##
@@ -880,11 +880,11 @@ proc renderCodeBlock(d: PDoc, n: PRstNode, result: var string) =
   else:
     var g: TGeneralTokenizer
     initGeneralTokenizer(g, m.text)
-    while true: 
+    while true:
       getNextToken(g, params.lang)
       case g.kind
-      of gtEof: break 
-      of gtNone, gtWhitespace: 
+      of gtEof: break
+      of gtNone, gtWhitespace:
         add(result, substr(m.text, g.start, g.length + g.start - 1))
       else:
         dispA(d.target, result, "<span class=\"$2\">$1</span>", "\\span$2{$1}", [
@@ -893,36 +893,36 @@ proc renderCodeBlock(d: PDoc, n: PRstNode, result: var string) =
     deinitGeneralTokenizer(g)
   dispA(d.target, result, blockEnd, "\n\\end{rstpre}\n")
 
-proc renderContainer(d: PDoc, n: PRstNode, result: var string) = 
+proc renderContainer(d: PDoc, n: PRstNode, result: var string) =
   var tmp = ""
   renderRstToOut(d, n.sons[2], tmp)
   var arg = strip(getArgument(n))
-  if arg == "": 
+  if arg == "":
     dispA(d.target, result, "<div>$1</div>", "$1", [tmp])
   else:
     dispA(d.target, result, "<div class=\"$1\">$2</div>", "$2", [arg, tmp])
-  
-proc texColumns(n: PRstNode): string = 
+
+proc texColumns(n: PRstNode): string =
   result = ""
   for i in countup(1, len(n)): add(result, "|X")
-  
-proc renderField(d: PDoc, n: PRstNode, result: var string) = 
+
+proc renderField(d: PDoc, n: PRstNode, result: var string) =
   var b = false
-  if d.target == outLatex: 
+  if d.target == outLatex:
     var fieldname = addNodes(n.sons[0])
     var fieldval = esc(d.target, strip(addNodes(n.sons[1])))
-    if cmpIgnoreStyle(fieldname, "author") == 0 or 
+    if cmpIgnoreStyle(fieldname, "author") == 0 or
        cmpIgnoreStyle(fieldname, "authors") == 0:
       if d.meta[metaAuthor].len == 0:
         d.meta[metaAuthor] = fieldval
         b = true
-    elif cmpIgnoreStyle(fieldname, "version") == 0: 
+    elif cmpIgnoreStyle(fieldname, "version") == 0:
       if d.meta[metaVersion].len == 0:
         d.meta[metaVersion] = fieldval
         b = true
   if not b:
     renderAux(d, n, "<tr>$1</tr>\n", "$1", result)
-  
+
 proc renderRstToOut(d: PDoc, n: PRstNode, result: var string) =
   if n == nil: return
   case n.kind
@@ -947,54 +947,54 @@ proc renderRstToOut(d: PDoc, n: PRstNode, result: var string) =
   of rnDefBody: renderAux(d, n, "<dd>$1</dd>\n", "$1\n", result)
   of rnFieldList:
     var tmp = ""
-    for i in countup(0, len(n) - 1): 
+    for i in countup(0, len(n) - 1):
       renderRstToOut(d, n.sons[i], tmp)
-    if tmp.len != 0: 
+    if tmp.len != 0:
       dispA(d.target, result,
           "<table class=\"docinfo\" frame=\"void\" rules=\"none\">" &
           "<col class=\"docinfo-name\" />" &
-          "<col class=\"docinfo-content\" />" & 
+          "<col class=\"docinfo-content\" />" &
           "<tbody valign=\"top\">$1" &
-          "</tbody></table>", 
-          "\\begin{description}$1\\end{description}\n", 
+          "</tbody></table>",
+          "\\begin{description}$1\\end{description}\n",
           [tmp])
   of rnField: renderField(d, n, result)
-  of rnFieldName: 
+  of rnFieldName:
     renderAux(d, n, "<th class=\"docinfo-name\">$1:</th>",
                     "\\item[$1:]", result)
-  of rnFieldBody: 
+  of rnFieldBody:
     renderAux(d, n, "<td>$1</td>", " $1\n", result)
-  of rnIndex: 
+  of rnIndex:
     renderRstToOut(d, n.sons[2], result)
-  of rnOptionList: 
-    renderAux(d, n, "<table frame=\"void\">$1</table>", 
+  of rnOptionList:
+    renderAux(d, n, "<table frame=\"void\">$1</table>",
       "\\begin{description}\n$1\\end{description}\n", result)
-  of rnOptionListItem: 
+  of rnOptionListItem:
     renderAux(d, n, "<tr>$1</tr>\n", "$1", result)
-  of rnOptionGroup: 
+  of rnOptionGroup:
     renderAux(d, n, "<th align=\"left\">$1</th>", "\\item[$1]", result)
-  of rnDescription: 
+  of rnDescription:
     renderAux(d, n, "<td align=\"left\">$1</td>\n", " $1\n", result)
-  of rnOption, rnOptionString, rnOptionArgument: 
+  of rnOption, rnOptionString, rnOptionArgument:
     doAssert false, "renderRstToOut"
   of rnLiteralBlock:
-    renderAux(d, n, "<pre>$1</pre>\n", 
+    renderAux(d, n, "<pre>$1</pre>\n",
                     "\\begin{rstpre}\n$1\n\\end{rstpre}\n", result)
-  of rnQuotedLiteralBlock: 
+  of rnQuotedLiteralBlock:
     doAssert false, "renderRstToOut"
-  of rnLineBlock: 
+  of rnLineBlock:
     renderAux(d, n, "<p>$1</p>", "$1\n\n", result)
-  of rnLineBlockItem: 
+  of rnLineBlockItem:
     renderAux(d, n, "$1<br />", "$1\\\\\n", result)
-  of rnBlockQuote: 
-    renderAux(d, n, "<blockquote><p>$1</p></blockquote>\n", 
+  of rnBlockQuote:
+    renderAux(d, n, "<blockquote><p>$1</p></blockquote>\n",
                     "\\begin{quote}$1\\end{quote}\n", result)
-  of rnTable, rnGridTable: 
-    renderAux(d, n, 
-      "<table border=\"1\" class=\"docutils\">$1</table>", 
+  of rnTable, rnGridTable:
+    renderAux(d, n,
+      "<table border=\"1\" class=\"docutils\">$1</table>",
       "\\begin{table}\\begin{rsttab}{" &
         texColumns(n) & "|}\n\\hline\n$1\\end{rsttab}\\end{table}", result)
-  of rnTableRow: 
+  of rnTableRow:
     if len(n) >= 1:
       if d.target == outLatex:
         #var tmp = ""
@@ -1007,25 +1007,25 @@ proc renderRstToOut(d: PDoc, n: PRstNode, result: var string) =
         result.add("<tr>")
         renderAux(d, n, result)
         result.add("</tr>\n")
-  of rnTableDataCell: 
+  of rnTableDataCell:
     renderAux(d, n, "<td>$1</td>", "$1", result)
-  of rnTableHeaderCell: 
+  of rnTableHeaderCell:
     renderAux(d, n, "<th>$1</th>", "\\textbf{$1}", result)
-  of rnLabel: 
+  of rnLabel:
     doAssert false, "renderRstToOut" # used for footnotes and other
-  of rnFootnote: 
+  of rnFootnote:
     doAssert false, "renderRstToOut" # a footnote
-  of rnCitation: 
+  of rnCitation:
     doAssert false, "renderRstToOut" # similar to footnote
-  of rnRef: 
+  of rnRef:
     var tmp = ""
     renderAux(d, n, tmp)
     dispA(d.target, result,
       "<a class=\"reference external\" href=\"#$2\">$1</a>",
       "$1\\ref{$2}", [tmp, rstnodeToRefname(n)])
-  of rnStandaloneHyperlink: 
-    renderAux(d, n, 
-      "<a class=\"reference external\" href=\"$1\">$1</a>", 
+  of rnStandaloneHyperlink:
+    renderAux(d, n,
+      "<a class=\"reference external\" href=\"$1\">$1</a>",
       "\\href{$1}{$1}", result)
   of rnHyperlink:
     var tmp0 = ""
@@ -1042,11 +1042,11 @@ proc renderRstToOut(d: PDoc, n: PRstNode, result: var string) =
   of rnRawLatex:
     if d.target == outLatex:
       result.add addNodes(lastSon(n))
-      
+
   of rnImage, rnFigure: renderImage(d, n, result)
   of rnCodeBlock: renderCodeBlock(d, n, result)
   of rnContainer: renderContainer(d, n, result)
-  of rnSubstitutionReferences, rnSubstitutionDef: 
+  of rnSubstitutionReferences, rnSubstitutionDef:
     renderAux(d, n, "|$1|", "|$1|", result)
   of rnDirective:
     renderAux(d, n, "", "", result)
@@ -1063,15 +1063,15 @@ proc renderRstToOut(d: PDoc, n: PRstNode, result: var string) =
   of rnStrongEmphasis:
     renderAux(d, n, "<strong>$1</strong>", "\\textbf{$1}", result)
   of rnTripleEmphasis:
-    renderAux(d, n, "<strong><em>$1</em></strong>", 
+    renderAux(d, n, "<strong><em>$1</em></strong>",
                     "\\textbf{emph{$1}}", result)
   of rnInterpretedText:
     renderAux(d, n, "<cite>$1</cite>", "\\emph{$1}", result)
   of rnIdx:
     renderIndexTerm(d, n, result)
-  of rnInlineLiteral: 
-    renderAux(d, n, 
-      "<tt class=\"docutils literal\"><span class=\"pre\">$1</span></tt>", 
+  of rnInlineLiteral:
+    renderAux(d, n,
+      "<tt class=\"docutils literal\"><span class=\"pre\">$1</span></tt>",
       "\\texttt{$1}", result)
   of rnSmiley: renderSmiley(d, n, result)
   of rnLeaf: result.add(esc(d.target, n.text))
@@ -1082,55 +1082,55 @@ proc renderRstToOut(d: PDoc, n: PRstNode, result: var string) =
 
 # -----------------------------------------------------------------------------
 
-proc getVarIdx(varnames: openArray[string], id: string): int = 
-  for i in countup(0, high(varnames)): 
-    if cmpIgnoreStyle(varnames[i], id) == 0: 
+proc getVarIdx(varnames: openArray[string], id: string): int =
+  for i in countup(0, high(varnames)):
+    if cmpIgnoreStyle(varnames[i], id) == 0:
       return i
   result = -1
 
-proc formatNamedVars*(frmt: string, varnames: openArray[string], 
-                      varvalues: openArray[string]): string = 
+proc formatNamedVars*(frmt: string, varnames: openArray[string],
+                      varvalues: openArray[string]): string =
   var i = 0
   var L = len(frmt)
   result = ""
   var num = 0
-  while i < L: 
-    if frmt[i] == '$': 
+  while i < L:
+    if frmt[i] == '$':
       inc(i)                  # skip '$'
       case frmt[i]
-      of '#': 
+      of '#':
         add(result, varvalues[num])
         inc(num)
         inc(i)
-      of '$': 
+      of '$':
         add(result, "$")
         inc(i)
-      of '0'..'9': 
+      of '0'..'9':
         var j = 0
-        while true: 
+        while true:
           j = (j * 10) + ord(frmt[i]) - ord('0')
           inc(i)
-          if i > L-1 or frmt[i] notin {'0'..'9'}: break 
+          if i > L-1 or frmt[i] notin {'0'..'9'}: break
         if j > high(varvalues) + 1:
           raise newException(ValueError, "invalid index: " & $j)
         num = j
         add(result, varvalues[j - 1])
-      of 'A'..'Z', 'a'..'z', '\x80'..'\xFF': 
+      of 'A'..'Z', 'a'..'z', '\x80'..'\xFF':
         var id = ""
-        while true: 
+        while true:
           add(id, frmt[i])
           inc(i)
-          if frmt[i] notin {'A'..'Z', '_', 'a'..'z', '\x80'..'\xFF'}: break 
+          if frmt[i] notin {'A'..'Z', '_', 'a'..'z', '\x80'..'\xFF'}: break
         var idx = getVarIdx(varnames, id)
-        if idx >= 0: 
+        if idx >= 0:
           add(result, varvalues[idx])
         else:
           raise newException(ValueError, "unknown substitution var: " & id)
-      of '{': 
+      of '{':
         var id = ""
         inc(i)
-        while frmt[i] != '}': 
-          if frmt[i] == '\0': 
+        while frmt[i] != '}':
+          if frmt[i] == '\0':
             raise newException(ValueError, "'}' expected")
           add(id, frmt[i])
           inc(i)
@@ -1138,12 +1138,12 @@ proc formatNamedVars*(frmt: string, varnames: openArray[string],
                               # search for the variable:
         var idx = getVarIdx(varnames, id)
         if idx >= 0: add(result, varvalues[idx])
-        else: 
+        else:
           raise newException(ValueError, "unknown substitution var: " & id)
       else:
         raise newException(ValueError, "unknown substitution: $" & $frmt[i])
     var start = i
-    while i < L: 
+    while i < L:
       if frmt[i] != '$': inc(i)
       else: break
     if i-1 >= start: add(result, substr(frmt, start, i - 1))
@@ -1163,10 +1163,10 @@ proc defaultConfig*(): StringTableRef =
   ## pages, while this proc returns just the content for procs like
   ## ``rstToHtml`` to generate the bare minimum HTML.
   result = newStringTable(modeStyleInsensitive)
-  
+
   template setConfigVar(key, val: expr) =
     result[key] = val
-  
+
   # If you need to modify these values, it might be worth updating the template
   # file in config/nimdoc.cfg.
   setConfigVar("split.item.toc", "20")
@@ -1214,7 +1214,7 @@ $content
 
 # ---------- forum ---------------------------------------------------------
 
-proc rstToHtml*(s: string, options: TRstParseOptions, 
+proc rstToHtml*(s: string, options: TRstParseOptions,
                 config: StringTableRef): string =
   ## Converts an input rst string into embeddable HTML.
   ##
@@ -1236,13 +1236,13 @@ proc rstToHtml*(s: string, options: TRstParseOptions,
   ## output you have to create your own ``TRstGenerator`` with
   ## ``initRstGenerator`` and related procs.
 
-  proc myFindFile(filename: string): string = 
+  proc myFindFile(filename: string): string =
     # we don't find any files in online mode:
     result = ""
 
   const filen = "input"
   var d: TRstGenerator
-  initRstGenerator(d, outHtml, config, filen, options, myFindFile, 
+  initRstGenerator(d, outHtml, config, filen, options, myFindFile,
                    rst.defaultMsgHandler)
   var dummyHasToc = false
   var rst = rstParse(s, filen, 0, 1, dummyHasToc, options)
@@ -1251,5 +1251,6 @@ proc rstToHtml*(s: string, options: TRstParseOptions,
 
 
 when isMainModule:
-  echo rstToHtml("*Hello* **world**!", {},
-    newStringTable(modeStyleInsensitive))
+  assert rstToHtml("*Hello* **world**!", {},
+    newStringTable(modeStyleInsensitive)) ==
+    "<em>Hello</em> <strong>world</strong>!"
diff --git a/lib/posix/termios.nim b/lib/posix/termios.nim
index 830e8a207..710b2fa6b 100644
--- a/lib/posix/termios.nim
+++ b/lib/posix/termios.nim
@@ -10,28 +10,25 @@
 {.deadCodeElim: on.}
 import posix
 
-type 
+type
   Speed* = cuint
   Tcflag* = cuint
 
-const 
+const
   NCCS* = 32
 
-type 
-  Termios* = object {.importc: "struct termios", header: "<termios.h>", final, pure.}
-    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 
-  
-
-# cc characters 
-
-const 
+type
+  Termios* {.importc: "struct termios", header: "<termios.h>".} = object
+    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
+
+const
   VINTR* = 0
   VQUIT* = 1
   VERASE* = 2
@@ -50,9 +47,9 @@ const
   VLNEXT* = 15
   VEOL2* = 16
 
-# iflag bits 
+# iflag bits
 
-const 
+const
   IGNBRK* = 1
   BRKINT* = 2
   IGNPAR* = 4
@@ -69,9 +66,9 @@ const
   IMAXBEL* = 20000
   IUTF8* = 40000
 
-# oflag bits 
+# oflag bits
 
-const 
+const
   OPOST* = 1
   OLCUC* = 2
   ONLCR* = 4
@@ -104,9 +101,9 @@ const
   VT1* = 40000
   XTABS* = 14000
 
-# cflag bit meaning 
+# cflag bit meaning
 
-const 
+const
   CBAUD* = 10017
   B0* = 0
   B50* = 1
@@ -158,9 +155,9 @@ const
   CMSPAR* = 0o010000000000
   CRTSCTS* = 0o020000000000
 
-# lflag bits 
+# lflag bits
 
-const 
+const
   ISIG* = 1
   ICANON* = 2
   XCASE* = 4
@@ -178,87 +175,87 @@ const
   IEXTEN* = 0o000000100000
   EXTPROC* = 0o000000200000
 
-# tcflow() and TCXONC use these 
+# tcflow() and TCXONC use these
 
-const 
+const
   TCOOFF* = 0
   TCOON* = 1
   TCIOFF* = 2
   TCION* = 3
 
-# tcflush() and TCFLSH use these 
+# tcflush() and TCFLSH use these
 
-const 
+const
   TCIFLUSH* = 0
   TCOFLUSH* = 1
   TCIOFLUSH* = 2
 
-# tcsetattr uses these 
+# tcsetattr uses these
 
-const 
+const
   TCSANOW* = 0
   TCSADRAIN* = 1
   TCSAFLUSH* = 2
 
 # Compare a character C to a value VAL from the `cc' array in a
-#   `struct termios'.  If VAL is _POSIX_VDISABLE, no character can match it.  
+#   `struct termios'.  If VAL is _POSIX_VDISABLE, no character can match it.
 
-template cceq*(val, c: expr): expr = 
+template cceq*(val, c: expr): expr =
   c == val and val != POSIX_VDISABLE
 
-# Return the output baud rate stored in *TERMIOS_P.  
+# Return the output baud rate stored in *TERMIOS_P.
 
-proc cfGetOspeed*(termios: ptr Termios): Speed {.importc: "cfgetospeed", 
+proc cfGetOspeed*(termios: ptr Termios): Speed {.importc: "cfgetospeed",
     header: "<termios.h>".}
-# Return the input baud rate stored in *TERMIOS_P.  
+# Return the input baud rate stored in *TERMIOS_P.
 
-proc cfGetIspeed*(termios: ptr Termios): Speed {.importc: "cfgetispeed", 
+proc cfGetIspeed*(termios: ptr Termios): Speed {.importc: "cfgetispeed",
     header: "<termios.h>".}
-# Set the output baud rate stored in *TERMIOS_P to SPEED.  
+# Set the output baud rate stored in *TERMIOS_P to SPEED.
 
 proc cfSetOspeed*(termios: ptr Termios; speed: Speed): cint {.
     importc: "cfsetospeed", header: "<termios.h>".}
-# Set the input baud rate stored in *TERMIOS_P to SPEED.  
+# Set the input baud rate stored in *TERMIOS_P to SPEED.
 
 proc cfSetIspeed*(termios: ptr Termios; speed: Speed): cint {.
     importc: "cfsetispeed", header: "<termios.h>".}
-# Set both the input and output baud rates in *TERMIOS_OP to SPEED.  
+# Set both the input and output baud rates in *TERMIOS_OP to SPEED.
 
 proc cfSetSpeed*(termios: ptr Termios; speed: Speed): cint {.
     importc: "cfsetspeed", header: "<termios.h>".}
-# Put the state of FD into *TERMIOS_P.  
+# Put the state of FD into *TERMIOS_P.
 
 proc tcGetAttr*(fd: cint; termios: ptr Termios): cint {.
     importc: "tcgetattr", header: "<termios.h>".}
 # Set the state of FD to *TERMIOS_P.
-#   Values for OPTIONAL_ACTIONS (TCSA*) are in <bits/termios.h>.  
+#   Values for OPTIONAL_ACTIONS (TCSA*) are in <bits/termios.h>.
 
 proc tcSetAttr*(fd: cint; optional_actions: cint; termios: ptr Termios): cint {.
     importc: "tcsetattr", header: "<termios.h>".}
-# Set *TERMIOS_P to indicate raw mode.  
+# Set *TERMIOS_P to indicate raw mode.
 
-proc cfMakeRaw*(termios: ptr Termios) {.importc: "cfmakeraw", 
+proc cfMakeRaw*(termios: ptr Termios) {.importc: "cfmakeraw",
     header: "<termios.h>".}
-# Send zero bits on FD.  
+# Send zero bits on FD.
 
-proc tcSendBreak*(fd: cint; duration: cint): cint {.importc: "tcsendbreak", 
+proc tcSendBreak*(fd: cint; duration: cint): cint {.importc: "tcsendbreak",
     header: "<termios.h>".}
 # Wait for pending output to be written on FD.
 #
 #   This function is a cancellation point and therefore not marked with
-#  .  
+#  .
 
 proc tcDrain*(fd: cint): cint {.importc: "tcdrain", header: "<termios.h>".}
 # Flush pending data on FD.
-#   Values for QUEUE_SELECTOR (TC{I,O,IO}FLUSH) are in <bits/termios.h>.  
+#   Values for QUEUE_SELECTOR (TC{I,O,IO}FLUSH) are in <bits/termios.h>.
 
-proc tcFlush*(fd: cint; queue_selector: cint): cint {.importc: "tcflush", 
+proc tcFlush*(fd: cint; queue_selector: cint): cint {.importc: "tcflush",
     header: "<termios.h>".}
 # Suspend or restart transmission on FD.
-#   Values for ACTION (TC[IO]{OFF,ON}) are in <bits/termios.h>.  
+#   Values for ACTION (TC[IO]{OFF,ON}) are in <bits/termios.h>.
 
-proc tcFlow*(fd: cint; action: cint): cint {.importc: "tcflow", 
+proc tcFlow*(fd: cint; action: cint): cint {.importc: "tcflow",
     header: "<termios.h>".}
-# Get process group ID for session leader for controlling terminal FD.  
+# Get process group ID for session leader for controlling terminal FD.
 
 proc tcGetSid*(fd: cint): TPid {.importc: "tcgetsid", header: "<termios.h>".}
diff --git a/lib/pure/actors.nim b/lib/pure/actors.nim
index 8c61ce7df..294c24741 100644
--- a/lib/pure/actors.nim
+++ b/lib/pure/actors.nim
@@ -221,7 +221,7 @@ proc spawn*[TIn](p: var TActorPool[TIn, void], input: TIn,
   setupTask()
   schedule()
   
-when isMainModule:
+when not defined(testing) and isMainModule:
   var
     a: TActorPool[int, void]
   createActorPool(a)
diff --git a/lib/pure/algorithm.nim b/lib/pure/algorithm.nim
index 68960e2e8..0eafb316a 100644
--- a/lib/pure/algorithm.nim
+++ b/lib/pure/algorithm.nim
@@ -24,6 +24,17 @@ proc `*`*(x: int, order: SortOrder): int {.inline.} =
   var y = order.ord - 1
   result = (x xor y) - y
 
+proc fill*[T](a: var openArray[T], first, last: Natural, value: T) =
+  ## fills the array ``a[first..last]`` with `value`.
+  var x = first
+  while x <= last:
+    a[x] = value
+    inc(x)
+
+proc fill*[T](a: var openArray[T], value: T) =
+  ## fills the array `a` with `value`.
+  fill(a, 0, a.high, value)
+
 proc reverse*[T](a: var openArray[T], first, last: Natural) =
   ## reverses the array ``a[first..last]``.
   var x = first
@@ -40,8 +51,8 @@ proc reverse*[T](a: var openArray[T]) =
 proc reversed*[T](a: openArray[T], first, last: Natural): seq[T] =
   ## returns the reverse of the array `a[first..last]`.
   result = newSeq[T](last - first + 1)
-  var x = first
-  var y = last
+  var x = first.int
+  var y = last.int
   while x <= last:
     result[x] = a[y]
     dec(y)
@@ -210,8 +221,7 @@ template sortedByIt*(seq1, op: expr): expr =
   ##     p2: Person = (name: "p2", age: 20)
   ##     p3: Person = (name: "p3", age: 30)
   ##     p4: Person = (name: "p4", age: 30)
-  ##
-  ##   people = @[p1,p2,p4,p3]
+  ##     people = @[p1,p2,p4,p3]
   ##
   ##   echo people.sortedByIt(it.name)
   ##
@@ -233,7 +243,7 @@ template sortedByIt*(seq1, op: expr): expr =
 proc product*[T](x: openArray[seq[T]]): seq[seq[T]] =
   ## produces the Cartesian product of the array. Warning: complexity
   ## may explode.
-  result = @[]
+  result = newSeq[seq[T]]()
   if x.len == 0:
     return
   if x.len == 1:
@@ -243,8 +253,7 @@ proc product*[T](x: openArray[seq[T]]): seq[seq[T]] =
     indexes = newSeq[int](x.len)
     initial = newSeq[int](x.len)
     index = 0
-  # replace with newSeq as soon as #853 is fixed
-  var next: seq[T] = @[]
+  var next = newSeq[T]()
   next.setLen(x.len)
   for i in 0..(x.len-1):
     if len(x[i]) == 0: return
diff --git a/lib/pure/asyncdispatch.nim b/lib/pure/asyncdispatch.nim
index 27f77cef2..8010e9ebc 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")
@@ -1043,7 +1154,7 @@ else:
 
 proc sleepAsync*(ms: int): Future[void] =
   ## Suspends the execution of the current async procedure for the next
-  ## ``ms`` miliseconds.
+  ## ``ms`` milliseconds.
   var retFuture = newFuture[void]("sleepAsync")
   let p = getGlobalDispatcher()
   p.timers.add((epochTime() + (ms / 1000), retFuture))
@@ -1217,7 +1328,7 @@ proc processBody(node, retFutureSym: NimNode,
     else: discard
   of nnkDiscardStmt:
     # discard await x
-    if node[0].kind != nnkEmpty and node[0][0].kind == nnkIdent and
+    if node[0].kind == nnkCommand and node[0][0].kind == nnkIdent and
           node[0][0].ident == !"await":
       var newDiscard = node
       result.createVar("futureDiscard_" & $toStrLit(node[0][1]), node[0][1],
diff --git a/lib/pure/asyncftpclient.nim b/lib/pure/asyncftpclient.nim
index 96f54b49e..daf69d59f 100644
--- a/lib/pure/asyncftpclient.nim
+++ b/lib/pure/asyncftpclient.nim
@@ -300,7 +300,7 @@ proc newAsyncFtpClient*(address: string, port = Port(21),
   result.dsockConnected = false
   result.csock = newAsyncSocket()
 
-when isMainModule:
+when not defined(testing) and isMainModule:
   var ftp = newAsyncFtpClient("example.com", user = "test", pass = "test")
   proc main(ftp: AsyncFtpClient) {.async.} =
     await ftp.connect()
diff --git a/lib/pure/asynchttpserver.nim b/lib/pure/asynchttpserver.nim
index 64242234c..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()
@@ -260,7 +262,7 @@ proc close*(server: AsyncHttpServer) =
   ## Terminates the async http server instance.
   server.socket.close()
 
-when isMainModule:
+when not defined(testing) and isMainModule:
   proc main =
     var server = newAsyncHttpServer()
     proc cb(req: Request) {.async.} =
diff --git a/lib/pure/asyncio.nim b/lib/pure/asyncio.nim
index f58bb4302..6ae2c608b 100644
--- a/lib/pure/asyncio.nim
+++ b/lib/pure/asyncio.nim
@@ -660,7 +660,7 @@ proc len*(disp: Dispatcher): int =
   ## Retrieves the amount of delegates in ``disp``.
   return disp.delegates.len
 
-when isMainModule:
+when not defined(testing) and isMainModule:
 
   proc testConnect(s: AsyncSocket, no: int) =
     echo("Connected! " & $no)
diff --git a/lib/pure/asyncnet.nim b/lib/pure/asyncnet.nim
index e7325e0d7..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.
@@ -458,7 +496,7 @@ proc isClosed*(socket: AsyncSocket): bool =
   ## Determines whether the socket has been closed.
   return socket.closed
 
-when isMainModule:
+when not defined(testing) and isMainModule:
   type
     TestCases = enum
       HighClient, LowClient, LowServer
@@ -500,11 +538,11 @@ when 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/LockFreeHash.nim b/lib/pure/collections/LockFreeHash.nim
index c3954468a..0df97c685 100644
--- a/lib/pure/collections/LockFreeHash.nim
+++ b/lib/pure/collections/LockFreeHash.nim
@@ -525,7 +525,7 @@ proc get*[K,V](table: var PConcTable[K,V], key: var K): V =
 
 
 #Tests ----------------------------
-when isMainModule:
+when not defined(testing) and isMainModule:
   import locks, times, mersenne
   
   const 
diff --git a/lib/pure/collections/critbits.nim b/lib/pure/collections/critbits.nim
index 3d10e39aa..7e3f23851 100644
--- a/lib/pure/collections/critbits.nim
+++ b/lib/pure/collections/critbits.nim
@@ -286,18 +286,19 @@ proc `$`*[T](c: CritBitTree[T]): string =
     result.add("}")
 
 when isMainModule:
+  import sequtils
+
   var r: CritBitTree[void]
   r.incl "abc"
   r.incl "xyz"
   r.incl "def"
   r.incl "definition"
   r.incl "prefix"
+
   doAssert r.contains"def"
-  #r.del "def"
 
-  for w in r.items:
-    echo w
-    
-  for w in r.itemsWithPrefix("de"):
-    echo w
+  r.excl "def"
+
+  assert toSeq(r.items) == @["abc", "definition", "prefix", "xyz"]
 
+  assert toSeq(r.itemsWithPrefix("de")) == @["definition"]
diff --git a/lib/pure/collections/intsets.nim b/lib/pure/collections/intsets.nim
index ae26c5af6..25f6616a6 100644
--- a/lib/pure/collections/intsets.nim
+++ b/lib/pure/collections/intsets.nim
@@ -198,14 +198,21 @@ proc empty*(s: IntSet): bool {.inline, deprecated.} =
   result = s.counter == 0
 
 when isMainModule:
+  import sequtils, algorithm
+
   var x = initIntSet()
   x.incl(1)
   x.incl(2)
   x.incl(7)
   x.incl(1056)
-  for e in items(x): echo e
 
-  var y: TIntSet
+  var xs = toSeq(items(x))
+  xs.sort(cmp[int])
+  assert xs == @[1, 2, 7, 1056]
+
+  var y: IntSet
   assign(y, x)
-  for e in items(y): echo e
+  var ys = toSeq(items(y))
+  ys.sort(cmp[int])
+  assert ys == @[1, 2, 7, 1056]
 
diff --git a/lib/pure/collections/sequtils.nim b/lib/pure/collections/sequtils.nim
index 3f37d1ef0..e9cd2cb3c 100644
--- a/lib/pure/collections/sequtils.nim
+++ b/lib/pure/collections/sequtils.nim
@@ -492,9 +492,8 @@ when isMainModule:
 
   block: # filter iterator test
     let numbers = @[1, 4, 5, 8, 9, 7, 4]
-    for n in filter(numbers, proc (x: int): bool = x mod 2 == 0):
-      echo($n)
-    # echoes 4, 8, 4 in separate lines
+    assert toSeq(filter(numbers, proc (x: int): bool = x mod 2 == 0)) ==
+      @[4, 8, 4]
 
   block: # keepIf test
     var floats = @[13.0, 12.5, 5.8, 2.0, 6.1, 9.9, 10.1]
@@ -616,4 +615,5 @@ when isMainModule:
     #doAssert a.repeat(-1) == @[] # will not compile!
     doAssert b.repeat(3) == @[]
 
-  echo "Finished doc tests"
+  when not defined(testing):
+    echo "Finished doc tests"
diff --git a/lib/pure/collections/sets.nim b/lib/pure/collections/sets.nim
index bd6c2dc20..280e0eeba 100644
--- a/lib/pure/collections/sets.nim
+++ b/lib/pure/collections/sets.nim
@@ -970,6 +970,7 @@ when isMainModule and not defined(release):
       if s <= i or mustRehash(s, i):
         echo "performance issue: rightSize() will not elide enlarge() at ", i
 
-    echo "Micro tests run successfully."
+    when not defined(testing):
+      echo "Micro tests run successfully."
 
   testModule()
diff --git a/lib/pure/collections/tables.nim b/lib/pure/collections/tables.nim
index 5c4ac0401..9496fa2fe 100644
--- a/lib/pure/collections/tables.nim
+++ b/lib/pure/collections/tables.nim
@@ -215,6 +215,10 @@ proc hasKey*[A, B](t: Table[A, B], key: A): bool =
   var hc: THash
   result = rawGet(t, key, hc) >= 0
 
+proc contains*[A, B](t: Table[A, B], key: A): bool =
+  ## alias of `hasKey` for use with the `in` operator.
+  return hasKey[A, B](t, key)
+
 proc rawInsert[A, B](t: var Table[A, B], data: var KeyValuePairSeq[A, B],
                      key: A, val: B, hc: THash, h: THash) =
   rawInsertImpl()
@@ -411,6 +415,10 @@ proc hasKey*[A, B](t: TableRef[A, B], key: A): bool =
   ## returns true iff `key` is in the table `t`.
   result = t[].hasKey(key)
 
+proc contains*[A, B](t: TableRef[A, B], key: A): bool =
+  ## alias of `hasKey` for use with the `in` operator.
+  return hasKey[A, B](t, key)
+
 proc `[]=`*[A, B](t: TableRef[A, B], key: A, val: B) =
   ## puts a (key, value)-pair into `t`.
   t[][key] = val
@@ -532,6 +540,10 @@ proc hasKey*[A, B](t: OrderedTable[A, B], key: A): bool =
   var hc: THash
   result = rawGet(t, key, hc) >= 0
 
+proc contains*[A, B](t: OrderedTable[A, B], key: A): bool =
+  ## alias of `hasKey` for use with the `in` operator.
+  return hasKey[A, B](t, key)
+
 proc rawInsert[A, B](t: var OrderedTable[A, B],
                      data: var OrderedKeyValuePairSeq[A, B],
                      key: A, val: B, hc: THash, h: THash) =
@@ -704,6 +716,10 @@ proc hasKey*[A, B](t: OrderedTableRef[A, B], key: A): bool =
   ## returns true iff `key` is in the table `t`.
   result = t[].hasKey(key)
 
+proc contains*[A, B](t: OrderedTableRef[A, B], key: A): bool =
+  ## alias of `hasKey` for use with the `in` operator.
+  return hasKey[A, B](t, key)
+
 proc `[]=`*[A, B](t: OrderedTableRef[A, B], key: A, val: B) =
   ## puts a (key, value)-pair into `t`.
   t[][key] = val
@@ -804,6 +820,10 @@ proc hasKey*[A](t: CountTable[A], key: A): bool =
   ## returns true iff `key` is in the table `t`.
   result = rawGet(t, key) >= 0
 
+proc contains*[A](t: CountTable[A], key: A): bool =
+  ## alias of `hasKey` for use with the `in` operator.
+  return hasKey[A](t, key)
+
 proc rawInsert[A](t: CountTable[A], data: var seq[tuple[key: A, val: int]],
                   key: A, val: int) =
   var h: THash = hash(key) and high(data)
@@ -819,15 +839,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.
@@ -942,6 +965,10 @@ proc hasKey*[A](t: CountTableRef[A], key: A): bool =
   ## returns true iff `key` is in the table `t`.
   result = t[].hasKey(key)
 
+proc contains*[A](t: CountTableRef[A], key: A): bool =
+  ## alias of `hasKey` for use with the `in` operator.
+  return hasKey[A](t, key)
+
 proc `[]=`*[A](t: CountTableRef[A], key: A, val: int) =
   ## puts a (key, value)-pair into `t`. `val` has to be positive.
   assert val > 0
@@ -984,6 +1011,22 @@ proc sort*[A](t: CountTableRef[A]) =
   ## `t` in the sorted order.
   t[].sort
 
+proc merge*[A](s: var CountTable[A], t: CountTable[A]) =
+  ## merges the second table into the first one
+  for key, value in t:
+    s.inc(key, value)
+
+proc merge*[A](s, t: CountTable[A]): CountTable[A] =
+  ## merges the two tables into a new one
+  result = initCountTable[A](nextPowerOfTwo(max(s.len, t.len)))
+  for table in @[s, t]:
+    for key, value in table:
+      result.inc(key, value)
+
+proc merge*[A](s, t: CountTableRef[A]) =
+  ## merges the second table into the first one
+  s[].merge(t[])
+
 when isMainModule:
   type
     Person = object
@@ -1012,3 +1055,48 @@ when isMainModule:
   s2[p2] = 45_000
   s3[p1] = 30_000
   s3[p2] = 45_000
+
+  var
+    t1 = initCountTable[string]()
+    t2 = initCountTable[string]()
+  t1.inc("foo")
+  t1.inc("bar", 2)
+  t1.inc("baz", 3)
+  t2.inc("foo", 4)
+  t2.inc("bar")
+  t2.inc("baz", 11)
+  merge(t1, t2)
+  assert(t1["foo"] == 5)
+  assert(t1["bar"] == 3)
+  assert(t1["baz"] == 14)
+
+  let
+    t1r = newCountTable[string]()
+    t2r = newCountTable[string]()
+  t1r.inc("foo")
+  t1r.inc("bar", 2)
+  t1r.inc("baz", 3)
+  t2r.inc("foo", 4)
+  t2r.inc("bar")
+  t2r.inc("baz", 11)
+  merge(t1r, t2r)
+  assert(t1r["foo"] == 5)
+  assert(t1r["bar"] == 3)
+  assert(t1r["baz"] == 14)
+
+  var
+    t1l = initCountTable[string]()
+    t2l = initCountTable[string]()
+  t1l.inc("foo")
+  t1l.inc("bar", 2)
+  t1l.inc("baz", 3)
+  t2l.inc("foo", 4)
+  t2l.inc("bar")
+  t2l.inc("baz", 11)
+  let
+    t1merging = t1l
+    t2merging = t2l
+  let merged = merge(t1merging, t2merging)
+  assert(merged["foo"] == 5)
+  assert(merged["bar"] == 3)
+  assert(merged["baz"] == 14)
diff --git a/lib/pure/concurrency/cpuload.nim b/lib/pure/concurrency/cpuload.nim
index c1796089a..7ce5e01b7 100644
--- a/lib/pure/concurrency/cpuload.nim
+++ b/lib/pure/concurrency/cpuload.nim
@@ -78,7 +78,7 @@ proc advice*(s: var ThreadPoolState): ThreadPoolAdvice =
     result = doNothing
   inc s.calls
 
-when isMainModule:
+when not defined(testing) and isMainModule:
   proc busyLoop() =
     while true:
       discard random(80)
diff --git a/lib/pure/concurrency/threadpool.nim b/lib/pure/concurrency/threadpool.nim
index 9f1e53fb8..a431691ad 100644
--- a/lib/pure/concurrency/threadpool.nim
+++ b/lib/pure/concurrency/threadpool.nim
@@ -300,7 +300,7 @@ proc setMinPoolSize*(size: range[1..MaxThreadPoolSize]) =
   minPoolSize = size
 
 proc setMaxPoolSize*(size: range[1..MaxThreadPoolSize]) =
-  ## sets the minimal thread pool size. The default value of this
+  ## sets the maximal thread pool size. The default value of this
   ## is ``MaxThreadPoolSize``.
   maxPoolSize = size
   if currentPoolSize > maxPoolSize:
diff --git a/lib/pure/cookies.nim b/lib/pure/cookies.nim
index 6247efed2..9983c4a04 100644
--- a/lib/pure/cookies.nim
+++ b/lib/pure/cookies.nim
@@ -56,6 +56,12 @@ proc setCookie*(key, value: string, expires: TimeInfo,
 when isMainModule:
   var tim = Time(int(getTime()) + 76 * (60 * 60 * 24))
 
-  echo(setCookie("test", "value", tim.getGMTime()))
+  let cookie = setCookie("test", "value", tim.getGMTime())
+  when not defined(testing):
+    echo cookie
+  let start = "Set-Cookie: test=value; Expires="
+  assert cookie[0..start.high] == start
   
-  echo parseCookies("uid=1; kp=2")
+  let table = parseCookies("uid=1; kp=2")
+  assert table["uid"] == "1"
+  assert table["kp"] == "2"
diff --git a/lib/pure/encodings.nim b/lib/pure/encodings.nim
index 25c7ad9ef..2a6134615 100644
--- a/lib/pure/encodings.nim
+++ b/lib/pure/encodings.nim
@@ -451,7 +451,7 @@ proc convert*(s: string, destEncoding = "UTF-8",
   finally:
     close(c)
 
-when isMainModule:
+when not defined(testing) and isMainModule:
   let
     orig = "öäüß"
     cp1252 = convert(orig, "CP1252", "UTF-8")
diff --git a/lib/pure/fsmonitor.nim b/lib/pure/fsmonitor.nim
index e6919b661..83779eb9c 100644
--- a/lib/pure/fsmonitor.nim
+++ b/lib/pure/fsmonitor.nim
@@ -198,7 +198,7 @@ proc register*(d: Dispatcher, monitor: FSMonitor,
   var deleg = toDelegate(monitor)
   d.register(deleg)
 
-when isMainModule:
+when not defined(testing) and isMainModule:
   proc main =
     var disp = newDispatcher()
     var monitor = newMonitor()
diff --git a/lib/pure/ftpclient.nim b/lib/pure/ftpclient.nim
index dc387b79c..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 =
@@ -629,7 +629,7 @@ when isMainModule:
       if not d.poll(): break
   main()
 
-when isMainModule and false:
+when not defined(testing) and isMainModule:
   var ftp = ftpClient("example.com", user = "foo", pass = "bar")
   ftp.connect()
   echo ftp.pwd()
diff --git a/lib/pure/gentabs.nim b/lib/pure/gentabs.nim
index a6128efc9..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,31 +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
-  
-  for k,v in pairs(z):
-    echo( "$# ($#) ->" % [k,$len(v)] )
-    #for k2,v2 in pairs(v):
-    #  echo( "   $# <-> $#" % [k2,$v2] )
-  echo()
+
+  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/hashes.nim b/lib/pure/hashes.nim
index a16342d44..2ce8ac796 100644
--- a/lib/pure/hashes.nim
+++ b/lib/pure/hashes.nim
@@ -37,29 +37,29 @@
 ##    h = h !& hash(x.bar)
 ##    result = !$h
 
-import 
+import
   strutils
 
-type 
-  THash* = int ## a hash value; hash tables using these values should 
+type
+  THash* = int ## a hash value; hash tables using these values should
                ## always have a size of a power of two and can use the ``and``
                ## operator instead of ``mod`` for truncation of the hash value.
 
-proc `!&`*(h: THash, val: int): THash {.inline.} = 
+proc `!&`*(h: THash, val: int): THash {.inline.} =
   ## mixes a hash value `h` with `val` to produce a new hash value. This is
   ## only needed if you need to implement a hash proc for a new datatype.
   result = h +% val
   result = result +% result shl 10
   result = result xor (result shr 6)
 
-proc `!$`*(h: THash): THash {.inline.} = 
+proc `!$`*(h: THash): THash {.inline.} =
   ## finishes the computation of the hash value. This is
   ## only needed if you need to implement a hash proc for a new datatype.
   result = h +% h shl 3
   result = result xor (result shr 11)
   result = result +% result shl 15
 
-proc hashData*(data: pointer, size: int): THash = 
+proc hashData*(data: pointer, size: int): THash =
   ## hashes an array of bytes of size `size`
   var h: THash = 0
   when defined(js):
@@ -69,7 +69,7 @@ proc hashData*(data: pointer, size: int): THash =
     var p = cast[cstring](data)
   var i = 0
   var s = size
-  while s > 0: 
+  while s > 0:
     h = h !& ord(p[i])
     inc(i)
     dec(s)
@@ -78,7 +78,7 @@ proc hashData*(data: pointer, size: int): THash =
 when defined(js):
   var objectID = 0
 
-proc hash*(x: pointer): THash {.inline.} = 
+proc hash*(x: pointer): THash {.inline.} =
   ## efficient hashing of pointers
   when defined(js):
     asm """
@@ -93,7 +93,7 @@ proc hash*(x: pointer): THash {.inline.} =
     """
   else:
     result = (cast[THash](x)) shr 3 # skip the alignment
-  
+
 when not defined(booting):
   proc hash*[T: proc](x: T): THash {.inline.} =
     ## efficient hashing of proc vars; closures are supported too.
@@ -101,58 +101,65 @@ when not defined(booting):
       result = hash(rawProc(x)) !& hash(rawEnv(x))
     else:
       result = hash(pointer(x))
-  
-proc hash*(x: int): THash {.inline.} = 
+
+proc hash*(x: int): THash {.inline.} =
   ## efficient hashing of integers
   result = x
 
-proc hash*(x: int64): THash {.inline.} = 
+proc hash*(x: int64): THash {.inline.} =
   ## efficient hashing of integers
   result = toU32(x)
 
-proc hash*(x: char): THash {.inline.} = 
+proc hash*(x: char): THash {.inline.} =
   ## efficient hashing of characters
   result = ord(x)
 
-proc hash*(x: string): THash = 
+proc hash*(x: string): THash =
   ## efficient hashing of strings
   var h: THash = 0
-  for i in 0..x.len-1: 
+  for i in 0..x.len-1:
     h = h !& ord(x[i])
   result = !$h
-  
-proc hashIgnoreStyle*(x: string): THash = 
+
+proc hashIgnoreStyle*(x: string): THash =
   ## efficient hashing of strings; style is ignored
   var h: THash = 0
-  for i in 0..x.len-1: 
+  for i in 0..x.len-1:
     var c = x[i]
-    if c == '_': 
+    if c == '_':
       continue                # skip _
-    if c in {'A'..'Z'}: 
+    if c in {'A'..'Z'}:
       c = chr(ord(c) + (ord('a') - ord('A'))) # toLower()
     h = h !& ord(c)
   result = !$h
 
-proc hashIgnoreCase*(x: string): THash = 
+proc hashIgnoreCase*(x: string): THash =
   ## efficient hashing of strings; case is ignored
   var h: THash = 0
-  for i in 0..x.len-1: 
+  for i in 0..x.len-1:
     var c = x[i]
-    if c in {'A'..'Z'}: 
+    if c in {'A'..'Z'}:
       c = chr(ord(c) + (ord('a') - ord('A'))) # toLower()
     h = h !& ord(c)
   result = !$h
-  
-proc hash*[T: tuple](x: T): THash = 
-  ## efficient hashing of tuples.
-  for f in fields(x):
-    result = result !& hash(f)
-  result = !$result
 
 proc hash*(x: float): THash {.inline.} =
   var y = x + 1.0
   result = cast[ptr THash](addr(y))[]
 
+
+# Forward declarations before methods that hash containers. This allows
+# containers to contain other containers
+proc hash*[A](x: openArray[A]): THash
+proc hash*[A](x: set[A]): THash
+
+
+proc hash*[T: tuple](x: T): THash =
+  ## efficient hashing of tuples.
+  for f in fields(x):
+    result = result !& hash(f)
+  result = !$result
+
 proc hash*[A](x: openArray[A]): THash =
   for it in items(x): result = result !& hash(it)
   result = !$result
@@ -160,3 +167,4 @@ proc hash*[A](x: openArray[A]): THash =
 proc hash*[A](x: set[A]): THash =
   for it in items(x): result = result !& hash(it)
   result = !$result
+
diff --git a/lib/pure/htmlgen.nim b/lib/pure/htmlgen.nim
index d712e53f3..e6c15371e 100644
--- a/lib/pure/htmlgen.nim
+++ b/lib/pure/htmlgen.nim
@@ -483,7 +483,8 @@ macro `var`*(e: expr): expr {.immediate.} =
   result = xmlCheckedTag(e, "var", commonAttr)
 
 when isMainModule:
-  var nim = "Nim"
-  echo h1(a(href="http://nim-lang.org", nim))
-  echo form(action="test", `accept-charset` = "Content-Type")
-
+  let nim = "Nim"
+  assert h1(a(href="http://nim-lang.org", nim)) ==
+    """<h1><a href="http://nim-lang.org">Nim</a></h1>"""
+  assert form(action="test", `accept-charset` = "Content-Type") ==
+    """<form action="test" accept-charset="Content-Type"></form>"""
diff --git a/lib/pure/htmlparser.nim b/lib/pure/htmlparser.nim
index 5e4eba4e5..9719181b8 100644
--- a/lib/pure/htmlparser.nim
+++ b/lib/pure/htmlparser.nim
@@ -593,7 +593,7 @@ proc loadHtml*(path: string): XmlNode =
   var errors: seq[string] = @[]
   result = loadHtml(path, errors)
 
-when isMainModule:
+when not defined(testing) and isMainModule:
   import os
 
   var errors: seq[string] = @[]  
diff --git a/lib/pure/httpclient.nim b/lib/pure/httpclient.nim
index 4c2580da0..e083d44ea 100644
--- a/lib/pure/httpclient.nim
+++ b/lib/pure/httpclient.nim
@@ -64,7 +64,7 @@
 ## ========
 ## Currently all functions support an optional timeout, by default the timeout is set to
 ## `-1` which means that the function will never time out. The timeout is
-## measured in miliseconds, once it is set any call on a socket which may
+## measured in milliseconds, once it is set any call on a socket which may
 ## block will be susceptible to this timeout, however please remember that the
 ## function as a whole can take longer than the specified timeout, only
 ## individual internal calls on the socket are affected. In practice this means
@@ -386,7 +386,7 @@ proc request*(url: string, httpMethod: string, extraHeaders = "",
   ## | Requests ``url`` with the custom method string specified by the
   ## | ``httpMethod`` parameter.
   ## | Extra headers can be specified and must be separated by ``\c\L``
-  ## | An optional timeout can be specified in miliseconds, if reading from the
+  ## | An optional timeout can be specified in milliseconds, if reading from the
   ## server takes longer than specified an ETimeout exception will be raised.
   var r = if proxy == nil: parseUri(url) else: proxy.url
   var headers = substr(httpMethod, len("http"))
@@ -440,7 +440,7 @@ proc request*(url: string, httpMethod = httpGET, extraHeaders = "",
               userAgent = defUserAgent, proxy: Proxy = nil): Response =
   ## | Requests ``url`` with the specified ``httpMethod``.
   ## | Extra headers can be specified and must be separated by ``\c\L``
-  ## | An optional timeout can be specified in miliseconds, if reading from the
+  ## | An optional timeout can be specified in milliseconds, if reading from the
   ## server takes longer than specified an ETimeout exception will be raised.
   result = request(url, $httpMethod, extraHeaders, body, sslContext, timeout,
                    userAgent, proxy)
@@ -467,7 +467,7 @@ proc get*(url: string, extraHeaders = "", maxRedirects = 5,
   ## | GETs the ``url`` and returns a ``Response`` object
   ## | This proc also handles redirection
   ## | Extra headers can be specified and must be separated by ``\c\L``.
-  ## | An optional timeout can be specified in miliseconds, if reading from the
+  ## | An optional timeout can be specified in milliseconds, if reading from the
   ## server takes longer than specified an ETimeout exception will be raised.
   result = request(url, httpGET, extraHeaders, "", sslContext, timeout,
                    userAgent, proxy)
@@ -486,7 +486,7 @@ proc getContent*(url: string, extraHeaders = "", maxRedirects = 5,
   ## | GETs the body and returns it as a string.
   ## | Raises exceptions for the status codes ``4xx`` and ``5xx``
   ## | Extra headers can be specified and must be separated by ``\c\L``.
-  ## | An optional timeout can be specified in miliseconds, if reading from the
+  ## | An optional timeout can be specified in milliseconds, if reading from the
   ## server takes longer than specified an ETimeout exception will be raised.
   var r = get(url, extraHeaders, maxRedirects, sslContext, timeout, userAgent,
               proxy)
@@ -505,7 +505,7 @@ proc post*(url: string, extraHeaders = "", body = "",
   ## | This proc adds the necessary Content-Length header.
   ## | This proc also handles redirection.
   ## | Extra headers can be specified and must be separated by ``\c\L``.
-  ## | An optional timeout can be specified in miliseconds, if reading from the
+  ## | An optional timeout can be specified in milliseconds, if reading from the
   ## server takes longer than specified an ETimeout exception will be raised.
   ## | The optional ``multipart`` parameter can be used to create
   ## ``multipart/form-data`` POSTs comfortably.
@@ -542,7 +542,7 @@ proc postContent*(url: string, extraHeaders = "", body = "",
   ## | POSTs ``body`` to ``url`` and returns the response's body as a string
   ## | Raises exceptions for the status codes ``4xx`` and ``5xx``
   ## | Extra headers can be specified and must be separated by ``\c\L``.
-  ## | An optional timeout can be specified in miliseconds, if reading from the
+  ## | An optional timeout can be specified in milliseconds, if reading from the
   ## server takes longer than specified an ETimeout exception will be raised.
   ## | The optional ``multipart`` parameter can be used to create
   ## ``multipart/form-data`` POSTs comfortably.
@@ -558,7 +558,7 @@ proc downloadFile*(url: string, outputFilename: string,
                    timeout = -1, userAgent = defUserAgent,
                    proxy: Proxy = nil) =
   ## | Downloads ``url`` and saves it to ``outputFilename``
-  ## | An optional timeout can be specified in miliseconds, if reading from the
+  ## | An optional timeout can be specified in milliseconds, if reading from the
   ## server takes longer than specified an ETimeout exception will be raised.
   var f: File
   if open(f, outputFilename, fmWrite):
@@ -819,7 +819,7 @@ proc get*(client: AsyncHttpClient, url: string): Future[Response] {.async.} =
       result = await client.request(redirectTo, httpGET)
       lastUrl = redirectTo
 
-when isMainModule:
+when not defined(testing) and isMainModule:
   when true:
     # Async
     proc main() {.async.} =
diff --git a/lib/pure/httpserver.nim b/lib/pure/httpserver.nim
index 5efdbe297..dc76c9228 100644
--- a/lib/pure/httpserver.nim
+++ b/lib/pure/httpserver.nim
@@ -514,7 +514,7 @@ proc close*(h: PAsyncHTTPServer) =
   ## Closes the ``PAsyncHTTPServer``.
   h.asyncSocket.close()
 
-when isMainModule:
+when not defined(testing) and isMainModule:
   var counter = 0
 
   var s: TServer
diff --git a/lib/pure/json.nim b/lib/pure/json.nim
index 1617402c9..518572be3 100644
--- a/lib/pure/json.nim
+++ b/lib/pure/json.nim
@@ -761,7 +761,7 @@ proc len*(n: JsonNode): int =
   of JObject: result = n.fields.len
   else: discard
 
-proc `[]`*(node: JsonNode, name: string): JsonNode =
+proc `[]`*(node: JsonNode, name: string): JsonNode {.inline.} =
   ## Gets a field from a `JObject`, which must not be nil.
   ## If the value at `name` does not exist, returns nil
   assert(not isNil(node))
@@ -771,7 +771,7 @@ proc `[]`*(node: JsonNode, name: string): JsonNode =
       return item
   return nil
 
-proc `[]`*(node: JsonNode, index: int): JsonNode =
+proc `[]`*(node: JsonNode, index: int): JsonNode {.inline.} =
   ## Gets the node at `index` in an Array. Result is undefined if `index`
   ## is out of bounds
   assert(not isNil(node))
@@ -799,7 +799,7 @@ proc add*(obj: JsonNode, key: string, val: JsonNode) =
   assert obj.kind == JObject
   obj.fields.add((key, val))
 
-proc `[]=`*(obj: JsonNode, key: string, val: JsonNode) =
+proc `[]=`*(obj: JsonNode, key: string, val: JsonNode) {.inline.} =
   ## Sets a field from a `JObject`. Performs a check for duplicate keys.
   assert(obj.kind == JObject)
   for i in 0..obj.fields.len-1:
@@ -808,22 +808,25 @@ proc `[]=`*(obj: JsonNode, key: string, val: JsonNode) =
       return
   obj.fields.add((key, val))
 
-proc `{}`*(node: JsonNode, key: string): JsonNode =
-  ## Transverses the node and gets the given value. If any of the
-  ## names does not exist, returns nil
+proc `{}`*(node: JsonNode, keys: varargs[string]): JsonNode =
+  ## Traverses the node and gets the given value. If any of the
+  ## keys do not exist, returns nil. Also returns nil if one of the
+  ## intermediate data structures is not an object
   result = node
-  if isNil(node): return nil
-  result = result[key]
-
-proc `{}=`*(node: JsonNode, names: varargs[string], value: JsonNode) =
-  ## Transverses the node and tries to set the value at the given location
-  ## to `value` If any of the names are missing, they are added
+  for key in keys:
+    if isNil(result) or result.kind!=JObject:
+      return nil
+    result=result[key]
+
+proc `{}=`*(node: JsonNode, keys: varargs[string], value: JsonNode) =
+  ## Traverses the node and tries to set the value at the given location
+  ## to `value` If any of the keys are missing, they are added
   var node = node
-  for i in 0..(names.len-2):
-    if isNil(node[names[i]]):
-      node[names[i]] = newJObject()
-    node = node[names[i]]
-  node[names[names.len-1]] = value
+  for i in 0..(keys.len-2):
+    if isNil(node[keys[i]]):
+      node[keys[i]] = newJObject()
+    node = node[keys[i]]
+  node[keys[keys.len-1]] = value
 
 proc delete*(obj: JsonNode, key: string) =
   ## Deletes ``obj[key]`` preserving the order of the other (key, value)-pairs.
@@ -946,10 +949,46 @@ proc pretty*(node: JsonNode, indent = 2): string =
   result = ""
   toPretty(result, node, indent)
 
+proc toUgly*(result: var string, node: JsonNode) =
+  ## Converts `node` to its JSON Representation, without
+  ## regard for human readability. Meant to improve ``$`` string
+  ## conversion performance.
+  ##
+  ## This provides higher efficiency than the ``toPretty`` procedure as it
+  ## does **not** attempt to format the resulting JSON to make it human readable.
+  var comma = false
+  case node.kind:
+  of JArray:
+    result.add "["
+    for child in node.elems:
+      if comma: result.add ","
+      else:     comma = true
+      result.toUgly child
+    result.add "]"
+  of JObject:
+    result.add "{"
+    for key, value in items(node.fields):
+      if comma: result.add ","
+      else:     comma = true
+      result.add key.escapeJson()
+      result.add ":"
+      result.toUgly value
+    result.add "}"
+  of JString:
+    result.add node.str.escapeJson()
+  of JInt:
+    result.add($node.num)
+  of JFloat:
+    result.add($node.fnum)
+  of JBool:
+    result.add(if node.bval: "true" else: "false")
+  of JNull:
+    result.add "null"
+
 proc `$`*(node: JsonNode): string =
   ## Converts `node` to its JSON Representation on one line.
-  result = ""
-  toPretty(result, node, 0, false)
+  result = newStringOfCap(node.len shl 1)
+  toUgly(result, node)
 
 iterator items*(node: JsonNode): JsonNode =
   ## Iterator for the items of `node`. `node` has to be a JArray.
@@ -1150,19 +1189,22 @@ when false:
 when isMainModule:
   #var node = parse("{ \"test\": null }")
   #echo(node.existsKey("test56"))
+
   var parsed = parseFile("tests/testdata/jsontest.json")
   var parsed2 = parseFile("tests/testdata/jsontest2.json")
-  echo(parsed)
-  echo()
-  echo(pretty(parsed, 2))
-  echo()
-  echo(parsed["keyÄÖöoßß"])
-  echo()
-  echo(pretty(parsed2))
-  try:
-    echo(parsed["key2"][12123])
-    raise newException(ValueError, "That line was expected to fail")
-  except IndexError: echo()
+
+  when not defined(testing):
+    echo(parsed)
+    echo()
+    echo(pretty(parsed, 2))
+    echo()
+    echo(parsed["keyÄÖöoßß"])
+    echo()
+    echo(pretty(parsed2))
+    try:
+      echo(parsed["key2"][12123])
+      raise newException(ValueError, "That line was expected to fail")
+    except IndexError: echo()
 
   let testJson = parseJson"""{ "a": [1, 2, 3, 4], "b": "asd" }"""
   # nil passthrough
@@ -1170,6 +1212,11 @@ when isMainModule:
   testJson{["c", "d"]} = %true
   assert(testJson["c"]["d"].bval)
 
+  # test `$`
+  let stringified = $testJson
+  let parsedAgain = parseJson(stringified)
+  assert(parsedAgain["b"].str == "asd")
+
   # Bounds checking
   try:
     let a = testJson["a"][9]
@@ -1186,6 +1233,14 @@ when isMainModule:
   except:
     assert(false, "EInvalidIndex thrown for valid index")
 
+  assert(testJson{"b"}.str=="asd", "Couldn't fetch a singly nested key with {}")
+  assert(isNil(testJson{"nonexistent"}), "Non-existent keys should return nil")
+  assert(parsed2{"repository", "description"}.str=="IRC Library for Haskell", "Couldn't fetch via multiply nested key using {}")
+  assert(isNil(testJson{"a", "b"}), "Indexing through a list should return nil")
+  assert(isNil(testJson{"a", "b"}), "Indexing through a list should return nil")
+  assert(testJson{"a"}==parseJson"[1, 2, 3, 4]", "Didn't return a non-JObject when there was one to be found")
+  assert(isNil(parseJson("[1, 2, 3]"){"foo"}), "Indexing directly into a list should return nil")
+
   # Generator:
   var j = %* [{"name": "John", "age": 30}, {"name": "Susan", "age": 31}]
   assert j == %[%{"name": %"John", "age": %30}, %{"name": %"Susan", "age": %31}]
@@ -1217,11 +1272,12 @@ when isMainModule:
     ]
   assert j3 == %[%{"name": %"John", "age": %30}, %{"name": %"Susan", "age": %31}]
 
-  discard """
-  while true:
-    var json = stdin.readLine()
-    var node = parse(json)
-    echo(node)
-    echo()
-    echo()
-  """
+  when not defined(testing):
+    discard """
+    while true:
+      var json = stdin.readLine()
+      var node = parse(json)
+      echo(node)
+      echo()
+      echo()
+    """
diff --git a/lib/pure/logging.nim b/lib/pure/logging.nim
index ca674af4b..a2ea53472 100644
--- a/lib/pure/logging.nim
+++ b/lib/pure/logging.nim
@@ -278,7 +278,7 @@ proc getLogFilter*(): Level =
 
 # --------------
 
-when isMainModule:
+when not defined(testing) and isMainModule:
   var L = newConsoleLogger()
   var fL = newFileLogger("test.log", fmtStr = verboseFmtStr)
   var rL = newRollingFileLogger("rolling.log", fmtStr = verboseFmtStr)
diff --git a/lib/pure/marshal.nim b/lib/pure/marshal.nim
index b63c334ff..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 isMainModule:
+
+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 isMainModule:
         help: string
       else:
         nil
-        
+
     PNode = ref TNode
     TNode = object
       next, prev: PNode
@@ -294,7 +305,7 @@ when 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 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 aa64933fb..a9e9010f6 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))
 
@@ -347,6 +352,9 @@ proc `^`*[T](x, y: T): T =
 
 proc gcd*[T](x, y: T): T =
   ## Computes the greatest common divisor of ``x`` and ``y``.
+  ## Note that for floats, the result cannot always be interpreted as
+  ## "greatest decimal `z` such that ``z*N == x and z*M == y``
+  ## where N and M are positive integers."
   var (x,y) = (x,y)
   while y != 0:
     x = x mod y
@@ -372,7 +380,9 @@ when isMainModule and not defined(JS):
   randomize(seed)
   for i in 0..SIZE-1:
     assert buf[i] == random(high(int)), "non deterministic random seeding"
-  echo "random values equal after reseeding"
+
+  when not defined(testing):
+    echo "random values equal after reseeding"
 
   # Check for no side effect annotation
   proc mySqrt(num: float): float {.noSideEffect.} =
diff --git a/lib/pure/mersenne.nim b/lib/pure/mersenne.nim
index a6a781cb8..74112e304 100644
--- a/lib/pure/mersenne.nim
+++ b/lib/pure/mersenne.nim
@@ -32,7 +32,7 @@ proc getNum*(m: var MersenneTwister): int =
   return int(y)
 
 # Test
-when isMainModule:
+when not defined(testing) and isMainModule:
   var mt = newMersenneTwister(2525)
 
   for i in 0..99:
diff --git a/lib/pure/mimetypes.nim b/lib/pure/mimetypes.nim
index a52ba4ebe..642419e64 100644
--- a/lib/pure/mimetypes.nim
+++ b/lib/pure/mimetypes.nim
@@ -518,5 +518,5 @@ proc register*(mimedb: var MimeDB, ext: string, mimetype: string) =
 
 when isMainModule:
   var m = newMimetypes()
-  echo m.getMimetype("mp4")
-  echo m.getExt("text/html")
+  assert m.getMimetype("mp4") == "video/mp4"
+  assert m.getExt("text/html") == "html"
diff --git a/lib/pure/net.nim b/lib/pure/net.nim
index ffbc6e320..cf37c271e 100644
--- a/lib/pure/net.nim
+++ b/lib/pure/net.nim
@@ -704,7 +704,7 @@ proc waitFor(socket: Socket, waited: var float, timeout, size: int,
 
 proc recv*(socket: Socket, data: pointer, size: int, timeout: int): int {.
   tags: [ReadIOEffect, TimeEffect].} =
-  ## overload with a ``timeout`` parameter in miliseconds.
+  ## overload with a ``timeout`` parameter in milliseconds.
   var waited = 0.0 # number of seconds already waited  
   
   var read = 0
@@ -729,7 +729,7 @@ proc recv*(socket: Socket, data: var string, size: int, timeout = -1,
   ## This function will throw an EOS exception when an error occurs. A value
   ## lower than 0 is never returned.
   ##
-  ## A timeout may be specified in miliseconds, if enough data is not received
+  ## A timeout may be specified in milliseconds, if enough data is not received
   ## within the time specified an ETimeout exception will be raised.
   ##
   ## **Note**: ``data`` must be initialised.
@@ -777,7 +777,7 @@ proc readLine*(socket: Socket, line: var TaintedString, timeout = -1,
   ##
   ## An EOS exception will be raised in the case of a socket error.
   ##
-  ## A timeout can be specified in miliseconds, if data is not received within
+  ## A timeout can be specified in milliseconds, if data is not received within
   ## the specified time an ETimeout exception will be raised.
   ##
   ## **Warning**: Only the ``SafeDisconn`` flag is currently supported.
@@ -844,7 +844,7 @@ proc recvFrom*(socket: Socket, data: var string, length: int,
 proc skip*(socket: Socket, size: int, timeout = -1) =
   ## Skips ``size`` amount of bytes.
   ##
-  ## An optional timeout can be specified in miliseconds, if skipping the
+  ## An optional timeout can be specified in milliseconds, if skipping the
   ## bytes takes longer than specified an ETimeout exception will be raised.
   ##
   ## Returns the number of skipped bytes.
@@ -967,7 +967,7 @@ proc connect*(socket: Socket, address: string, port = Port(0), timeout: int,
              af: Domain = AF_INET) {.tags: [ReadIOEffect, WriteIOEffect].} =
   ## Connects to server as specified by ``address`` on port specified by ``port``.
   ##
-  ## The ``timeout`` paremeter specifies the time in miliseconds to allow for
+  ## The ``timeout`` paremeter specifies the time in milliseconds to allow for
   ## the connection to the server to be made.
   socket.fd.setBlocking(false)
   
diff --git a/lib/pure/oids.nim b/lib/pure/oids.nim
index 0dc8e3c15..ac90dd16b 100644
--- a/lib/pure/oids.nim
+++ b/lib/pure/oids.nim
@@ -88,6 +88,6 @@ proc generatedTime*(oid: Oid): Time =
   bigEndian32(addr(tmp), addr(dummy))
   result = Time(tmp)
 
-when isMainModule:
+when not defined(testing) and isMainModule:
   let xo = genOid()
   echo xo.generatedTime
diff --git a/lib/pure/os.nim b/lib/pure/os.nim
index f53abe81d..3a5bcbfa1 100644
--- a/lib/pure/os.nim
+++ b/lib/pure/os.nim
@@ -2033,10 +2033,10 @@ proc getFileInfo*(path: string, followSymlink = true): FileInfo =
   else:
     var rawInfo: TStat
     if followSymlink:
-      if lstat(path, rawInfo) < 0'i32:
+      if stat(path, rawInfo) < 0'i32:
         raiseOSError(osLastError())
     else:
-      if stat(path, rawInfo) < 0'i32:
+      if lstat(path, rawInfo) < 0'i32:
         raiseOSError(osLastError())
     rawToFormalFileInfo(rawInfo, result)
 
diff --git a/lib/pure/osproc.nim b/lib/pure/osproc.nim
index eb7ad64bb..dc6f21174 100644
--- a/lib/pure/osproc.nim
+++ b/lib/pure/osproc.nim
@@ -174,7 +174,7 @@ proc terminate*(p: Process) {.rtl, extern: "nosp$1", tags: [].}
 proc kill*(p: Process) {.rtl, extern: "nosp$1", tags: [].}
   ## Kill the process `p`. On Posix OSes the procedure sends ``SIGKILL`` to
   ## the process. On Windows ``kill()`` is simply an alias for ``terminate()``.
-  
+
 proc running*(p: Process): bool {.rtl, extern: "nosp$1", tags: [].}
   ## Returns true iff the process `p` is still running. Returns immediately.
 
@@ -195,43 +195,43 @@ proc peekExitCode*(p: Process): int {.tags: [].}
 proc inputStream*(p: Process): Stream {.rtl, extern: "nosp$1", tags: [].}
   ## returns ``p``'s input stream for writing to.
   ##
-  ## **Warning**: The returned `PStream` should not be closed manually as it
-  ## is closed when closing the PProcess ``p``.
+  ## **Warning**: The returned `Stream` should not be closed manually as it
+  ## is closed when closing the Process ``p``.
 
 proc outputStream*(p: Process): Stream {.rtl, extern: "nosp$1", tags: [].}
   ## returns ``p``'s output stream for reading from.
   ##
-  ## **Warning**: The returned `PStream` should not be closed manually as it
-  ## is closed when closing the PProcess ``p``.
+  ## **Warning**: The returned `Stream` should not be closed manually as it
+  ## is closed when closing the Process ``p``.
 
 proc errorStream*(p: Process): Stream {.rtl, extern: "nosp$1", tags: [].}
   ## returns ``p``'s error stream for reading from.
   ##
-  ## **Warning**: The returned `PStream` should not be closed manually as it
-  ## is closed when closing the PProcess ``p``.
+  ## **Warning**: The returned `Stream` should not be closed manually as it
+  ## is closed when closing the Process ``p``.
 
 proc inputHandle*(p: Process): FileHandle {.rtl, extern: "nosp$1",
   tags: [].} =
   ## returns ``p``'s input file handle for writing to.
   ##
-  ## **Warning**: The returned `TFileHandle` should not be closed manually as
-  ## it is closed when closing the PProcess ``p``.
+  ## **Warning**: The returned `FileHandle` should not be closed manually as
+  ## it is closed when closing the Process ``p``.
   result = p.inHandle
 
 proc outputHandle*(p: Process): FileHandle {.rtl, extern: "nosp$1",
   tags: [].} =
   ## returns ``p``'s output file handle for reading from.
   ##
-  ## **Warning**: The returned `TFileHandle` should not be closed manually as
-  ## it is closed when closing the PProcess ``p``.
+  ## **Warning**: The returned `FileHandle` should not be closed manually as
+  ## it is closed when closing the Process ``p``.
   result = p.outHandle
 
 proc errorHandle*(p: Process): FileHandle {.rtl, extern: "nosp$1",
   tags: [].} =
   ## returns ``p``'s error file handle for reading from.
   ##
-  ## **Warning**: The returned `TFileHandle` should not be closed manually as
-  ## it is closed when closing the PProcess ``p``.
+  ## **Warning**: The returned `FileHandle` should not be closed manually as
+  ## it is closed when closing the Process ``p``.
   result = p.errHandle
 
 proc countProcessors*(): int {.rtl, extern: "nosp$1".} =
@@ -303,7 +303,7 @@ proc execProcesses*(cmds: openArray[string],
       close(p)
 
 proc select*(readfds: var seq[Process], timeout = 500): int
-  ## `select` with a sensible Nim interface. `timeout` is in miliseconds.
+  ## `select` with a sensible Nim interface. `timeout` is in milliseconds.
   ## Specify -1 for no timeout. Returns the number of processes that are
   ## ready to read from. The processes that are ready to be read from are
   ## removed from `readfds`.
@@ -666,7 +666,7 @@ elif not defined(useNimRtl):
     data.workingDir = workingDir
 
 
-    when declared(posix_spawn) and not defined(useFork) and 
+    when declared(posix_spawn) and not defined(useFork) and
         not defined(useClone) and not defined(linux):
       pid = startProcessAuxSpawn(data)
     else:
@@ -823,7 +823,7 @@ elif not defined(useNimRtl):
         discard execvp(data.sysCommand, data.sysArgs)
       else:
         when defined(uClibc):
-          # uClibc environment (OpenWrt included) doesn't have the full execvpe 
+          # uClibc environment (OpenWrt included) doesn't have the full execvpe
           discard execve(data.sysCommand, data.sysArgs, data.sysEnv)
         else:
           discard execvpe(data.sysCommand, data.sysArgs, data.sysEnv)
@@ -864,9 +864,9 @@ elif not defined(useNimRtl):
       raiseOsError(osLastError())
 
   proc kill(p: Process) =
-    if kill(p.id, SIGKILL) != 0'i32: 
+    if kill(p.id, SIGKILL) != 0'i32:
       raiseOsError(osLastError())
-    
+
   proc waitForExit(p: Process, timeout: int = -1): int =
     #if waitPid(p.id, p.exitCode, 0) == int(p.id):
     # ``waitPid`` fails if the process is not running anymore. But then
@@ -883,7 +883,7 @@ elif not defined(useNimRtl):
     var ret = waitpid(p.id, p.exitCode, WNOHANG)
     var b = ret == int(p.id)
     if b: result = -1
-    if p.exitCode == -3: result = -1
+    if not WIFEXITED(p.exitCode): result = -1
     else: result = p.exitCode.int shr 8
 
   proc createStream(stream: var Stream, handle: var FileHandle,
@@ -907,7 +907,7 @@ elif not defined(useNimRtl):
       createStream(p.errStream, p.errHandle, fmRead)
     return p.errStream
 
-  proc csystem(cmd: cstring): cint {.nodecl, importc: "system", 
+  proc csystem(cmd: cstring): cint {.nodecl, importc: "system",
                                      header: "<stdlib.h>".}
 
   proc execCmd(command: string): int =
diff --git a/lib/pure/parsecsv.nim b/lib/pure/parsecsv.nim
index f4943ed89..117d75cfa 100644
--- a/lib/pure/parsecsv.nim
+++ b/lib/pure/parsecsv.nim
@@ -166,7 +166,7 @@ proc close*(my: var CsvParser) {.inline.} =
   ## closes the parser `my` and its associated input stream.
   lexbase.close(my)
 
-when isMainModule:
+when not defined(testing) and isMainModule:
   import os
   var s = newFileStream(paramStr(1), fmRead)
   if s == nil: quit("cannot open the file" & paramStr(1))
diff --git a/lib/pure/parsesql.nim b/lib/pure/parsesql.nim
index bb4ede779..91917b1c5 100644
--- a/lib/pure/parsesql.nim
+++ b/lib/pure/parsesql.nim
@@ -1330,7 +1330,7 @@ proc renderSQL*(n: SqlNode): string =
   result = ""
   ra(n, result, 0)
 
-when isMainModule:
+when not defined(testing) and isMainModule:
   echo(renderSQL(parseSQL(newStringStream("""
       CREATE TYPE happiness AS ENUM ('happy', 'very happy', 'ecstatic');
       CREATE TABLE holidays (
diff --git a/lib/pure/parseutils.nim b/lib/pure/parseutils.nim
index eb649a878..c07b713de 100644
--- a/lib/pure/parseutils.nim
+++ b/lib/pure/parseutils.nim
@@ -323,8 +323,12 @@ iterator interpolatedFragments*(s: string): tuple[kind: InterpolatedKind,
     i = j
 
 when isMainModule:
-  for k, v in interpolatedFragments("$test{}  $this is ${an{  example}}  "):
-    echo "(", k, ", \"", v, "\")"
+  import sequtils
+  let input = "$test{}  $this is ${an{  example}}  "
+  let expected = @[(ikVar, "test"), (ikStr, "{}  "), (ikVar, "this"),
+                   (ikStr, " is "), (ikExpr, "an{  example}"), (ikStr, "  ")]
+  assert toSeq(interpolatedFragments(input)) == expected
+
   var value = 0
   discard parseHex("0x38", value)
   assert value == 56
diff --git a/lib/pure/parsexml.nim b/lib/pure/parsexml.nim
index 2663c5b2f..eb792f086 100644
--- a/lib/pure/parsexml.nim
+++ b/lib/pure/parsexml.nim
@@ -628,7 +628,7 @@ proc next*(my: var XmlParser) =
     my.kind = xmlError
     my.state = stateNormal
   
-when isMainModule:
+when not defined(testing) and isMainModule:
   import os
   var s = newFileStream(paramStr(1), fmRead)
   if s == nil: quit("cannot open the file" & paramStr(1))
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/rawsockets.nim b/lib/pure/rawsockets.nim
index a30c23ada..d08c5b769 100644
--- a/lib/pure/rawsockets.nim
+++ b/lib/pure/rawsockets.nim
@@ -392,7 +392,7 @@ proc select*(readfds: var seq[SocketHandle], timeout = 500): int =
   ## Traditional select function. This function will return the number of
   ## sockets that are ready to be read from, written to, or which have errors.
   ## If there are none; 0 is returned. 
-  ## ``Timeout`` is in miliseconds and -1 can be specified for no timeout.
+  ## ``Timeout`` is in milliseconds and -1 can be specified for no timeout.
   ## 
   ## A socket is removed from the specific ``seq`` when it has data waiting to
   ## be read/written to or has errors (``exceptfds``).
@@ -416,7 +416,7 @@ proc selectWrite*(writefds: var seq[SocketHandle],
   ## written to. The sockets which can be written to will also be removed
   ## from ``writefds``.
   ##
-  ## ``timeout`` is specified in miliseconds and ``-1`` can be specified for
+  ## ``timeout`` is specified in milliseconds and ``-1`` can be specified for
   ## an unlimited time.
   var tv {.noInit.}: Timeval = timeValFromMilliseconds(timeout)
   
diff --git a/lib/pure/redis.nim b/lib/pure/redis.nim
index 9177ddee5..aa2e0f9bd 100644
--- a/lib/pure/redis.nim
+++ b/lib/pure/redis.nim
@@ -1080,7 +1080,7 @@ proc assertListsIdentical(listA, listB: seq[string]) =
     assert(item == listB[i])
     i = i + 1
   
-when isMainModule:
+when not defined(testing) and isMainModule:
   when false:
     var r = open()
 
diff --git a/lib/pure/romans.nim b/lib/pure/romans.nim
index 79fb75526..0c182843a 100644
--- a/lib/pure/romans.nim
+++ b/lib/pure/romans.nim
@@ -44,16 +44,13 @@ proc decimalToRoman*(number: range[1..3_999]): string =
     ("XC", 90), ("L", 50), ("XL", 40), ("X", 10), ("IX", 9),
     ("V", 5), ("IV", 4), ("I", 1)]
   result = ""
-  var decVal = number
+  var decVal: int = number
   for key, val in items(romanComposites):
     while decVal >= val:
       dec(decVal, val)
       result.add(key)
 
 when isMainModule:
-  import math
-  randomize()
-  for i in 1 .. 100:
-    var rnd = 1 + random(3990)
-    assert rnd == rnd.decimalToRoman.romanToDecimal
+  for i in 1 .. 3_999:
+    assert i == i.decimalToRoman.romanToDecimal
 
diff --git a/lib/pure/scgi.nim b/lib/pure/scgi.nim
index f3e2b583c..3de422c87 100644
--- a/lib/pure/scgi.nim
+++ b/lib/pure/scgi.nim
@@ -126,7 +126,7 @@ proc close*(s: var ScgiState) =
   s.server.close()
 
 proc next*(s: var ScgiState, timeout: int = -1): bool = 
-  ## proceed to the first/next request. Waits ``timeout`` miliseconds for a
+  ## proceed to the first/next request. Waits ``timeout`` milliseconds for a
   ## request, if ``timeout`` is `-1` then this function will never time out.
   ## Returns `true` if a new request has been processed.
   var rsocks = @[s.server]
diff --git a/lib/pure/selectors.nim b/lib/pure/selectors.nim
index b6bc9dd3a..6901ecf58 100644
--- a/lib/pure/selectors.nim
+++ b/lib/pure/selectors.nim
@@ -296,7 +296,7 @@ proc contains*(s: Selector, key: SelectorKey): bool =
    TReadyInfo: ReadyInfo, PSelector: Selector].}
 
 
-when isMainModule and not defined(nimdoc):
+when not defined(testing) and isMainModule and not defined(nimdoc):
   # Select()
   import sockets
   type
diff --git a/lib/pure/sexp.nim b/lib/pure/sexp.nim
new file mode 100644
index 000000000..3c9fbc150
--- /dev/null
+++ b/lib/pure/sexp.nim
@@ -0,0 +1,697 @@
+#
+#
+#            Nim's Runtime Library
+#        (c) Copyright 2015 Andreas Rumpf, Dominik Picheta
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+import
+  hashes, strutils, lexbase, streams, unicode, macros
+
+type
+  SexpEventKind* = enum  ## enumeration of all events that may occur when parsing
+    sexpError,           ## an error occurred during parsing
+    sexpEof,             ## end of file reached
+    sexpString,          ## a string literal
+    sexpSymbol,          ## a symbol
+    sexpInt,             ## an integer literal
+    sexpFloat,           ## a float literal
+    sexpNil,             ## the value ``nil``
+    sexpDot,             ## the dot to separate car/cdr
+    sexpListStart,       ## start of a list: the ``(`` token
+    sexpListEnd,         ## end of a list: the ``)`` token
+
+  TTokKind = enum        # must be synchronized with SexpEventKind!
+    tkError,
+    tkEof,
+    tkString,
+    tkSymbol,
+    tkInt,
+    tkFloat,
+    tkNil,
+    tkDot,
+    tkParensLe,
+    tkParensRi
+    tkSpace
+
+  SexpError* = enum        ## enumeration that lists all errors that can occur
+    errNone,               ## no error
+    errInvalidToken,       ## invalid token
+    errParensRiExpected,    ## ``)`` expected
+    errQuoteExpected,      ## ``"`` expected
+    errEofExpected,        ## EOF expected
+
+  SexpParser* = object of BaseLexer ## the parser object.
+    a: string
+    tok: TTokKind
+    kind: SexpEventKind
+    err: SexpError
+
+const
+  errorMessages: array [SexpError, string] = [
+    "no error",
+    "invalid token",
+    "')' expected",
+    "'\"' or \"'\" expected",
+    "EOF expected",
+  ]
+  tokToStr: array [TTokKind, string] = [
+    "invalid token",
+    "EOF",
+    "string literal",
+    "symbol",
+    "int literal",
+    "float literal",
+    "nil",
+    ".",
+    "(", ")", "space"
+  ]
+
+proc close*(my: var SexpParser) {.inline.} =
+  ## closes the parser `my` and its associated input stream.
+  lexbase.close(my)
+
+proc str*(my: SexpParser): string {.inline.} =
+  ## returns the character data for the events: ``sexpInt``, ``sexpFloat``,
+  ## ``sexpString``
+  assert(my.kind in {sexpInt, sexpFloat, sexpString})
+  result = my.a
+
+proc getInt*(my: SexpParser): BiggestInt {.inline.} =
+  ## returns the number for the event: ``sexpInt``
+  assert(my.kind == sexpInt)
+  result = parseBiggestInt(my.a)
+
+proc getFloat*(my: SexpParser): float {.inline.} =
+  ## returns the number for the event: ``sexpFloat``
+  assert(my.kind == sexpFloat)
+  result = parseFloat(my.a)
+
+proc kind*(my: SexpParser): SexpEventKind {.inline.} =
+  ## returns the current event type for the SEXP parser
+  result = my.kind
+
+proc getColumn*(my: SexpParser): int {.inline.} =
+  ## get the current column the parser has arrived at.
+  result = getColNumber(my, my.bufpos)
+
+proc getLine*(my: SexpParser): int {.inline.} =
+  ## get the current line the parser has arrived at.
+  result = my.lineNumber
+
+proc errorMsg*(my: SexpParser): string =
+  ## returns a helpful error message for the event ``sexpError``
+  assert(my.kind == sexpError)
+  result = "($1, $2) Error: $3" % [$getLine(my), $getColumn(my), errorMessages[my.err]]
+
+proc errorMsgExpected*(my: SexpParser, e: string): string =
+  ## returns an error message "`e` expected" in the same format as the
+  ## other error messages
+  result = "($1, $2) Error: $3" % [$getLine(my), $getColumn(my), e & " expected"]
+
+proc handleHexChar(c: char, x: var int): bool =
+  result = true # Success
+  case c
+  of '0'..'9': x = (x shl 4) or (ord(c) - ord('0'))
+  of 'a'..'f': x = (x shl 4) or (ord(c) - ord('a') + 10)
+  of 'A'..'F': x = (x shl 4) or (ord(c) - ord('A') + 10)
+  else: result = false # error
+
+proc parseString(my: var SexpParser): TTokKind =
+  result = tkString
+  var pos = my.bufpos + 1
+  var buf = my.buf
+  while true:
+    case buf[pos]
+    of '\0':
+      my.err = errQuoteExpected
+      result = tkError
+      break
+    of '"':
+      inc(pos)
+      break
+    of '\\':
+      case buf[pos+1]
+      of '\\', '"', '\'', '/':
+        add(my.a, buf[pos+1])
+        inc(pos, 2)
+      of 'b':
+        add(my.a, '\b')
+        inc(pos, 2)
+      of 'f':
+        add(my.a, '\f')
+        inc(pos, 2)
+      of 'n':
+        add(my.a, '\L')
+        inc(pos, 2)
+      of 'r':
+        add(my.a, '\C')
+        inc(pos, 2)
+      of 't':
+        add(my.a, '\t')
+        inc(pos, 2)
+      of 'u':
+        inc(pos, 2)
+        var r: int
+        if handleHexChar(buf[pos], r): inc(pos)
+        if handleHexChar(buf[pos], r): inc(pos)
+        if handleHexChar(buf[pos], r): inc(pos)
+        if handleHexChar(buf[pos], r): inc(pos)
+        add(my.a, toUTF8(Rune(r)))
+      else:
+        # don't bother with the error
+        add(my.a, buf[pos])
+        inc(pos)
+    of '\c':
+      pos = lexbase.handleCR(my, pos)
+      buf = my.buf
+      add(my.a, '\c')
+    of '\L':
+      pos = lexbase.handleLF(my, pos)
+      buf = my.buf
+      add(my.a, '\L')
+    else:
+      add(my.a, buf[pos])
+      inc(pos)
+  my.bufpos = pos # store back
+
+proc parseNumber(my: var SexpParser) =
+  var pos = my.bufpos
+  var buf = my.buf
+  if buf[pos] == '-':
+    add(my.a, '-')
+    inc(pos)
+  if buf[pos] == '.':
+    add(my.a, "0.")
+    inc(pos)
+  else:
+    while buf[pos] in Digits:
+      add(my.a, buf[pos])
+      inc(pos)
+    if buf[pos] == '.':
+      add(my.a, '.')
+      inc(pos)
+  # digits after the dot:
+  while buf[pos] in Digits:
+    add(my.a, buf[pos])
+    inc(pos)
+  if buf[pos] in {'E', 'e'}:
+    add(my.a, buf[pos])
+    inc(pos)
+    if buf[pos] in {'+', '-'}:
+      add(my.a, buf[pos])
+      inc(pos)
+    while buf[pos] in Digits:
+      add(my.a, buf[pos])
+      inc(pos)
+  my.bufpos = pos
+
+proc parseSymbol(my: var SexpParser) =
+  var pos = my.bufpos
+  var buf = my.buf
+  if buf[pos] in IdentStartChars:
+    while buf[pos] in IdentChars:
+      add(my.a, buf[pos])
+      inc(pos)
+  my.bufpos = pos
+
+proc getTok(my: var SexpParser): TTokKind =
+  setLen(my.a, 0)
+  case my.buf[my.bufpos]
+  of '-', '0'..'9': # numbers that start with a . are not parsed
+                    # correctly.
+    parseNumber(my)
+    if {'.', 'e', 'E'} in my.a:
+      result = tkFloat
+    else:
+      result = tkInt
+  of '"': #" # gotta fix nim-mode
+    result = parseString(my)
+  of '(':
+    inc(my.bufpos)
+    result = tkParensLe
+  of ')':
+    inc(my.bufpos)
+    result = tkParensRi
+  of '\0':
+    result = tkEof
+  of 'a'..'z', 'A'..'Z', '_':
+    parseSymbol(my)
+    if my.a == "nil":
+      result = tkNil
+    else:
+      result = tkSymbol
+  of ' ':
+    result = tkSpace
+    inc(my.bufpos)
+  of '.':
+    result = tkDot
+    inc(my.bufpos)
+  else:
+    inc(my.bufpos)
+    result = tkError
+  my.tok = result
+
+# ------------- higher level interface ---------------------------------------
+
+type
+  SexpNodeKind* = enum ## possible SEXP node types
+    SNil,
+    SInt,
+    SFloat,
+    SString,
+    SSymbol,
+    SList,
+    SCons
+
+  SexpNode* = ref SexpNodeObj ## SEXP node
+  SexpNodeObj* {.acyclic.} = object
+    case kind*: SexpNodeKind
+    of SString:
+      str*: string
+    of SSymbol:
+      symbol*: string
+    of SInt:
+      num*: BiggestInt
+    of SFloat:
+      fnum*: float
+    of SList:
+      elems*: seq[SexpNode]
+    of SCons:
+      car: SexpNode
+      cdr: SexpNode
+    of SNil:
+      discard
+
+  Cons = tuple[car: SexpNode, cdr: SexpNode]
+
+  SexpParsingError* = object of ValueError ## is raised for a SEXP error
+
+proc raiseParseErr*(p: SexpParser, msg: string) {.noinline, noreturn.} =
+  ## raises an `ESexpParsingError` exception.
+  raise newException(SexpParsingError, errorMsgExpected(p, msg))
+
+proc newSString*(s: string): SexpNode {.procvar.}=
+  ## Creates a new `SString SexpNode`.
+  new(result)
+  result.kind = SString
+  result.str = s
+
+proc newSStringMove(s: string): SexpNode =
+  new(result)
+  result.kind = SString
+  shallowCopy(result.str, s)
+
+proc newSInt*(n: BiggestInt): SexpNode {.procvar.} =
+  ## Creates a new `SInt SexpNode`.
+  new(result)
+  result.kind = SInt
+  result.num  = n
+
+proc newSFloat*(n: float): SexpNode {.procvar.} =
+  ## Creates a new `SFloat SexpNode`.
+  new(result)
+  result.kind = SFloat
+  result.fnum  = n
+
+proc newSNil*(): SexpNode {.procvar.} =
+  ## Creates a new `SNil SexpNode`.
+  new(result)
+
+proc newSCons*(car, cdr: SexpNode): SexpNode {.procvar.} =
+  ## Creates a new `SCons SexpNode`
+  new(result)
+  result.kind = SCons
+  result.car = car
+  result.cdr = cdr
+
+proc newSList*(): SexpNode {.procvar.} =
+  ## Creates a new `SList SexpNode`
+  new(result)
+  result.kind = SList
+  result.elems = @[]
+
+proc newSSymbol*(s: string): SexpNode {.procvar.} =
+  new(result)
+  result.kind = SSymbol
+  result.symbol = s
+
+proc newSSymbolMove(s: string): SexpNode =
+  new(result)
+  result.kind = SSymbol
+  shallowCopy(result.symbol, s)
+
+proc getStr*(n: SexpNode, default: string = ""): string =
+  ## Retrieves the string value of a `SString SexpNode`.
+  ##
+  ## Returns ``default`` if ``n`` is not a ``SString``.
+  if n.kind != SString: return default
+  else: return n.str
+
+proc getNum*(n: SexpNode, default: BiggestInt = 0): BiggestInt =
+  ## Retrieves the int value of a `SInt SexpNode`.
+  ##
+  ## Returns ``default`` if ``n`` is not a ``SInt``.
+  if n.kind != SInt: return default
+  else: return n.num
+
+proc getFNum*(n: SexpNode, default: float = 0.0): float =
+  ## Retrieves the float value of a `SFloat SexpNode`.
+  ##
+  ## Returns ``default`` if ``n`` is not a ``SFloat``.
+  if n.kind != SFloat: return default
+  else: return n.fnum
+
+proc getSymbol*(n: SexpNode, default: string = ""): string =
+  ## Retrieves the int value of a `SList SexpNode`.
+  ##
+  ## Returns ``default`` if ``n`` is not a ``SList``.
+  if n.kind != SSymbol: return default
+  else: return n.symbol
+
+proc getElems*(n: SexpNode, default: seq[SexpNode] = @[]): seq[SexpNode] =
+  ## Retrieves the int value of a `SList SexpNode`.
+  ##
+  ## Returns ``default`` if ``n`` is not a ``SList``.
+  if n.kind == SNil: return @[]
+  elif n.kind != SList: return default
+  else: return n.elems
+
+proc getCons*(n: SexpNode, defaults: Cons = (newSNil(), newSNil())): Cons =
+  ## Retrieves the cons value of a `SList SexpNode`.
+  ##
+  ## Returns ``default`` if ``n`` is not a ``SList``.
+  if n.kind == SCons: return (n.car, n.cdr)
+  elif n.kind == SList: return (n.elems[0], n.elems[1])
+  else: return defaults
+
+proc sexp*(s: string): SexpNode =
+  ## Generic constructor for SEXP data. Creates a new `SString SexpNode`.
+  new(result)
+  result.kind = SString
+  result.str = s
+
+proc sexp*(n: BiggestInt): SexpNode =
+  ## Generic constructor for SEXP data. Creates a new `SInt SexpNode`.
+  new(result)
+  result.kind = SInt
+  result.num  = n
+
+proc sexp*(n: float): SexpNode =
+  ## Generic constructor for SEXP data. Creates a new `SFloat SexpNode`.
+  new(result)
+  result.kind = SFloat
+  result.fnum  = n
+
+proc sexp*(b: bool): SexpNode =
+  ## Generic constructor for SEXP data. Creates a new `SSymbol
+  ## SexpNode` with value t or `SNil SexpNode`.
+  new(result)
+  if b:
+    result.kind = SSymbol
+    result.symbol = "t"
+  else:
+    result.kind = SNil
+
+proc sexp*(elements: openArray[SexpNode]): SexpNode =
+  ## Generic constructor for SEXP data. Creates a new `SList SexpNode`
+  new(result)
+  result.kind = SList
+  newSeq(result.elems, elements.len)
+  for i, p in pairs(elements): result.elems[i] = p
+
+proc sexp*(s: SexpNode): SexpNode =
+  result = s
+
+proc toSexp(x: NimNode): NimNode {.compiletime.} =
+  case x.kind
+  of nnkBracket:
+    result = newNimNode(nnkBracket)
+    for i in 0 .. <x.len:
+      result.add(toSexp(x[i]))
+
+  else:
+    result = x
+
+  result = prefix(result, "sexp")
+
+macro convertSexp*(x: expr): expr =
+  ## Convert an expression to a SexpNode directly, without having to specify
+  ## `%` for every element.
+  result = toSexp(x)
+
+proc `==`* (a,b: SexpNode): bool =
+  ## Check two nodes for equality
+  if a.isNil:
+    if b.isNil: return true
+    return false
+  elif b.isNil or a.kind != b.kind:
+    return false
+  else:
+    return case a.kind
+    of SString:
+      a.str == b.str
+    of SInt:
+      a.num == b.num
+    of SFloat:
+      a.fnum == b.fnum
+    of SNil:
+      true
+    of SList:
+      a.elems == b.elems
+    of SSymbol:
+      a.symbol == b.symbol
+    of SCons:
+      a.car == b.car and a.cdr == b.cdr
+
+proc hash* (n:SexpNode): THash =
+  ## Compute the hash for a SEXP node
+  case n.kind
+  of SList:
+    result = hash(n.elems)
+  of SInt:
+    result = hash(n.num)
+  of SFloat:
+    result = hash(n.fnum)
+  of SString:
+    result = hash(n.str)
+  of SNil:
+    result = hash(0)
+  of SSymbol:
+    result = hash(n.symbol)
+  of SCons:
+    result = hash(n.car) !& hash(n.cdr)
+
+proc len*(n: SexpNode): int =
+  ## If `n` is a `SList`, it returns the number of elements.
+  ## If `n` is a `JObject`, it returns the number of pairs.
+  ## Else it returns 0.
+  case n.kind
+  of SList: result = n.elems.len
+  else: discard
+
+proc `[]`*(node: SexpNode, index: int): SexpNode =
+  ## Gets the node at `index` in a List. Result is undefined if `index`
+  ## is out of bounds
+  assert(not isNil(node))
+  assert(node.kind == SList)
+  return node.elems[index]
+
+proc add*(father, child: SexpNode) =
+  ## Adds `child` to a SList node `father`.
+  assert father.kind == SList
+  father.elems.add(child)
+
+# ------------- pretty printing ----------------------------------------------
+
+proc indent(s: var string, i: int) =
+  s.add(spaces(i))
+
+proc newIndent(curr, indent: int, ml: bool): int =
+  if ml: return curr + indent
+  else: return indent
+
+proc nl(s: var string, ml: bool) =
+  if ml: s.add("\n")
+
+proc escapeJson*(s: string): string =
+  ## Converts a string `s` to its JSON representation.
+  result = newStringOfCap(s.len + s.len shr 3)
+  result.add("\"")
+  for x in runes(s):
+    var r = int(x)
+    if r >= 32 and r <= 127:
+      var c = chr(r)
+      case c
+      of '"': result.add("\\\"") #" # gotta fix nim-mode
+      of '\\': result.add("\\\\")
+      else: result.add(c)
+    else:
+      result.add("\\u")
+      result.add(toHex(r, 4))
+  result.add("\"")
+
+proc copy*(p: SexpNode): SexpNode =
+  ## Performs a deep copy of `a`.
+  case p.kind
+  of SString:
+    result = newSString(p.str)
+  of SInt:
+    result = newSInt(p.num)
+  of SFloat:
+    result = newSFloat(p.fnum)
+  of SNil:
+    result = newSNil()
+  of SSymbol:
+    result = newSSymbol(p.symbol)
+  of SList:
+    result = newSList()
+    for i in items(p.elems):
+      result.elems.add(copy(i))
+  of SCons:
+    result = newSCons(copy(p.car), copy(p.cdr))
+
+proc toPretty(result: var string, node: SexpNode, indent = 2, ml = true,
+              lstArr = false, currIndent = 0) =
+  case node.kind
+  of SString:
+    if lstArr: result.indent(currIndent)
+    result.add(escapeJson(node.str))
+  of SInt:
+    if lstArr: result.indent(currIndent)
+    result.add($node.num)
+  of SFloat:
+    if lstArr: result.indent(currIndent)
+    result.add($node.fnum)
+  of SNil:
+    if lstArr: result.indent(currIndent)
+    result.add("nil")
+  of SSymbol:
+    if lstArr: result.indent(currIndent)
+    result.add($node.symbol)
+  of SList:
+    if lstArr: result.indent(currIndent)
+    if len(node.elems) != 0:
+      result.add("(")
+      result.nl(ml)
+      for i in 0..len(node.elems)-1:
+        if i > 0:
+          result.add(" ")
+          result.nl(ml) # New Line
+        toPretty(result, node.elems[i], indent, ml,
+            true, newIndent(currIndent, indent, ml))
+      result.nl(ml)
+      result.indent(currIndent)
+      result.add(")")
+    else: result.add("nil")
+  of SCons:
+    if lstArr: result.indent(currIndent)
+    result.add("(")
+    toPretty(result, node.car, indent, ml,
+        true, newIndent(currIndent, indent, ml))
+    result.add(" . ")
+    toPretty(result, node.cdr, indent, ml,
+        true, newIndent(currIndent, indent, ml))
+    result.add(")")
+
+proc pretty*(node: SexpNode, indent = 2): string =
+  ## Converts `node` to its Sexp Representation, with indentation and
+  ## on multiple lines.
+  result = ""
+  toPretty(result, node, indent)
+
+proc `$`*(node: SexpNode): string =
+  ## Converts `node` to its SEXP Representation on one line.
+  result = ""
+  toPretty(result, node, 0, false)
+
+iterator items*(node: SexpNode): SexpNode =
+  ## Iterator for the items of `node`. `node` has to be a SList.
+  assert node.kind == SList
+  for i in items(node.elems):
+    yield i
+
+iterator mitems*(node: var SexpNode): var SexpNode =
+  ## Iterator for the items of `node`. `node` has to be a SList. Items can be
+  ## modified.
+  assert node.kind == SList
+  for i in mitems(node.elems):
+    yield i
+
+proc eat(p: var SexpParser, tok: TTokKind) =
+  if p.tok == tok: discard getTok(p)
+  else: raiseParseErr(p, tokToStr[tok])
+
+proc parseSexp(p: var SexpParser): SexpNode =
+  ## Parses SEXP from a SEXP Parser `p`.
+  case p.tok
+  of tkString:
+    # we capture 'p.a' here, so we need to give it a fresh buffer afterwards:
+    result = newSStringMove(p.a)
+    p.a = ""
+    discard getTok(p)
+  of tkInt:
+    result = newSInt(parseBiggestInt(p.a))
+    discard getTok(p)
+  of tkFloat:
+    result = newSFloat(parseFloat(p.a))
+    discard getTok(p)
+  of tkNil:
+    result = newSNil()
+    discard getTok(p)
+  of tkSymbol:
+    result = newSSymbolMove(p.a)
+    p.a = ""
+    discard getTok(p)
+  of tkParensLe:
+    result = newSList()
+    discard getTok(p)
+    while p.tok notin {tkParensRi, tkDot}:
+      result.add(parseSexp(p))
+      if p.tok != tkSpace: break
+      discard getTok(p)
+    if p.tok == tkDot:
+      eat(p, tkDot)
+      eat(p, tkSpace)
+      result.add(parseSexp(p))
+      result = newSCons(result[0], result[1])
+    eat(p, tkParensRi)
+  of tkSpace, tkDot, tkError, tkParensRi, tkEof:
+    raiseParseErr(p, "(")
+
+proc open*(my: var SexpParser, input: Stream) =
+  ## initializes the parser with an input stream.
+  lexbase.open(my, input)
+  my.kind = sexpError
+  my.a = ""
+
+proc parseSexp*(s: Stream): SexpNode =
+  ## Parses from a buffer `s` into a `SexpNode`.
+  var p: SexpParser
+  p.open(s)
+  discard getTok(p) # read first token
+  result = p.parseSexp()
+  p.close()
+
+proc parseSexp*(buffer: string): SexpNode =
+  ## Parses Sexp from `buffer`.
+  result = parseSexp(newStringStream(buffer))
+
+when isMainModule:
+  let testSexp = parseSexp("""(1 (98 2) nil (2) foobar "foo" 9.234)""")
+  assert(testSexp[0].getNum == 1)
+  assert(testSexp[1][0].getNum == 98)
+  assert(testSexp[2].getElems == @[])
+  assert(testSexp[4].getSymbol == "foobar")
+  assert(testSexp[5].getStr == "foo")
+
+  let alist = parseSexp("""((1 . 2) (2 . "foo"))""")
+  assert(alist[0].getCons.car.getNum == 1)
+  assert(alist[0].getCons.cdr.getNum == 2)
+  assert(alist[1].getCons.cdr.getStr == "foo")
+
+  # Generator:
+  var j = convertSexp([true, false, "foobar", [1, 2, "baz"]])
+  assert($j == """(t nil "foobar" (1 2 "baz"))""")
diff --git a/lib/pure/smtp.nim b/lib/pure/smtp.nim
index 81198f9e1..c1bc259a5 100644
--- a/lib/pure/smtp.nim
+++ b/lib/pure/smtp.nim
@@ -253,7 +253,7 @@ proc close*(smtp: AsyncSmtp) {.async.} =
   await smtp.sock.send("QUIT\c\L")
   smtp.sock.close()
 
-when isMainModule:
+when not defined(testing) and isMainModule:
   #var msg = createMessage("Test subject!", 
   #     "Hello, my name is dom96.\n What\'s yours?", @["dominik@localhost"])
   #echo(msg)
diff --git a/lib/pure/sockets.nim b/lib/pure/sockets.nim
index 3afb545c8..64e2cdcd3 100644
--- a/lib/pure/sockets.nim
+++ b/lib/pure/sockets.nim
@@ -986,7 +986,7 @@ proc select*(readfds, writefds, exceptfds: var seq[Socket],
   ## Traditional select function. This function will return the number of
   ## sockets that are ready to be read from, written to, or which have errors.
   ## If there are none; 0 is returned. 
-  ## ``Timeout`` is in miliseconds and -1 can be specified for no timeout.
+  ## ``Timeout`` is in milliseconds and -1 can be specified for no timeout.
   ## 
   ## Sockets which are **not** ready for reading, writing or which don't have
   ## errors waiting on them are removed from the ``readfds``, ``writefds``,
@@ -1040,7 +1040,7 @@ proc selectWrite*(writefds: var seq[Socket],
   ## written to. The sockets which **cannot** be written to will also be removed
   ## from ``writefds``.
   ##
-  ## ``timeout`` is specified in miliseconds and ``-1`` can be specified for
+  ## ``timeout`` is specified in milliseconds and ``-1`` can be specified for
   ## an unlimited time.
   var tv {.noInit.}: Timeval = timeValFromMilliseconds(timeout)
   
@@ -1174,7 +1174,7 @@ proc waitFor(socket: Socket, waited: var float, timeout, size: int,
 
 proc recv*(socket: Socket, data: pointer, size: int, timeout: int): int {.
   tags: [ReadIOEffect, TimeEffect].} =
-  ## overload with a ``timeout`` parameter in miliseconds.
+  ## overload with a ``timeout`` parameter in milliseconds.
   var waited = 0.0 # number of seconds already waited  
   
   var read = 0
@@ -1197,7 +1197,7 @@ proc recv*(socket: Socket, data: var string, size: int, timeout = -1): int =
   ## This function will throw an EOS exception when an error occurs. A value
   ## lower than 0 is never returned.
   ##
-  ## A timeout may be specified in miliseconds, if enough data is not received
+  ## A timeout may be specified in milliseconds, if enough data is not received
   ## within the time specified an ETimeout exception will be raised.
   ##
   ## **Note**: ``data`` must be initialised.
@@ -1258,7 +1258,7 @@ proc recvLine*(socket: Socket, line: var TaintedString, timeout = -1): bool {.
   ## If the socket is disconnected, ``line`` will be set to ``""`` and ``True``
   ## will be returned.
   ##
-  ## A timeout can be specified in miliseconds, if data is not received within
+  ## A timeout can be specified in milliseconds, if data is not received within
   ## the specified time an ETimeout exception will be raised.
   ##
   ## **Deprecated since version 0.9.2**: This function has been deprecated in
@@ -1302,7 +1302,7 @@ proc readLine*(socket: Socket, line: var TaintedString, timeout = -1) {.
   ##
   ## An EOS exception will be raised in the case of a socket error.
   ##
-  ## A timeout can be specified in miliseconds, if data is not received within
+  ## A timeout can be specified in milliseconds, if data is not received within
   ## the specified time an ETimeout exception will be raised.
   
   template addNLIfEmpty(): stmt =
@@ -1433,7 +1433,7 @@ proc recv*(socket: Socket): TaintedString {.tags: [ReadIOEffect], deprecated.} =
 proc recvTimeout*(socket: Socket, timeout: int): TaintedString {.
   tags: [ReadIOEffect], deprecated.} =
   ## overloaded variant to support a ``timeout`` parameter, the ``timeout``
-  ## parameter specifies the amount of miliseconds to wait for data on the
+  ## parameter specifies the amount of milliseconds to wait for data on the
   ## socket.
   ##
   ## **Deprecated since version 0.9.2**: This function is not safe for use.
@@ -1554,7 +1554,7 @@ proc skip*(socket: Socket) {.tags: [ReadIOEffect], deprecated.} =
 proc skip*(socket: Socket, size: int, timeout = -1) =
   ## Skips ``size`` amount of bytes.
   ##
-  ## An optional timeout can be specified in miliseconds, if skipping the
+  ## An optional timeout can be specified in milliseconds, if skipping the
   ## bytes takes longer than specified an ETimeout exception will be raised.
   ##
   ## Returns the number of skipped bytes.
@@ -1708,7 +1708,7 @@ proc connect*(socket: Socket, address: string, port = Port(0), timeout: int,
              af: Domain = AF_INET) {.tags: [ReadIOEffect, WriteIOEffect].} =
   ## Connects to server as specified by ``address`` on port specified by ``port``.
   ##
-  ## The ``timeout`` paremeter specifies the time in miliseconds to allow for
+  ## The ``timeout`` paremeter specifies the time in milliseconds to allow for
   ## the connection to the server to be made.
   let originalStatus = not socket.nonblocking
   socket.setBlocking(false)
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 2678f4fc8..eb4be719a 100644
--- a/lib/pure/strutils.nim
+++ b/lib/pure/strutils.nim
@@ -169,14 +169,12 @@ proc cmpIgnoreStyle*(a, b: string): int {.noSideEffect,
 
 {.pop.}
 
-proc strip*(s: string, leading = true, trailing = true): string {.noSideEffect,
-  rtl, extern: "nsuStrip".} =
-  ## Strips whitespace from `s` and returns the resulting string.
+proc strip*(s: string, leading = true, trailing = true, chars: set[char] = Whitespace): string 
+  {.noSideEffect, rtl, extern: "nsuStrip".} =
+  ## Strips `chars` from `s` and returns the resulting string.
   ##
-  ## If `leading` is true, leading whitespace is stripped.
-  ## If `trailing` is true, trailing whitespace is stripped.
-  const
-    chars: set[char] = Whitespace
+  ## If `leading` is true, leading `chars` are stripped.
+  ## If `trailing` is true, trailing `chars` are stripped.
   var
     first = 0
     last = len(s)-1
@@ -1402,14 +1400,21 @@ when isMainModule:
   doAssert align("a", 0) == "a"
   doAssert align("1232", 6) == "  1232"
   doAssert align("1232", 6, '#') == "##1232"
-  echo wordWrap(""" this is a long text --  muchlongerthan10chars and here
-                   it goes""", 10, false)
+
+  let
+    inp = """ this is a long text --  muchlongerthan10chars and here
+               it goes"""
+    outp = " this is a\nlong text\n--\nmuchlongerthan10chars\nand here\nit goes"
+  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"
-  echo formatSize(1'i64 shl 31 + 300'i64) # == "4,GB"
-  echo formatSize(1'i64 shl 31)
+  when not defined(testing):
+    echo formatSize(1'i64 shl 31 + 300'i64) # == "4,GB"
+    echo formatSize(1'i64 shl 31)
 
   doAssert "$animal eats $food." % ["animal", "The cat", "food", "fish"] ==
            "The cat eats fish."
@@ -1426,3 +1431,11 @@ when isMainModule:
   doAssert count("foofoofoo", "foofoo", overlapping = true) == 2
   doAssert count("foofoofoo", 'f') == 3
   doAssert count("foofoofoobar", {'f','b'}) == 4
+
+  doAssert strip("  foofoofoo  ") == "foofoofoo"
+  doAssert strip("sfoofoofoos", chars = {'s'}) == "foofoofoo"
+  doAssert strip("barfoofoofoobar", chars = {'b', 'a', 'r'}) == "foofoofoo"
+  doAssert strip("stripme but don't strip this stripme",
+                 chars = {'s', 't', 'r', 'i', 'p', 'm', 'e'}) == " but don't strip this "
+  doAssert strip("sfoofoofoos", leading = false, chars = {'s'}) == "sfoofoofoo"
+  doAssert strip("sfoofoofoos", trailing = false, chars = {'s'}) == "foofoofoos"
diff --git a/lib/pure/subexes.nim b/lib/pure/subexes.nim
index d701b85b1..d213c99e6 100644
--- a/lib/pure/subexes.nim
+++ b/lib/pure/subexes.nim
@@ -386,8 +386,13 @@ when isMainModule:
     longishA, 
     longish)"""
   
-  echo "type TMyEnum* = enum\n  $', '2i'\n  '{..}" % ["fieldA", 
-    "fieldB", "FiledClkad", "fieldD", "fieldE", "longishFieldName"]
+  assert "type TMyEnum* = enum\n  $', '2i'\n  '{..}" % ["fieldA",
+    "fieldB", "FiledClkad", "fieldD", "fieldE", "longishFieldName"] ==
+    strutils.unindent """
+      type TMyEnum* = enum
+        fieldA, fieldB, 
+        FiledClkad, fieldD, 
+        fieldE, longishFieldName"""
   
   doAssert subex"$1($', '{2..})" % ["f", "a", "b", "c"] == "f(a, b, c)"
   
@@ -395,7 +400,12 @@ when isMainModule:
   
   doAssert subex"$['''|'|''''|']']#" % "0" == "'|"
   
-  echo subex("type\n  TEnum = enum\n    $', '40c'\n    '{..}") % [
-    "fieldNameA", "fieldNameB", "fieldNameC", "fieldNameD"]
+  assert subex("type\n  TEnum = enum\n    $', '40c'\n    '{..}") % [
+    "fieldNameA", "fieldNameB", "fieldNameC", "fieldNameD"] ==
+    strutils.unindent """
+      type
+        TEnum = enum
+          fieldNameA, fieldNameB, fieldNameC, 
+          fieldNameD"""
   
   
diff --git a/lib/pure/terminal.nim b/lib/pure/terminal.nim
index df637dcb6..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) =
@@ -375,7 +376,7 @@ when not defined(windows):
     result = stdin.readChar()
     discard fd.tcsetattr(TCSADRAIN, addr oldMode)
 
-when isMainModule:
+when not defined(testing) and isMainModule:
   system.addQuitProc(resetAttributes)
   write(stdout, "never mind")
   eraseLine()
diff --git a/lib/pure/times.nim b/lib/pure/times.nim
index 5cc9b4993..b8836c15b 100644
--- a/lib/pure/times.nim
+++ b/lib/pure/times.nim
@@ -119,7 +119,7 @@ type
                               ## in the range 0 to 23.
     monthday*: range[1..31]   ## The day of the month, in the range 1 to 31.
     month*: Month             ## The current month.
-    year*: range[-10_000..10_000] ## The current year.
+    year*: int                ## The current year.
     weekday*: WeekDay         ## The current day of the week.
     yearday*: range[0..365]   ## The number of days since January 1,
                               ## in the range 0 to 365.
@@ -134,7 +134,7 @@ type
   ## everything should be positive or everything negative. Zero is
   ## fine too. Mixed signs will lead to unexpected results.
   TimeInterval* = object ## a time interval
-    miliseconds*: int ## The number of miliseconds
+    milliseconds*: int ## The number of milliseconds
     seconds*: int     ## The number of seconds
     minutes*: int     ## The number of minutes
     hours*: int       ## The number of hours
@@ -145,6 +145,11 @@ type
 {.deprecated: [TMonth: Month, TWeekDay: WeekDay, TTime: Time,
     TTimeInterval: TimeInterval, TTimeInfo: TimeInfo].}
 
+proc miliseconds*(t: TimeInterval): int {.deprecated.} = t.milliseconds
+
+proc `miliseconds=`*(t:var TimeInterval, milliseconds: int) {.deprecated.} =
+  t.milliseconds = milliseconds
+
 proc getTime*(): Time {.tags: [TimeEffect], benign.}
   ## gets the current calendar time as a UNIX epoch value (number of seconds
   ## elapsed since 1970) with integer precission. Use epochTime for higher
@@ -208,13 +213,13 @@ proc getTimezone*(): int {.tags: [TimeEffect], raises: [], benign.}
   ## returns the offset of the local (non-DST) timezone in seconds west of UTC.
 
 proc getStartMilsecs*(): int {.deprecated, tags: [TimeEffect], benign.}
-  ## get the miliseconds from the start of the program. **Deprecated since
+  ## get the milliseconds from the start of the program. **Deprecated since
   ## version 0.8.10.** Use ``epochTime`` or ``cpuTime`` instead.
 
-proc initInterval*(miliseconds, seconds, minutes, hours, days, months,
+proc initInterval*(milliseconds, seconds, minutes, hours, days, months,
                    years: int = 0): TimeInterval =
   ## creates a new ``TimeInterval``.
-  result.miliseconds = miliseconds
+  result.milliseconds = milliseconds
   result.seconds = seconds
   result.minutes = minutes
   result.hours = hours
@@ -264,7 +269,7 @@ proc toSeconds(a: TimeInfo, interval: TimeInterval): float =
   result += float(newinterv.hours * 60 * 60)
   result += float(newinterv.minutes * 60)
   result += float(newinterv.seconds)
-  result += newinterv.miliseconds / 1000
+  result += newinterv.milliseconds / 1000
 
 proc `+`*(a: TimeInfo, interval: TimeInterval): TimeInfo =
   ## adds ``interval`` time.
@@ -379,7 +384,7 @@ when not defined(JS):
     result.hour = t.hour
     result.monthday = t.monthday
     result.month = ord(t.month)
-    result.year = t.year - 1900
+    result.year = cint(t.year - 1900)
     result.weekday = weekDays[t.weekday]
     result.yearday = t.yearday
     result.isdst = if t.isDST: 1 else: 0
@@ -530,7 +535,7 @@ elif defined(JS):
     startMilsecs = getTime()
 
   proc getStartMilsecs(): int =
-    ## get the miliseconds from the start of the program
+    ## get the milliseconds from the start of the program
     return int(getTime() - startMilsecs)
 
   proc valueOf(time: Time): float {.importcpp: "getTime", tags:[]}
@@ -764,7 +769,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":
@@ -1036,8 +1041,6 @@ when isMainModule:
   # Tue 19 Jan 03:14:07 GMT 2038
 
   var t = getGMTime(fromSeconds(2147483647))
-  echo t.format("ddd dd MMM hh:mm:ss ZZZ yyyy")
-  echo t.format("ddd ddMMMhhmmssZZZyyyy")
   assert t.format("ddd dd MMM hh:mm:ss ZZZ yyyy") == "Tue 19 Jan 03:14:07 UTC 2038"
   assert t.format("ddd ddMMMhh:mm:ssZZZyyyy") == "Tue 19Jan03:14:07UTC2038"
 
@@ -1070,46 +1073,48 @@ 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"
-  echo "Kitchen: " & $s.parse(f)
+  assert "15:04:00" in $s.parse(f)
+  when not defined(testing):
+    echo "Kitchen: " & $s.parse(f)
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/unidecode/unidecode.nim b/lib/pure/unidecode/unidecode.nim
index 798eef5d0..a83b9be0f 100644
--- a/lib/pure/unidecode/unidecode.nim
+++ b/lib/pure/unidecode/unidecode.nim
@@ -70,5 +70,5 @@ proc unidecode*(s: string): string =
 
 when isMainModule:
   loadUnidecodeTable("lib/pure/unidecode/unidecode.dat")
-  echo unidecode("Äußerst")
+  assert unidecode("Äußerst") == "Ausserst"
 
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/pure/xmldomparser.nim b/lib/pure/xmldomparser.nim
index 7f34d72a8..050362435 100644
--- a/lib/pure/xmldomparser.nim
+++ b/lib/pure/xmldomparser.nim
@@ -155,7 +155,7 @@ proc loadXMLFile*(path: string): PDocument =
   return loadXMLStream(s)
 
 
-when isMainModule:
+when not defined(testing) and isMainModule:
   var xml = loadXMLFile("nim/xmldom/test.xml")
   #echo(xml.getElementsByTagName("m:test2")[0].namespaceURI)
   #echo(xml.getElementsByTagName("bla:test")[0].namespaceURI)
diff --git a/lib/pure/xmlparser.nim b/lib/pure/xmlparser.nim
index 755bfcdbc..840cae734 100644
--- a/lib/pure/xmlparser.nim
+++ b/lib/pure/xmlparser.nim
@@ -143,7 +143,7 @@ proc loadXml*(path: string): XmlNode =
   result = loadXml(path, errors)
   if errors.len > 0: raiseInvalidXml(errors)
 
-when isMainModule:
+when not defined(testing) and isMainModule:
   import os
 
   var errors: seq[string] = @[]  
diff --git a/lib/pure/xmltree.nim b/lib/pure/xmltree.nim
index 0bf5b52a4..7526a989a 100644
--- a/lib/pure/xmltree.nim
+++ b/lib/pure/xmltree.nim
@@ -353,5 +353,6 @@ proc findAll*(n: XmlNode, tag: string): seq[XmlNode] =
   findAll(n, tag, result)
 
 when isMainModule:
-  assert """<a href="http://nim-lang.org">Nim rules.</a>""" ==
+  let link = "http://nim-lang.org"
+  assert """<a href="""" & escape(link) & """">Nim rules.</a>""" ==
     $(<>a(href="http://nim-lang.org", newText("Nim rules.")))
diff --git a/lib/system.nim b/lib/system.nim
index 83f071717..1e6f76f3d 100644
--- a/lib/system.nim
+++ b/lib/system.nim
@@ -663,7 +663,7 @@ proc `+` *(x: int): int {.magic: "UnaryPlusI", noSideEffect.}
 proc `+` *(x: int8): int8 {.magic: "UnaryPlusI", noSideEffect.}
 proc `+` *(x: int16): int16 {.magic: "UnaryPlusI", noSideEffect.}
 proc `+` *(x: int32): int32 {.magic: "UnaryPlusI", noSideEffect.}
-proc `+` *(x: int64): int64 {.magic: "UnaryPlusI64", noSideEffect.}
+proc `+` *(x: int64): int64 {.magic: "UnaryPlusI", noSideEffect.}
   ## Unary `+` operator for an integer. Has no effect.
 
 proc `-` *(x: int): int {.magic: "UnaryMinusI", noSideEffect.}
@@ -1110,7 +1110,7 @@ var programResult* {.exportc: "nim_program_result".}: int
   ## prematurely using ``quit``, this value is ignored.
 
 proc quit*(errorcode: int = QuitSuccess) {.
-  magic: "Exit", importc: "exit", header: "<stdlib.h>", noReturn.}
+  magic: "Exit", importc: "exit", header: "<stdlib.h>", noreturn.}
   ## Stops the program immediately with an exit code.
   ##
   ## Before stopping the program the "quit procedures" are called in the
@@ -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
@@ -1638,7 +1638,7 @@ proc min*(x, y: int16): int16 {.magic: "MinI", noSideEffect.} =
   if x <= y: x else: y
 proc min*(x, y: int32): int32 {.magic: "MinI", noSideEffect.} =
   if x <= y: x else: y
-proc min*(x, y: int64): int64 {.magic: "MinI64", noSideEffect.} =
+proc min*(x, y: int64): int64 {.magic: "MinI", noSideEffect.} =
   ## The minimum value of two integers.
   if x <= y: x else: y
 
@@ -1656,7 +1656,7 @@ proc max*(x, y: int16): int16 {.magic: "MaxI", noSideEffect.} =
   if y <= x: x else: y
 proc max*(x, y: int32): int32 {.magic: "MaxI", noSideEffect.} =
   if y <= x: x else: y
-proc max*(x, y: int64): int64 {.magic: "MaxI64", noSideEffect.} =
+proc max*(x, y: int64): int64 {.magic: "MaxI", noSideEffect.} =
   ## The maximum value of two integers.
   if y <= x: x else: y
 
@@ -1744,6 +1744,12 @@ iterator items*(E: typedesc[enum]): E =
   for v in low(E)..high(E):
     yield v
 
+iterator items*[T](s: Slice[T]): T =
+  ## iterates over the slice `s`, yielding each value between `s.a` and `s.b`
+  ## (inclusively).
+  for x in s.a..s.b:
+    yield x
+
 iterator pairs*[T](a: openArray[T]): tuple[key: int, val: T] {.inline.} =
   ## iterates over each item of `a`. Yields ``(index, a[index])`` pairs.
   var i = 0
@@ -2264,20 +2270,21 @@ when hostOS == "standalone":
   include panicoverride
 
 when not declared(sysFatal):
-  template sysFatal(exceptn: typedesc, message: string) =
-    when hostOS == "standalone":
+  when hostOS == "standalone":
+    proc sysFatal(exceptn: typedesc, message: string) {.inline.} =
       panic(message)
-    else:
+
+    proc sysFatal(exceptn: typedesc, message, arg: string) {.inline.} =
+      rawoutput(message)
+      panic(arg)
+  else:
+    proc sysFatal(exceptn: typedesc, message: string) {.inline, noReturn.} =
       var e: ref exceptn
       new(e)
       e.msg = message
       raise e
 
-  template sysFatal(exceptn: typedesc, message, arg: string) =
-    when hostOS == "standalone":
-      rawoutput(message)
-      panic(arg)
-    else:
+    proc sysFatal(exceptn: typedesc, message, arg: string) {.inline, noReturn.} =
       var e: ref exceptn
       new(e)
       e.msg = message & arg
@@ -3201,7 +3208,7 @@ when hostOS != "standalone":
     if x == nil: x = y
     else: x.add(y)
 
-proc locals*(): RootObj {.magic: "Locals", noSideEffect.} =
+proc locals*(): RootObj {.magic: "Plugin", noSideEffect.} =
   ## generates a tuple constructor expression listing all the local variables
   ## in the current scope. This is quite fast as it does not rely
   ## on any debug or runtime information. Note that in constrast to what
@@ -3250,4 +3257,20 @@ proc `^`*(x: int): int {.noSideEffect, magic: "Roof".} =
   ## overloaded ``[]`` or ``[]=`` accessors.
   discard
 
+template `..^`*(a, b: expr): expr =
+  ## a shortcut for '.. ^' to avoid the common gotcha that a space between
+  ## '..' and '^' is required.
+  a .. ^b
+
+template `..<`*(a, b: expr): expr =
+  ## a shortcut for '.. <' to avoid the common gotcha that a space between
+  ## '..' and '<' is required.
+  a .. <b
+
+proc xlen*(x: string): int {.magic: "XLenStr", noSideEffect.} = discard
+proc xlen*[T](x: seq[T]): int {.magic: "XLenSeq", noSideEffect.} =
+  ## returns the length of a sequence or a string without testing for 'nil'.
+  ## This is an optimization that rarely makes sense.
+  discard
+
 {.pop.} #{.push warning[GcMem]: off.}
diff --git a/lib/system/arithm.nim b/lib/system/arithm.nim
index f68e2dcd9..ef153417c 100644
--- a/lib/system/arithm.nim
+++ b/lib/system/arithm.nim
@@ -10,11 +10,11 @@
 
 # simple integer arithmetic with overflow checking
 
-proc raiseOverflow {.compilerproc, noinline, noreturn.} =
+proc raiseOverflow {.compilerproc, noinline.} =
   # a single proc to reduce code size to a minimum
   sysFatal(OverflowError, "over- or underflow")
 
-proc raiseDivByZero {.compilerproc, noinline, noreturn.} =
+proc raiseDivByZero {.compilerproc, noinline.} =
   sysFatal(DivByZeroError, "division by zero")
 
 proc addInt64(a, b: int64): int64 {.compilerProc, inline.} =
@@ -327,13 +327,13 @@ when not declared(mulInt):
 # We avoid setting the FPU control word here for compatibility with libraries
 # written in other languages.
 
-proc raiseFloatInvalidOp {.noinline, noreturn.} =
+proc raiseFloatInvalidOp {.noinline.} =
   sysFatal(FloatInvalidOpError, "FPU operation caused a NaN result")
 
 proc nanCheck(x: float64) {.compilerProc, inline.} =
   if x != x: raiseFloatInvalidOp()
 
-proc raiseFloatOverflow(x: float64) {.noinline, noreturn.} =
+proc raiseFloatOverflow(x: float64) {.noinline.} =
   if x > 0.0:
     sysFatal(FloatOverflowError, "FPU operation caused an overflow")
   else:
diff --git a/lib/system/atomics.nim b/lib/system/atomics.nim
index 300fa85f3..c97d2fc7f 100644
--- a/lib/system/atomics.nim
+++ b/lib/system/atomics.nim
@@ -87,7 +87,7 @@ when someGcc and hasThreadSupport:
 
   proc atomicCompareExchange*[T: TAtomType](p, expected, desired: ptr T,
     weak: bool, success_memmodel: AtomMemModel, failure_memmodel: AtomMemModel): bool {.
-    importc: "__atomic_compare_exchange_n ", nodecl.}
+    importc: "__atomic_compare_exchange", nodecl.}
     ## This proc implements the generic version of atomic_compare_exchange.
     ## The proc is virtually identical to atomic_compare_exchange_n, except the desired
     ## value is also a pointer.
diff --git a/lib/system/chcks.nim b/lib/system/chcks.nim
index 2f6d25a12..6caf99d27 100644
--- a/lib/system/chcks.nim
+++ b/lib/system/chcks.nim
@@ -9,16 +9,16 @@
 
 # Implementation of some runtime checks.
 
-proc raiseRangeError(val: BiggestInt) {.compilerproc, noreturn, noinline.} =
+proc raiseRangeError(val: BiggestInt) {.compilerproc, noinline.} =
   when hostOS == "standalone":
     sysFatal(RangeError, "value out of range")
   else:
     sysFatal(RangeError, "value out of range: ", $val)
 
-proc raiseIndexError() {.compilerproc, noreturn, noinline.} =
+proc raiseIndexError() {.compilerproc, noinline.} =
   sysFatal(IndexError, "index out of bounds")
 
-proc raiseFieldError(f: string) {.compilerproc, noreturn, noinline.} =
+proc raiseFieldError(f: string) {.compilerproc, noinline.} =
   sysFatal(FieldError, f, " is not accessible")
 
 proc chckIndx(i, a, b: int): int =
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/windows.nim b/lib/windows/windows.nim
index b76dea6c5..02c87132a 100644
--- a/lib/windows/windows.nim
+++ b/lib/windows/windows.nim
@@ -18513,11 +18513,15 @@ proc DisableThreadLibraryCalls*(hLibModule: HMODULE): WINBOOL{.stdcall,
 proc GetProcAddress*(hModule: HINST, lpProcName: LPCSTR): FARPROC{.stdcall,

     dynlib: "kernel32", importc: "GetProcAddress".}

 proc GetVersion*(): DWORD{.stdcall, dynlib: "kernel32", importc: "GetVersion".}

-proc GlobalAlloc*(uFlags: int32, dwBytes: DWORD): HGLOBAL{.stdcall,

+proc GlobalAlloc*(uFlags: int32, dwBytes: SIZE_T): HGLOBAL{.stdcall,

     dynlib: "kernel32", importc: "GlobalAlloc".}

-proc GlobalReAlloc*(hMem: HGLOBAL, dwBytes: DWORD, uFlags: int32): HGLOBAL{.

+proc GlobalAlloc*(uFlags: int32, dwBytes: DWORD): HGLOBAL{.stdcall,

+    dynlib: "kernel32", importc: "GlobalAlloc", deprecated.}

+proc GlobalReAlloc*(hMem: HGLOBAL, dwBytes: SIZE_T, uFlags: int32): HGLOBAL{.

     stdcall, dynlib: "kernel32", importc: "GlobalReAlloc".}

-proc GlobalSize*(hMem: HGLOBAL): DWORD{.stdcall, dynlib: "kernel32",

+proc GlobalReAlloc*(hMem: HGLOBAL, dwBytes: DWORD, uFlags: int32): HGLOBAL{.

+    stdcall, dynlib: "kernel32", importc: "GlobalReAlloc", deprecated.}

+proc GlobalSize*(hMem: HGLOBAL): SIZE_T{.stdcall, dynlib: "kernel32",

                                         importc: "GlobalSize".}

 proc GlobalFlags*(hMem: HGLOBAL): WINUINT{.stdcall, dynlib: "kernel32",

                                         importc: "GlobalFlags".}

@@ -18541,10 +18545,14 @@ proc GlobalUnWire*(hMem: HGLOBAL): WINBOOL{.stdcall, dynlib: "kernel32",
     importc: "GlobalUnWire".}

 proc GlobalMemoryStatus*(lpBuffer: LPMEMORYSTATUS){.stdcall, dynlib: "kernel32",

     importc: "GlobalMemoryStatus".}

-proc LocalAlloc*(uFlags: WINUINT, uBytes: WINUINT): HLOCAL{.stdcall,

+proc LocalAlloc*(uFlags: WINUINT, uBytes: SIZE_T): HLOCAL{.stdcall,

     dynlib: "kernel32", importc: "LocalAlloc".}

-proc LocalReAlloc*(hMem: HLOCAL, uBytes: WINUINT, uFlags: WINUINT): HLOCAL{.stdcall,

+proc LocalAlloc*(uFlags: WINUINT, uBytes: DWORD): HLOCAL{.stdcall,

+    dynlib: "kernel32", importc: "LocalAlloc", deprecated.}

+proc LocalReAlloc*(hMem: HLOCAL, uBytes: SIZE_T, uFlags: WINUINT): HLOCAL{.stdcall,

     dynlib: "kernel32", importc: "LocalReAlloc".}

+proc LocalReAlloc*(hMem: HLOCAL, uBytes: DWORD, uFlags: WINUINT): HLOCAL{.stdcall,

+    dynlib: "kernel32", importc: "LocalReAlloc", deprecated.}

 proc LocalLock*(hMem: HLOCAL): LPVOID{.stdcall, dynlib: "kernel32",

                                        importc: "LocalLock".}

 proc LocalHandle*(pMem: LPCVOID): HLOCAL{.stdcall, dynlib: "kernel32",

@@ -18564,38 +18572,71 @@ proc LocalCompact*(uMinFree: WINUINT): WINUINT{.stdcall, dynlib: "kernel32",
 proc FlushInstructionCache*(hProcess: HANDLE, lpBaseAddress: LPCVOID,

                             dwSize: DWORD): WINBOOL{.stdcall,

     dynlib: "kernel32", importc: "FlushInstructionCache".}

-proc VirtualAlloc*(lpAddress: LPVOID, dwSize: DWORD, flAllocationType: DWORD,

+proc VirtualAlloc*(lpAddress: LPVOID, dwSize: SIZE_T, flAllocationType: DWORD,

                    flProtect: DWORD): LPVOID{.stdcall, dynlib: "kernel32",

     importc: "VirtualAlloc".}

-proc VirtualFree*(lpAddress: LPVOID, dwSize: DWORD, dwFreeType: DWORD): WINBOOL{.

+proc VirtualAlloc*(lpAddress: LPVOID, dwSize: DWORD, flAllocationType: DWORD,

+                   flProtect: DWORD): LPVOID{.stdcall, dynlib: "kernel32",

+    importc: "VirtualAlloc", deprecated.}

+proc VirtualAllocEx*(hProcess: HANDLE, lpAddress: LPVOID, dwSize: SIZE_T,

+                     flAllocationType: DWORD, flProtect: DWORD): LPVOID

+                     {.stdcall, dynlib: "kernel32", importc: "VirtualAllocEx".}

+proc VirtualAllocEx*(hProcess: HANDLE, lpAddress: LPVOID, dwSize: DWORD,

+                     flAllocationType: DWORD, flProtect: DWORD): LPVOID

+                     {.stdcall, dynlib: "kernel32", importc: "VirtualAllocEx", 

+                       deprecated.}

+proc VirtualFree*(lpAddress: LPVOID, dwSize: SIZE_T, dwFreeType: DWORD): WINBOOL{.

     stdcall, dynlib: "kernel32", importc: "VirtualFree".}

-proc VirtualProtect*(lpAddress: LPVOID, dwSize: DWORD, flNewProtect: DWORD,

+proc VirtualFree*(lpAddress: LPVOID, dwSize: DWORD, dwFreeType: DWORD): WINBOOL{.

+    stdcall, dynlib: "kernel32", importc: "VirtualFree", deprecated.}

+proc VirtualFreeEx*(hProcess: HANDLE, lpAddress: LPVOID, dwSize: SIZE_T,

+                    dwFreeType: DWORD): WINBOOL

+                    {.stdcall, dynlib: "kernel32", importc: "VirtualFree".}

+proc VirtualFreeEx*(hProcess: HANDLE, lpAddress: LPVOID, dwSize: DWORD,

+                    dwFreeType: DWORD): WINBOOL

+                    {.stdcall, dynlib: "kernel32", importc: "VirtualFree".}

+proc VirtualProtect*(lpAddress: LPVOID, dwSize: SIZE_T, flNewProtect: DWORD,

                      lpflOldProtect: PDWORD): WINBOOL{.stdcall,

     dynlib: "kernel32", importc: "VirtualProtect".}

+proc VirtualProtect*(lpAddress: LPVOID, dwSize: DWORD, flNewProtect: DWORD,

+                     lpflOldProtect: PDWORD): WINBOOL{.stdcall,

+    dynlib: "kernel32", importc: "VirtualProtect", deprecated.}

 proc VirtualQuery*(lpAddress: LPCVOID, lpBuffer: PMEMORY_BASIC_INFORMATION,

                    dwLength: DWORD): DWORD{.stdcall, dynlib: "kernel32",

     importc: "VirtualQuery".}

-proc VirtualProtectEx*(hProcess: HANDLE, lpAddress: LPVOID, dwSize: DWORD,

+proc VirtualProtectEx*(hProcess: HANDLE, lpAddress: LPVOID, dwSize: SIZE_T,

                        flNewProtect: DWORD, lpflOldProtect: PDWORD): WINBOOL{.

     stdcall, dynlib: "kernel32", importc: "VirtualProtectEx".}

+proc VirtualProtectEx*(hProcess: HANDLE, lpAddress: LPVOID, dwSize: DWORD,

+                       flNewProtect: DWORD, lpflOldProtect: PDWORD): WINBOOL{.

+    stdcall, dynlib: "kernel32", importc: "VirtualProtectEx", deprecated.}

 proc VirtualQueryEx*(hProcess: HANDLE, lpAddress: LPCVOID,

-                     lpBuffer: PMEMORY_BASIC_INFORMATION, dwLength: DWORD): DWORD{.

+                     lpBuffer: PMEMORY_BASIC_INFORMATION, dwLength: SIZE_T): DWORD{.

     stdcall, dynlib: "kernel32", importc: "VirtualQueryEx".}

-proc HeapCreate*(flOptions: DWORD, dwInitialSize: DWORD, dwMaximumSize: DWORD): HANDLE{.

+proc VirtualQueryEx*(hProcess: HANDLE, lpAddress: LPCVOID,

+                     lpBuffer: PMEMORY_BASIC_INFORMATION, dwLength: DWORD): DWORD{.

+    stdcall, dynlib: "kernel32", importc: "VirtualQueryEx", deprecated.}

+proc HeapCreate*(flOptions: DWORD, dwInitialSize: SIZE_T, dwMaximumSize: SIZE_T): HANDLE{.

     stdcall, dynlib: "kernel32", importc: "HeapCreate".}

+proc HeapCreate*(flOptions: DWORD, dwInitialSize: DWORD, dwMaximumSize: DWORD): HANDLE{.

+    stdcall, dynlib: "kernel32", importc: "HeapCreate", deprecated.}

 proc HeapDestroy*(hHeap: HANDLE): WINBOOL{.stdcall, dynlib: "kernel32",

     importc: "HeapDestroy".}

-proc HeapAlloc*(hHeap: HANDLE, dwFlags: DWORD, dwBytes: DWORD): LPVOID{.stdcall,

+proc HeapAlloc*(hHeap: HANDLE, dwFlags: DWORD, dwBytes: SIZE_T): LPVOID{.stdcall,

     dynlib: "kernel32", importc: "HeapAlloc".}

-proc HeapReAlloc*(hHeap: HANDLE, dwFlags: DWORD, lpMem: LPVOID, dwBytes: DWORD): LPVOID{.

+proc HeapAlloc*(hHeap: HANDLE, dwFlags: DWORD, dwBytes: DWORD): LPVOID{.stdcall,

+    dynlib: "kernel32", importc: "HeapAlloc", deprecated.}

+proc HeapReAlloc*(hHeap: HANDLE, dwFlags: DWORD, lpMem: LPVOID, dwBytes: SIZE_T): LPVOID{.

     stdcall, dynlib: "kernel32", importc: "HeapReAlloc".}

+proc HeapReAlloc*(hHeap: HANDLE, dwFlags: DWORD, lpMem: LPVOID, dwBytes: DWORD): LPVOID{.

+    stdcall, dynlib: "kernel32", importc: "HeapReAlloc", deprecated.}

 proc HeapFree*(hHeap: HANDLE, dwFlags: DWORD, lpMem: LPVOID): WINBOOL{.stdcall,

     dynlib: "kernel32", importc: "HeapFree".}

-proc HeapSize*(hHeap: HANDLE, dwFlags: DWORD, lpMem: LPCVOID): DWORD{.stdcall,

+proc HeapSize*(hHeap: HANDLE, dwFlags: DWORD, lpMem: LPCVOID): SIZE_T{.stdcall,

     dynlib: "kernel32", importc: "HeapSize".}

 proc HeapValidate*(hHeap: HANDLE, dwFlags: DWORD, lpMem: LPCVOID): WINBOOL{.

     stdcall, dynlib: "kernel32", importc: "HeapValidate".}

-proc HeapCompact*(hHeap: HANDLE, dwFlags: DWORD): WINUINT{.stdcall,

+proc HeapCompact*(hHeap: HANDLE, dwFlags: DWORD): SIZE_T{.stdcall,

     dynlib: "kernel32", importc: "HeapCompact".}

 proc GetProcessHeap*(): HANDLE{.stdcall, dynlib: "kernel32",

                                 importc: "GetProcessHeap".}

@@ -19221,10 +19262,14 @@ proc FindNextChangeNotification*(hChangeHandle: HANDLE): WINBOOL{.stdcall,
     dynlib: "kernel32", importc: "FindNextChangeNotification".}

 proc FindCloseChangeNotification*(hChangeHandle: HANDLE): WINBOOL{.stdcall,

     dynlib: "kernel32", importc: "FindCloseChangeNotification".}

-proc VirtualLock*(lpAddress: LPVOID, dwSize: DWORD): WINBOOL{.stdcall,

+proc VirtualLock*(lpAddress: LPVOID, dwSize: SIZE_T): WINBOOL{.stdcall,

     dynlib: "kernel32", importc: "VirtualLock".}

-proc VirtualUnlock*(lpAddress: LPVOID, dwSize: DWORD): WINBOOL{.stdcall,

+proc VirtualLock*(lpAddress: LPVOID, dwSize: DWORD): WINBOOL{.stdcall,

+    dynlib: "kernel32", importc: "VirtualLock", deprecated.}

+proc VirtualUnlock*(lpAddress: LPVOID, dwSize: SIZE_T): WINBOOL{.stdcall,

     dynlib: "kernel32", importc: "VirtualUnlock".}

+proc VirtualUnlock*(lpAddress: LPVOID, dwSize: DWORD): WINBOOL{.stdcall,

+    dynlib: "kernel32", importc: "VirtualUnlock", deprecated.}

 proc MapViewOfFileEx*(hFileMappingObject: HANDLE, dwDesiredAccess: DWORD,

                       dwFileOffsetHigh: DWORD, dwFileOffsetLow: DWORD,

                       dwNumberOfBytesToMap: DWORD, lpBaseAddress: LPVOID): LPVOID{.

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/lib/wrappers/claro.nim b/lib/wrappers/claro.nim
index d36b9f178..0fb0882bf 100644
--- a/lib/wrappers/claro.nim
+++ b/lib/wrappers/claro.nim
@@ -2710,7 +2710,7 @@ proc workspace_window_set_icon*(w: ptr TWorkspaceWindow, icon: ptr TImage){.
 claro_base_init()

 claro_graphics_init()

 

-when isMainModule:

+when not defined(testing) and isMainModule:

   var w = newWindow(nil, newBounds(100, 100, 230, 230), 0)

   window_set_title(w, "Hello, World!")

 

diff --git a/lib/wrappers/pcre.nim b/lib/wrappers/pcre.nim
index afa8f447a..67436f026 100644
--- a/lib/wrappers/pcre.nim
+++ b/lib/wrappers/pcre.nim
@@ -1,158 +1,190 @@
 #************************************************
-#       Perl-Compatible Regular Expressions      *
-#***********************************************
+#       Perl-Compatible Regular Expressions     *
+#************************************************
 # This is the public header file for the PCRE library, to be #included by
-#applications that call the PCRE functions.
+# applications that call the PCRE functions.
 #
-#           Copyright (c) 1997-2010 University of Cambridge
+#           Copyright (c) 1997-2014 University of Cambridge
 #
 #-----------------------------------------------------------------------------
-#Redistribution and use in source and binary forms, with or without
-#modification, are permitted provided that the following conditions are met:
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
 #
-#     Redistributions of source code must retain the above copyright notice,
+#    * Redistributions of source code must retain the above copyright notice,
 #      this list of conditions and the following disclaimer.
 #
-#     Redistributions in binary form must reproduce the above copyright
+#    * Redistributions in binary form must reproduce the above copyright
 #      notice, this list of conditions and the following disclaimer in the
 #      documentation and/or other materials provided with the distribution.
 #
-#     Neither the name of the University of Cambridge nor the names of its
+#    * Neither the name of the University of Cambridge nor the names of its
 #      contributors may be used to endorse or promote products derived from
 #      this software without specific prior written permission.
 #
-#THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-#AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-#IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-#ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-#LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-#CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-#SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-#INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-#CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-#ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-#POSSIBILITY OF SUCH DAMAGE.
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
 #-----------------------------------------------------------------------------
-#
 
-{.deadcodeElim: on.}
-
-when not defined(pcreDll):
-  when hostOS == "windows":
-    const pcreDll = "pcre.dll"
-  elif hostOS == "macosx":
-    const pcreDll = "libpcre(.3|.1|).dylib"
-  else:
-    const pcreDll = "libpcre.so(.3|.1|)"
-  {.pragma: pcreImport, dynlib: pcreDll.}
-else:
-  {.pragma: pcreImport, header: "<pcre.h>".}
+{.deadCodeElim: on.}
 
-# The current PCRE version information. 
+# The current PCRE version information.
 
-const 
-  MAJOR* = 8
-  MINOR* = 31
-  PRERELEASE* = true
-  DATE* = "2012-07-06"
+const
+  PCRE_MAJOR* = 8
+  PCRE_MINOR* = 36
+  PCRE_PRERELEASE* = true
+  PCRE_DATE* = "2014-09-26"
 
 # When an application links to a PCRE DLL in Windows, the symbols that are
 # imported have to be identified as such. When building PCRE, the appropriate
 # export setting is defined in pcre_internal.h, which includes this file. So we
-# don't change existing definitions of PCRE_EXP_DECL and PCRECPP_EXP_DECL. 
-
-# Have to include stdlib.h in order to ensure that size_t is defined;
-# it is needed here for malloc. 
-
-# Allow for C++ users 
-
-# Options. Some are compile-time only, some are run-time only, and some are
-# both, so we keep them all distinct. 
-
-const 
-  CASELESS* = 0x00000001
-  MULTILINE* = 0x00000002
-  DOTALL* = 0x00000004
-  EXTENDED* = 0x00000008
-  ANCHORED* = 0x00000010
-  DOLLAR_ENDONLY* = 0x00000020
-  EXTRA* = 0x00000040
-  NOTBOL* = 0x00000080
-  NOTEOL* = 0x00000100
-  UNGREEDY* = 0x00000200
-  NOTEMPTY* = 0x00000400
-  UTF8* = 0x00000800
-  NO_AUTO_CAPTURE* = 0x00001000
-  NO_UTF8_CHECK* = 0x00002000
-  AUTO_CALLOUT* = 0x00004000
-  PARTIAL_SOFT* = 0x00008000
-  PARTIAL* = 0x00008000       # Backwards compatible synonym 
-  DFA_SHORTEST* = 0x00010000
-  DFA_RESTART* = 0x00020000
-  FIRSTLINE* = 0x00040000
-  DUPNAMES* = 0x00080000
-  NEWLINE_CR* = 0x00100000
-  NEWLINE_LF* = 0x00200000
-  NEWLINE_CRLF* = 0x00300000
-  NEWLINE_ANY* = 0x00400000
-  NEWLINE_ANYCRLF* = 0x00500000
-  BSR_ANYCRLF* = 0x00800000
-  BSR_UNICODE* = 0x01000000
-  JAVASCRIPT_COMPAT* = 0x02000000
-  NO_START_OPTIMIZE* = 0x04000000
-  NO_START_OPTIMISE* = 0x04000000
-  PARTIAL_HARD* = 0x08000000
-  NOTEMPTY_ATSTART* = 0x10000000
-  UCP* = 0x20000000
-
-# Exec-time and get/set-time error codes 
-
-const 
-  ERROR_NOMATCH* = (- 1)
-  ERROR_NULL* = (- 2)
-  ERROR_BADOPTION* = (- 3)
-  ERROR_BADMAGIC* = (- 4)
-  ERROR_UNKNOWN_OPCODE* = (- 5)
-  ERROR_UNKNOWN_NODE* = (- 5) # For backward compatibility 
-  ERROR_NOMEMORY* = (- 6)
-  ERROR_NOSUBSTRING* = (- 7)
-  ERROR_MATCHLIMIT* = (- 8)
-  ERROR_CALLOUT* = (- 9)      # Never used by PCRE itself 
-  ERROR_BADUTF8* = (- 10)
-  ERROR_BADUTF8_OFFSET* = (- 11)
-  ERROR_PARTIAL* = (- 12)
-  ERROR_BADPARTIAL* = (- 13)
-  ERROR_INTERNAL* = (- 14)
-  ERROR_BADCOUNT* = (- 15)
-  ERROR_DFA_UITEM* = (- 16)
-  ERROR_DFA_UCOND* = (- 17)
-  ERROR_DFA_UMLIMIT* = (- 18)
-  ERROR_DFA_WSSIZE* = (- 19)
-  ERROR_DFA_RECURSE* = (- 20)
-  ERROR_RECURSIONLIMIT* = (- 21)
-  ERROR_NULLWSLIMIT* = (- 22) # No longer actually used 
-  ERROR_BADNEWLINE* = (- 23)
-  ERROR_BADOFFSET* = (- 24)
-  ERROR_SHORTUTF8* = (- 25)
-  ERROR_RECURSELOOP* = (- 26)
-  ERROR_JIT_STACKLIMIT* = (- 27)
-  ERROR_BADMODE* = (- 28)
-  ERROR_BADENDIANNESS* = (- 29)
-  ERROR_DFA_BADRESTART* = (- 30)
-
-# Specific error codes for UTF-8 validity checks
+# don't change existing definitions of PCRE_EXP_DECL and PCRECPP_EXP_DECL.
+
+# By default, we use the standard "extern" declarations.
+
+# Allow for C++ users
+
+# Public options. Some are compile-time only, some are run-time only, and some
+# are both. Most of the compile-time options are saved with the compiled regex
+# so that they can be inspected during studying (and therefore JIT compiling).
+# Note that pcre_study() has its own set of options. Originally, all the options
+# defined here used distinct bits. However, almost all the bits in a 32-bit word
+# are now used, so in order to conserve them, option bits that were previously
+# only recognized at matching time (i.e. by pcre_exec() or pcre_dfa_exec()) may
+# also be used for compile-time options that affect only compiling and are not
+# relevant for studying or JIT compiling.
+#
+# Some options for pcre_compile() change its behaviour but do not affect the
+# behaviour of the execution functions. Other options are passed through to the
+# execution functions and affect their behaviour, with or without affecting the
+# behaviour of pcre_compile().
+#
+# Options that can be passed to pcre_compile() are tagged Cx below, with these
+# variants:
+#
+# C1   Affects compile only
+# C2   Does not affect compile; affects exec, dfa_exec
+# C3   Affects compile, exec, dfa_exec
+# C4   Affects compile, exec, dfa_exec, study
+# C5   Affects compile, exec, study
+#
+# Options that can be set for pcre_exec() and/or pcre_dfa_exec() are flagged 
+# with E and D, respectively. They take precedence over C3, C4, and C5 settings 
+# passed from pcre_compile(). Those that are compatible with JIT execution are 
+# flagged with J.
+
+const
+  CASELESS*          = 0x00000001  # C1
+  MULTILINE*         = 0x00000002  # C1
+  DOTALL*            = 0x00000004  # C1
+  EXTENDED*          = 0x00000008  # C1
+  ANCHORED*          = 0x00000010  # C4 E D
+  DOLLAR_ENDONLY*    = 0x00000020  # C2
+  EXTRA*             = 0x00000040  # C1
+  NOTBOL*            = 0x00000080  #    E D J
+  NOTEOL*            = 0x00000100  #    E D J
+  UNGREEDY*          = 0x00000200  # C1
+  NOTEMPTY*          = 0x00000400  #    E D J
+  UTF8*              = 0x00000800  # C4        )
+  UTF16*             = 0x00000800  # C4        ) Synonyms
+  UTF32*             = 0x00000800  # C4        )
+  NO_AUTO_CAPTURE*   = 0x00001000  # C1
+  NO_UTF8_CHECK*     = 0x00002000  # C1 E D J  )
+  NO_UTF16_CHECK*    = 0x00002000  # C1 E D J  ) Synonyms
+  NO_UTF32_CHECK*    = 0x00002000  # C1 E D J  )
+  AUTO_CALLOUT*      = 0x00004000  # C1
+  PARTIAL_SOFT*      = 0x00008000  #    E D J  ) Synonyms
+  PARTIAL*           = 0x00008000  #    E D J  )
+
+# This pair use the same bit.
+const
+  NEVER_UTF*         = 0x00010000  # C1        ) Overlaid
+  DFA_SHORTEST*      = 0x00010000  #      D    ) Overlaid
 
+# This pair use the same bit.
 const
-  UTF8_ERR0* = 0
-  UTF8_ERR1* = 1
-  UTF8_ERR2* = 2
-  UTF8_ERR3* = 3
-  UTF8_ERR4* = 4
-  UTF8_ERR5* = 5
-  UTF8_ERR6* = 6
-  UTF8_ERR7* = 7
-  UTF8_ERR8* = 8
-  UTF8_ERR9* = 9
+  NO_AUTO_POSSESS*   = 0x00020000  # C1        ) Overlaid
+  DFA_RESTART*       = 0x00020000  #      D    ) Overlaid
+
+const
+  FIRSTLINE*         = 0x00040000  # C3
+  DUPNAMES*          = 0x00080000  # C1
+  NEWLINE_CR*        = 0x00100000  # C3 E D
+  NEWLINE_LF*        = 0x00200000  # C3 E D
+  NEWLINE_CRLF*      = 0x00300000  # C3 E D
+  NEWLINE_ANY*       = 0x00400000  # C3 E D
+  NEWLINE_ANYCRLF*   = 0x00500000  # C3 E D
+  BSR_ANYCRLF*       = 0x00800000  # C3 E D
+  BSR_UNICODE*       = 0x01000000  # C3 E D
+  JAVASCRIPT_COMPAT* = 0x02000000  # C5
+  NO_START_OPTIMIZE* = 0x04000000  # C2 E D    ) Synonyms
+  NO_START_OPTIMISE* = 0x04000000  # C2 E D    )
+  PARTIAL_HARD*      = 0x08000000  #    E D J
+  NOTEMPTY_ATSTART*  = 0x10000000  #    E D J
+  UCP*               = 0x20000000  # C3
+
+## Exec-time and get/set-time error codes
+const
+  ERROR_NOMATCH*          =  -1
+  ERROR_NULL*             =  -2
+  ERROR_BADOPTION*        =  -3
+  ERROR_BADMAGIC*         =  -4
+  ERROR_UNKNOWN_OPCODE*   =  -5
+  ERROR_UNKNOWN_NODE*     =  -5 ## For backward compatibility
+  ERROR_NOMEMORY*         =  -6
+  ERROR_NOSUBSTRING*      =  -7
+  ERROR_MATCHLIMIT*       =  -8
+  ERROR_CALLOUT*          =  -9 ## Never used by PCRE itself
+  ERROR_BADUTF8*          = -10 ## Same for 8/16/32
+  ERROR_BADUTF16*         = -10 ## Same for 8/16/32
+  ERROR_BADUTF32*         = -10 ## Same for 8/16/32
+  ERROR_BADUTF8_OFFSET*   = -11 ## Same for 8/16
+  ERROR_BADUTF16_OFFSET*  = -11 ## Same for 8/16
+  ERROR_PARTIAL*          = -12
+  ERROR_BADPARTIAL*       = -13
+  ERROR_INTERNAL*         = -14
+  ERROR_BADCOUNT*         = -15
+  ERROR_DFA_UITEM*        = -16
+  ERROR_DFA_UCOND*        = -17
+  ERROR_DFA_UMLIMIT*      = -18
+  ERROR_DFA_WSSIZE*       = -19
+  ERROR_DFA_RECURSE*      = -20
+  ERROR_RECURSIONLIMIT*   = -21
+  ERROR_NULLWSLIMIT*      = -22 ## No longer actually used
+  ERROR_BADNEWLINE*       = -23
+  ERROR_BADOFFSET*        = -24
+  ERROR_SHORTUTF8*        = -25
+  ERROR_SHORTUTF16*       = -25 ## Same for 8/16
+  ERROR_RECURSELOOP*      = -26
+  ERROR_JIT_STACKLIMIT*   = -27
+  ERROR_BADMODE*          = -28
+  ERROR_BADENDIANNESS*    = -29
+  ERROR_DFA_BADRESTART*   = -30
+  ERROR_JIT_BADOPTION*    = -31
+  ERROR_BADLENGTH*        = -32
+  ERROR_UNSET*            = -33
+
+## Specific error codes for UTF-8 validity checks
+const
+  UTF8_ERR0*  =  0
+  UTF8_ERR1*  =  1
+  UTF8_ERR2*  =  2
+  UTF8_ERR3*  =  3
+  UTF8_ERR4*  =  4
+  UTF8_ERR5*  =  5
+  UTF8_ERR6*  =  6
+  UTF8_ERR7*  =  7
+  UTF8_ERR8*  =  8
+  UTF8_ERR9*  =  9
   UTF8_ERR10* = 10
   UTF8_ERR11* = 11
   UTF8_ERR12* = 12
@@ -165,193 +197,305 @@ const
   UTF8_ERR19* = 19
   UTF8_ERR20* = 20
   UTF8_ERR21* = 21
+  UTF8_ERR22* = 22 # Unused (was non-character)
 
-# Request types for pcre_fullinfo() 
-
-const 
-  INFO_OPTIONS* = 0
-  INFO_SIZE* = 1
-  INFO_CAPTURECOUNT* = 2
-  INFO_BACKREFMAX* = 3
-  INFO_FIRSTBYTE* = 4
-  INFO_FIRSTCHAR* = 4         # For backwards compatibility 
-  INFO_FIRSTTABLE* = 5
-  INFO_LASTLITERAL* = 6
-  INFO_NAMEENTRYSIZE* = 7
-  INFO_NAMECOUNT* = 8
-  INFO_NAMETABLE* = 9
-  INFO_STUDYSIZE* = 10
-  INFO_DEFAULT_TABLES* = 11
-  INFO_OKPARTIAL* = 12
-  INFO_JCHANGED* = 13
-  INFO_HASCRORLF* = 14
-  INFO_MINLENGTH* = 15
-  INFO_JIT* = 16
-  INFO_JITSIZE* = 17
-  INFO_MAXLOOKBEHIND* = 18
-
-# Request types for pcre_config(). Do not re-arrange, in order to remain
-# compatible. 
-
-const 
-  CONFIG_UTF8* = 0
-  CONFIG_NEWLINE* = 1
-  CONFIG_LINK_SIZE* = 2
-  CONFIG_POSIX_MALLOC_THRESHOLD* = 3
-  CONFIG_MATCH_LIMIT* = 4
-  CONFIG_STACKRECURSE* = 5
-  CONFIG_UNICODE_PROPERTIES* = 6
-  CONFIG_MATCH_LIMIT_RECURSION* = 7
-  CONFIG_BSR* = 8
-  CONFIG_JIT* = 9
-  CONFIG_JITTARGET* = 11
-
-# Request types for pcre_study(). Do not re-arrange, in order to remain
-# compatible.
+## Specific error codes for UTF-16 validity checks
+const
+  UTF16_ERR0* = 0
+  UTF16_ERR1* = 1
+  UTF16_ERR2* = 2
+  UTF16_ERR3* = 3
+  UTF16_ERR4* = 4 # Unused (was non-character)
 
+## Specific error codes for UTF-32 validity checks
 const
-  STUDY_JIT_COMPILE* = 0x00000001
-  STUDY_JIT_PARTIAL_SOFT_COMPILE* = 0x00000002
-  STUDY_JIT_PARTIAL_HARD_COMPILE* = 0x00000004
-
-# Bit flags for the pcre_extra structure. Do not re-arrange or redefine
-# these bits, just add new ones on the end, in order to remain compatible. 
-
-const 
-  EXTRA_STUDY_DATA* = 0x00000001
-  EXTRA_MATCH_LIMIT* = 0x00000002
-  EXTRA_CALLOUT_DATA* = 0x00000004
-  EXTRA_TABLES* = 0x00000008
-  EXTRA_MATCH_LIMIT_RECURSION* = 0x00000010
-  EXTRA_MARK* = 0x00000020
-  EXTRA_EXECUTABLE_JIT* = 0x00000040
-
-# Types 
-
-type 
-  TPcre*{.pure, final.} = object
-  PPcre* = ptr TPcre
-  Tjit_stack*{.pure, final.} = object
-  Pjit_stack* = ptr Tjit_stack
-
-# When PCRE is compiled as a C++ library, the subject pointer type can be
-# replaced with a custom type. For conventional use, the public interface is a
-# const char *. 
-
-# The structure for passing additional data to pcre_exec(). This is defined in
-# such as way as to be extensible. Always add new fields at the end, in order to
-# remain compatible. 
-
-type 
-  TExtra*{.pure, final.} = object 
-    flags*: int                 ## Bits for which fields are set 
-    study_data*: pointer        ## Opaque data from pcre_study() 
-    match_limit*: int           ## Maximum number of calls to match() 
-    callout_data*: pointer      ## Data passed back in callouts 
-    tables*: cstring            ## Pointer to character tables 
-    match_limit_recursion*: int ## Max recursive calls to match() 
-    mark*: ptr cstring          ## For passing back a mark pointer 
-    executable_jit*: pointer    ## Contains a pointer to a compiled jit code
-  
-
-# The structure for passing out data via the pcre_callout_function. We use a
-# structure so that new fields can be added on the end in future versions,
-# without changing the API of the function, thereby allowing old clients to work
-# without modification. 
-
-type 
-  TCalloutBlock*{.pure, final.} = object 
-    version*: cint            ## Identifies version of block 
-    callout_number*: cint     ## Number compiled into pattern 
-    offset_vector*: ptr cint  ## The offset vector 
-    subject*: cstring         ## The subject being matched 
-    subject_length*: cint     ## The length of the subject 
-    start_match*: cint        ## Offset to start of this match attempt 
-    current_position*: cint   ## Where we currently are in the subject 
-    capture_top*: cint        ## Max current capture 
-    capture_last*: cint       ## Most recently closed capture 
-    callout_data*: pointer    ## Data passed in with the call 
-    pattern_position*: cint   ## Offset to next item in the pattern 
-    next_item_length*: cint   ## Length of next item in the pattern
-    mark*: cstring            ## Pointer to current mark or NULL
-
-# Indirection for store get and free functions. These can be set to
-#alternative malloc/free functions if required. Special ones are used in the
-#non-recursive case for "frames". There is also an optional callout function
-#that is triggered by the (?) regex item. For Virtual Pascal, these definitions
-#have to take another form.
-
-# User defined callback which provides a stack just before the match starts.
+  UTF32_ERR0* = 0
+  UTF32_ERR1* = 1
+  UTF32_ERR2* = 2 # Unused (was non-character)
+  UTF32_ERR3* = 3
 
+## Request types for pcre_fullinfo()
+const
+  INFO_OPTIONS*             =  0
+  INFO_SIZE*                =  1
+  INFO_CAPTURECOUNT*        =  2
+  INFO_BACKREFMAX*          =  3
+  INFO_FIRSTBYTE*           =  4
+  INFO_FIRSTCHAR*           =  4 ## For backwards compatibility
+  INFO_FIRSTTABLE*          =  5
+  INFO_LASTLITERAL*         =  6
+  INFO_NAMEENTRYSIZE*       =  7
+  INFO_NAMECOUNT*           =  8
+  INFO_NAMETABLE*           =  9
+  INFO_STUDYSIZE*           = 10
+  INFO_DEFAULT_TABLES*      = 11
+  INFO_OKPARTIAL*           = 12
+  INFO_JCHANGED*            = 13
+  INFO_HASCRORLF*           = 14
+  INFO_MINLENGTH*           = 15
+  INFO_JIT*                 = 16
+  INFO_JITSIZE*             = 17
+  INFO_MAXLOOKBEHIND*       = 18
+  INFO_FIRSTCHARACTER*      = 19
+  INFO_FIRSTCHARACTERFLAGS* = 20
+  INFO_REQUIREDCHAR*        = 21
+  INFO_REQUIREDCHARFLAGS*   = 22
+  INFO_MATCHLIMIT*          = 23
+  INFO_RECURSIONLIMIT*      = 24
+  INFO_MATCH_EMPTY*         = 25
+
+## Request types for pcre_config(). Do not re-arrange, in order to remain
+## compatible.
+const
+  CONFIG_UTF8*                   =  0
+  CONFIG_NEWLINE*                =  1
+  CONFIG_LINK_SIZE*              =  2
+  CONFIG_POSIX_MALLOC_THRESHOLD* =  3
+  CONFIG_MATCH_LIMIT*            =  4
+  CONFIG_STACKRECURSE*           =  5
+  CONFIG_UNICODE_PROPERTIES*     =  6
+  CONFIG_MATCH_LIMIT_RECURSION*  =  7
+  CONFIG_BSR*                    =  8
+  CONFIG_JIT*                    =  9
+  CONFIG_UTF16*                  = 10
+  CONFIG_JITTARGET*              = 11
+  CONFIG_UTF32*                  = 12
+  CONFIG_PARENS_LIMIT*           = 13
+
+## Request types for pcre_study(). Do not re-arrange, in order to remain
+## compatible.
+const
+  STUDY_JIT_COMPILE*              = 0x0001
+  STUDY_JIT_PARTIAL_SOFT_COMPILE* = 0x0002
+  STUDY_JIT_PARTIAL_HARD_COMPILE* = 0x0004
+  STUDY_EXTRA_NEEDED*             = 0x0008
+
+## Bit flags for the pcre[16|32]_extra structure. Do not re-arrange or redefine
+## these bits, just add new ones on the end, in order to remain compatible.
+const
+  EXTRA_STUDY_DATA*            = 0x0001
+  EXTRA_MATCH_LIMIT*           = 0x0002
+  EXTRA_CALLOUT_DATA*          = 0x0004
+  EXTRA_TABLES*                = 0x0008
+  EXTRA_MATCH_LIMIT_RECURSION* = 0x0010
+  EXTRA_MARK*                  = 0x0020
+  EXTRA_EXECUTABLE_JIT*        = 0x0040
+
+## Types
+type
+  Pcre* = object
+  Pcre16* = object
+  Pcre32* = object
+  JitStack* = object
+  JitStack16* = object
+  JitStack32* = object
+
+
+## The structure for passing additional data to pcre_exec(). This is defined in
+## such as way as to be extensible. Always add new fields at the end, in order
+## to remain compatible.
+type
+  ExtraData* = object
+    flags*: clong                  ## Bits for which fields are set
+    study_data*: pointer           ## Opaque data from pcre_study()
+    match_limit*: clong            ## Maximum number of calls to match()
+    callout_data*: pointer         ## Data passed back in callouts
+    tables*: pointer               ## Pointer to character tables
+    match_limit_recursion*: clong  ## Max recursive calls to match()
+    mark*: pointer                 ## For passing back a mark pointer
+    executable_jit*: pointer       ## Contains a pointer to a compiled jit code
+
+## The structure for passing out data via the pcre_callout_function. We use a
+## structure so that new fields can be added on the end in future versions,
+## without changing the API of the function, thereby allowing old clients to
+## work without modification.
 type
-  TJitCallback* = proc(p: pointer): ptr Tjit_stack{.cdecl.}
-
-# Exported PCRE functions 
-
-proc compile*(a2: cstring, a3: cint, a4: ptr cstring, a5: ptr cint, 
-              a6: ptr char): ptr TPcre{.cdecl, importc: "pcre_compile", 
-    pcreImport.}
-proc compile2*(a2: cstring, a3: cint, a4: ptr cint, a5: ptr cstring, 
-               a6: ptr cint, a7: ptr char): ptr TPcre{.cdecl, 
-    importc: "pcre_compile2", pcreImport.}
-proc config*(a2: cint, a3: pointer): cint{.cdecl, importc: "pcre_config", 
-    pcreImport.}
-proc copy_named_substring*(a2: ptr TPcre, a3: cstring, a4: ptr cint, a5: cint, 
-                           a6: cstring, a7: cstring, a8: cint): cint{.cdecl, 
-    importc: "pcre_copy_named_substring", pcreImport.}
-proc copy_substring*(a2: cstring, a3: ptr cint, a4: cint, a5: cint, 
-                     a6: cstring, 
-                     a7: cint): cint{.cdecl, importc: "pcre_copy_substring", 
-                                      pcreImport.}
-proc dfa_exec*(a2: ptr TPcre, a3: ptr TExtra, a4: cstring, a5: cint, 
-               a6: cint, a7: cint, a8: ptr cint, a9: cint, a10: ptr cint, 
-               a11: cint): cint{.cdecl, importc: "pcre_dfa_exec", 
-                                 pcreImport.}
-proc exec*(a2: ptr TPcre, a3: ptr TExtra, a4: cstring, a5: cint, a6: cint, 
-           a7: cint, a8: ptr cint, a9: cint): cint {.
-           cdecl, importc: "pcre_exec", pcreImport.}
-proc free_substring*(a2: cstring){.cdecl, importc: "pcre_free_substring", 
-                                   pcreImport.}
-proc free_substring_list*(a2: cstringArray){.cdecl, 
-    importc: "pcre_free_substring_list", pcreImport.}
-proc fullinfo*(a2: ptr TPcre, a3: ptr TExtra, a4: cint, a5: pointer): cint{.
-    cdecl, importc: "pcre_fullinfo", pcreImport.}
-proc get_named_substring*(a2: ptr TPcre, a3: cstring, a4: ptr cint, a5: cint, 
-                          a6: cstring, a7: cstringArray): cint{.cdecl, 
-    importc: "pcre_get_named_substring", pcreImport.}
-proc get_stringnumber*(a2: ptr TPcre, a3: cstring): cint{.cdecl, 
-    importc: "pcre_get_stringnumber", pcreImport.}
-proc get_stringtable_entries*(a2: ptr TPcre, a3: cstring, a4: cstringArray, 
-                              a5: cstringArray): cint{.cdecl, 
-    importc: "pcre_get_stringtable_entries", pcreImport.}
-proc get_substring*(a2: cstring, a3: ptr cint, a4: cint, a5: cint, 
-                    a6: cstringArray): cint{.cdecl, 
-    importc: "pcre_get_substring", pcreImport.}
-proc get_substring_list*(a2: cstring, a3: ptr cint, a4: cint, 
-                         a5: ptr cstringArray): cint{.cdecl, 
-    importc: "pcre_get_substring_list", pcreImport.}
-proc maketables*(): ptr char{.cdecl, importc: "pcre_maketables", 
-                                       pcreImport.}
-proc refcount*(a2: ptr TPcre, a3: cint): cint{.cdecl, importc: "pcre_refcount", 
-    pcreImport.}
-proc study*(a2: ptr TPcre, a3: cint, a4: var cstring): ptr TExtra{.cdecl, 
-    importc: "pcre_study", pcreImport.}
-proc version*(): cstring{.cdecl, importc: "pcre_version", pcreImport.}
+  CalloutBlock* = object
+    version*         : cint       ## Identifies version of block
+    # ------------------------ Version 0 -------------------------------
+    callout_number*  : cint       ## Number compiled into pattern
+    offset_vector*   : ptr cint   ## The offset vector
+    subject*         : cstring    ## The subject being matched
+    subject_length*  : cint       ## The length of the subject
+    start_match*     : cint       ## Offset to start of this match attempt
+    current_position*: cint       ## Where we currently are in the subject
+    capture_top*     : cint       ## Max current capture
+    capture_last*    : cint       ## Most recently closed capture
+    callout_data*    : pointer    ## Data passed in with the call
+    # ------------------- Added for Version 1 --------------------------
+    pattern_position*: cint       ## Offset to next item in the pattern
+    next_item_length*: cint       ## Length of next item in the pattern
+    # ------------------- Added for Version 2 --------------------------
+    mark*            : pointer    ## Pointer to current mark or NULL
+    # ------------------------------------------------------------------
+
+
+## User defined callback which provides a stack just before the match starts.
+type
+  JitCallback* = proc (a: pointer): ptr JitStack {.cdecl.}
+
+
+when not defined(usePcreHeader):
+  when hostOS == "windows":
+    const pcreDll = "pcre.dll"
+  elif hostOS == "macosx":
+    const pcreDll = "libpcre(.3|.1|).dylib"
+  else:
+    const pcreDll = "libpcre.so(.3|.1|)"
+  {.push dynlib: pcreDll.}
+else:
+  {.push header: "<pcre.h>".}
+
+{.push cdecl, importc: "pcre_$1".}
+
+# Exported PCRE functions
+
+proc compile*(pattern: cstring,
+              options: cint,
+              errptr: ptr cstring,
+              erroffset: ptr cint,
+              tableptr: pointer): ptr Pcre
+
+proc compile2*(pattern: cstring,
+               options: cint,
+               errorcodeptr: ptr cint,
+               errptr: ptr cstring,
+               erroffset: ptr cint,
+               tableptr: pointer): ptr Pcre
+
+proc config*(what: cint,
+             where: pointer): cint
+
+proc copy_named_substring*(code: ptr Pcre,
+                           subject: cstring,
+                           ovector: ptr cint,
+                           stringcount: cint,
+                           stringname: cstring,
+                           buffer: cstring,
+                           buffersize: cint): cint
+
+proc copy_substring*(subject: cstring,
+                     ovector: ptr cint,
+                     stringcount: cint,
+                     stringnumber: cint,
+                     buffer: cstring,
+                     buffersize: cint): cint
+
+proc dfa_exec*(code: ptr Pcre,
+               extra: ptr ExtraData,
+               subject: cstring,
+               length: cint,
+               startoffset: cint,
+               options: cint,
+               ovector: ptr cint,
+               ovecsize: cint,
+               workspace: ptr cint,
+               wscount: cint): cint
+
+proc exec*(code: ptr Pcre,
+           extra: ptr ExtraData,
+           subject: cstring,
+           length: cint,
+           startoffset: cint,
+           options: cint,
+           ovector: ptr cint,
+           ovecsize: cint): cint
+
+proc jit_exec*(code: ptr Pcre,
+               extra: ptr ExtraData,
+               subject: cstring,
+               length: cint,
+               startoffset: cint,
+               options: cint,
+               ovector: ptr cint,
+               ovecsize: cint,
+               jstack: ptr JitStack): cint
+
+proc free_substring*(stringptr: cstring)
+
+proc free_substring_list*(stringptr: cstringArray)
+
+proc fullinfo*(code: ptr Pcre,
+               extra: ptr ExtraData,
+               what: cint,
+               where: pointer): cint
+
+proc get_named_substring*(code: ptr Pcre,
+                          subject: cstring,
+                          ovector: ptr cint,
+                          stringcount: cint,
+                          stringname: cstring,
+                          stringptr: cstringArray): cint
+
+proc get_stringnumber*(code: ptr Pcre,
+                       name: cstring): cint
+
+proc get_stringtable_entries*(code: ptr Pcre,
+                              name: cstring,
+                              first: cstringArray,
+                              last: cstringArray): cint
+
+proc get_substring*(subject: cstring,
+                    ovector: ptr cint,
+                    stringcount: cint,
+                    stringnumber: cint,
+                    stringptr: cstringArray): cint
+
+proc get_substring_list*(subject: cstring,
+                         ovector: ptr cint,
+                         stringcount: cint,
+                         listptr: ptr cstringArray): cint
+
+proc maketables*(): pointer
+
+proc refcount*(code: ptr Pcre,
+               adjust: cint): cint
+
+proc study*(code: ptr Pcre,
+            options: cint,
+            errptr: ptr cstring): ptr ExtraData
+
+proc free_study*(extra: ptr ExtraData)
+
+proc version*(): cstring
 
 # Utility functions for byte order swaps.
 
-proc pattern_to_host_byte_order*(a2: ptr TPcre, a3: ptr TExtra,
-    a4: ptr char): cint{.cdecl, importc: "pcre_pattern_to_host_byte_order",
-    pcreImport.}
+proc pattern_to_host_byte_order*(code: ptr Pcre,
+                                 extra: ptr ExtraData,
+                                 tables: pointer): cint
 
 # JIT compiler related functions.
 
-proc jit_stack_alloc*(a2: cint, a3: cint): ptr Tjit_stack{.cdecl,
-    importc: "pcre_jit_stack_alloc", pcreImport.}
-proc jit_stack_free*(a2: ptr Tjit_stack){.cdecl, importc: "pcre_jit_stack_free",
-    pcreImport.}
-proc assign_jit_stack*(a2: ptr TExtra, a3: TJitCallback, a4: pointer){.cdecl,
-    importc: "pcre_assign_jit_stack", pcreImport.}
+proc jit_stack_alloc*(startsize: cint,
+                      maxsize: cint): ptr JitStack
+
+proc jit_stack_free*(stack: ptr JitStack)
+
+proc assign_jit_stack*(extra: ptr ExtraData,
+                       callback: JitCallback,
+                       data: pointer)
+
+proc jit_free_unused_memory*()
+
+
+# There was an odd function with `var cstring` instead of `ptr`
+proc study*(code: ptr Pcre,
+            options: cint,
+            errptr: var cstring): ptr ExtraData {.deprecated.}
+
+{.pop.}
+{.pop.}
+
+
+{.deprecated: [MAJOR: PCRE_MAJOR, MINOR: PCRE_MINOR,
+               PRERELEASE: PCRE_PRERELEASE, DATE: PCRE_DATE].}
+
+{.deprecated: [TPcre: Pcre, TJitStack: JitStack].}
+type
+  PPcre* {.deprecated.} = ptr Pcre
+  PJitStack* {.deprecated.} = ptr JitStack
 
-var 
-  pcre_free*: proc (p: ptr TPcre) {.cdecl.} 
+{.deprecated: [TExtra: ExtraData].}
+{.deprecated: [TCalloutBlock: CalloutBlock].}
+{.deprecated: [TJitCallback: JitCallback].}
diff --git a/tests/bind/tnicerrorforsymchoice.nim b/tests/bind/tnicerrorforsymchoice.nim
index bf6d92927..5145fdcff 100644
--- a/tests/bind/tnicerrorforsymchoice.nim
+++ b/tests/bind/tnicerrorforsymchoice.nim
@@ -1,17 +1,17 @@
 discard """
   line: 18
-  errormsg: "type mismatch: got (proc (TScgi) | proc (AsyncSocket, StringTableRef, string)"
+  errormsg: "type mismatch: got (proc (s: TScgi) | proc (client: AsyncSocket, headers: StringTableRef, input: string){.gcsafe, locks: 0.}"
 """
 
 #bug #442
 import scgi, sockets, asyncio, strtabs
 proc handleSCGIRequest[TScgi: ScgiState | AsyncScgiState](s: TScgi) =
   discard
-proc handleSCGIRequest(client: AsyncSocket, headers: StringTableRef, 
+proc handleSCGIRequest(client: AsyncSocket, headers: StringTableRef,
                        input: string) =
   discard
 
-proc test(handle: proc (client: AsyncSocket, headers: StringTableRef, 
+proc test(handle: proc (client: AsyncSocket, headers: StringTableRef,
                         input: string), b: int) =
   discard
 
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/closure/tinvalidclosure.nim b/tests/closure/tinvalidclosure.nim
index 18968a6c6..c9136a736 100644
--- a/tests/closure/tinvalidclosure.nim
+++ b/tests/closure/tinvalidclosure.nim
@@ -1,6 +1,6 @@
 discard """
   line: 12
-  errormsg: "type mismatch: got (proc (int){.closure, gcsafe, locks: 0.})"
+  errormsg: "type mismatch: got (proc (x: int){.closure, gcsafe, locks: 0.})"
 """
 
 proc ugh[T](x: T) {.closure.} =
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/collections/tsets.nim b/tests/collections/tsets.nim
index 656c5b3f2..a5bbe8dbd 100644
--- a/tests/collections/tsets.nim
+++ b/tests/collections/tsets.nim
@@ -1,17 +1,37 @@
-discard """
-  output: '''true
-true'''
-"""
-
 import sets
-var
-  a = initSet[int]()
-  b = initSet[int]()
-  c = initSet[string]()
 
-for i in 0..5: a.incl(i)
-for i in 1..6: b.incl(i)
-for i in 0..5: c.incl($i)
+block setEquality:
+  var
+    a = initSet[int]()
+    b = initSet[int]()
+    c = initSet[string]()
+
+  for i in 0..5: a.incl(i)
+  for i in 1..6: b.incl(i)
+  for i in 0..5: c.incl($i)
+
+  doAssert map(a, proc(x: int): int = x + 1) == b
+  doAssert map(a, proc(x: int): string = $x) == c
+
+
+block setsContainingTuples:
+  var set = initSet[tuple[i: int, i64: int64, f: float]]()
+  set.incl( (i: 123, i64: 123'i64, f: 3.14) )
+  doAssert set.contains( (i: 123, i64: 123'i64, f: 3.14) )
+  doAssert( not set.contains( (i: 456, i64: 789'i64, f: 2.78) ) )
+
+
+block setWithTuplesWithSeqs:
+  var s = initSet[tuple[s: seq[int]]]()
+  s.incl( (s: @[1, 2, 3]) )
+  doAssert s.contains( (s: @[1, 2, 3]) )
+  doAssert( not s.contains((s: @[4, 5, 6])) )
+
+
+block setWithSequences:
+  var s = initSet[seq[int]]()
+  s.incl( @[1, 2, 3] )
+  doAssert s.contains(@[1, 2, 3])
+  doAssert( not s.contains(@[4, 5, 6]) )
+
 
-echo map(a, proc(x: int): int = x + 1) == b
-echo map(a, proc(x: int): string = $x) == c
diff --git a/tests/collections/ttables.nim b/tests/collections/ttables.nim
index 3a923610e..a10606843 100644
--- a/tests/collections/ttables.nim
+++ b/tests/collections/ttables.nim
@@ -22,15 +22,15 @@ const
     "---00": 346677844,
     "0": 34404,
     "1": 344004,
-    "10": 34484, 
+    "10": 34484,
     "11": 34474,
     "12": 789,
     "19": 34464,
-    "2": 344774, "20": 34454, 
+    "2": 344774, "20": 34454,
     "3": 342244, "30": 34141244,
     "34": 123456,
     "4": 3412344, "40": 344114,
-    "5": 341232144, "50": 344490, 
+    "5": 341232144, "50": 344490,
     "6": 34214544, "60": 344491,
     "7": 3434544, "70": 344492,
     "8": 344544, "80": 344497,
@@ -46,7 +46,7 @@ block tableTest1:
   for x in 0..1:
     for y in 0..1:
       assert t[(x,y)] == $x & $y
-  assert($t == 
+  assert($t ==
     "{(x: 0, y: 1): 01, (x: 0, y: 0): 00, (x: 1, y: 0): 10, (x: 1, y: 1): 11}")
 
 block tableTest2:
@@ -55,14 +55,16 @@ block tableTest2:
   t["111"] = 1.000043
   t["123"] = 1.23
   t.del("111")
-  
+
   t["012"] = 67.9
   t["123"] = 1.5 # test overwriting
-  
+
   assert t["123"] == 1.5
   assert t["111"] == 0.0 # deleted
   assert(not hasKey(t, "111"))
-  
+  assert "123" in t
+  assert("111" notin t)
+
   for key, val in items(data): t[key] = val.toFloat
   for key, val in items(data): assert t[key] == val.toFloat
 
diff --git a/tests/collections/ttablesref.nim b/tests/collections/ttablesref.nim
index 16b0d831e..0b641ebc7 100644
--- a/tests/collections/ttablesref.nim
+++ b/tests/collections/ttablesref.nim
@@ -22,15 +22,15 @@ const
     "---00": 346677844,
     "0": 34404,
     "1": 344004,
-    "10": 34484, 
+    "10": 34484,
     "11": 34474,
     "12": 789,
     "19": 34464,
-    "2": 344774, "20": 34454, 
+    "2": 344774, "20": 34454,
     "3": 342244, "30": 34141244,
     "34": 123456,
     "4": 3412344, "40": 344114,
-    "5": 341232144, "50": 344490, 
+    "5": 341232144, "50": 344490,
     "6": 34214544, "60": 344491,
     "7": 3434544, "70": 344492,
     "8": 344544, "80": 344497,
@@ -46,7 +46,7 @@ block tableTest1:
   for x in 0..1:
     for y in 0..1:
       assert t[(x,y)] == $x & $y
-  assert($t == 
+  assert($t ==
     "{(x: 0, y: 1): 01, (x: 0, y: 0): 00, (x: 1, y: 0): 10, (x: 1, y: 1): 11}")
 
 block tableTest2:
@@ -55,17 +55,19 @@ block tableTest2:
   t["111"] = 1.000043
   t["123"] = 1.23
   t.del("111")
-  
+
   t["012"] = 67.9
   t["123"] = 1.5 # test overwriting
-  
+
   assert t["123"] == 1.5
   assert t["111"] == 0.0 # deleted
+  assert "123" in t
   assert(not hasKey(t, "111"))
-  
+  assert "111" notin t
+
   for key, val in items(data): t[key] = val.toFloat
   for key, val in items(data): assert t[key] == val.toFloat
-  
+
 
 block orderedTableTest1:
   var t = newOrderedTable[string, int](2)
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/cpp/tget_subsystem.nim b/tests/cpp/tget_subsystem.nim
new file mode 100644
index 000000000..461914739
--- /dev/null
+++ b/tests/cpp/tget_subsystem.nim
@@ -0,0 +1,23 @@
+discard """
+  cmd: "nim cpp $file"
+"""
+
+{.emit: """
+
+namespace System {
+  struct Input {};
+}
+
+struct SystemManager {
+  template <class T>
+  static T* getSubsystem() { return new T; }
+};
+
+""".}
+
+type Input {.importcpp: "System::Input".} = object
+proc getSubsystem*[T](): ptr T {.
+  importcpp: "SystemManager::getSubsystem<'*0>()", nodecl.}
+
+let input: ptr Input = getSubsystem[Input]()
+
diff --git a/tests/cpp/tvector_iterator.nim b/tests/cpp/tvector_iterator.nim
new file mode 100644
index 000000000..cb5ab33af
--- /dev/null
+++ b/tests/cpp/tvector_iterator.nim
@@ -0,0 +1,19 @@
+discard """
+  cmd: "nim cpp $file"
+"""
+
+{.emit: """
+
+template <class T>
+struct Vector {
+  struct Iterator {};
+};
+
+""".}
+
+type
+  Vector {.importcpp: "Vector".} [T] = object
+  VectorIterator {.importcpp: "Vector<'0>::Iterator".} [T] = object
+
+var x: VectorIterator[void]
+
diff --git a/tests/cpp/tvectorseq.nim b/tests/cpp/tvectorseq.nim
new file mode 100644
index 000000000..6eb5dc9e4
--- /dev/null
+++ b/tests/cpp/tvectorseq.nim
@@ -0,0 +1,38 @@
+discard """
+  output: '''(x: 1.0)
+(x: 0.0)'''
+  cmd: "nim cpp $file"
+  disabled: "true"
+"""
+
+# This cannot work yet because we omit type information for importcpp'ed types.
+# Fixing this is not hard, but also requires fixing Urhonimo.
+
+# bug #2536
+
+{.emit: """/*TYPESECTION*/
+struct Vector3 {
+public:
+  Vector3(): x(5) {}
+  Vector3(float x_): x(x_) {}
+  float x;
+};
+""".}
+
+type Vector3 {.importcpp: "Vector3", nodecl} = object
+  x: cfloat
+
+proc constructVector3(a: cfloat): Vector3 {.importcpp: "Vector3(@)", nodecl}
+
+# hack around another codegen issue: Generics are attached to where they came
+# from:
+proc `$!`(v:  seq[Vector3]): string = "(x: " & $v[0].x & ")"
+
+proc vec3List*(): seq[Vector3] =
+  let s = @[constructVector3(cfloat(1))]
+  echo($!s)
+  result = s
+  echo($!result)
+
+let f = vec3List()
+#echo($!f)
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/texceptions.nim b/tests/exception/texceptions.nim
index 69b2d0f6a..bdf338599 100644
--- a/tests/exception/texceptions.nim
+++ b/tests/exception/texceptions.nim
@@ -35,9 +35,9 @@ echo ""
 proc reraise_in_except =
   try:
     echo "BEFORE"
-    raise newException(EIO, "")
+    raise newException(IOError, "")
 
-  except EIO:
+  except IOError:
     echo "EXCEPT"
     raise
 
@@ -52,7 +52,7 @@ echo ""
 proc return_in_except =
   try:
     echo "BEFORE"
-    raise newException(EIO, "")
+    raise newException(IOError, "")
 
   except:
     echo "EXCEPT"
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/exception/treraise.nim b/tests/exception/treraise.nim
index cbd0b5f8a..b2a11d34f 100644
--- a/tests/exception/treraise.nim
+++ b/tests/exception/treraise.nim
@@ -4,8 +4,8 @@ discard """
   exitcode: "1"
 """
 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!":
diff --git a/tests/js/tstringitems.nim b/tests/js/tstringitems.nim
new file mode 100644
index 000000000..f4ea02fec
--- /dev/null
+++ b/tests/js/tstringitems.nim
@@ -0,0 +1,24 @@
+discard """
+  output: '''Hello
+Hello'''
+"""
+
+# bug #2581
+
+const someVars = [ "Hello" ]
+var someVars2 = [ "Hello" ]
+
+proc getSomeVar: string =
+    for i in someVars:
+        if i == "Hello":
+            result = i
+            break
+
+proc getSomeVar2: string =
+    for i in someVars2:
+        if i == "Hello":
+            result = i
+            break
+
+echo getSomeVar()
+echo getSomeVar2()
diff --git a/tests/js/tunittests.nim b/tests/js/tunittests.nim
index af38cd9b9..8a264a5e0 100644
--- a/tests/js/tunittests.nim
+++ b/tests/js/tunittests.nim
@@ -1,3 +1,10 @@
+discard """
+  disabled: "true"
+"""
+
+# Unittest uses lambdalifting at compile-time which we disable for the JS
+# codegen! So this cannot and will not work for quite some time.
+
 import unittest
 
 suite "Bacon":
diff --git a/tests/macros/tgettype.nim b/tests/macros/tgettype.nim
new file mode 100644
index 000000000..0eab6c0a0
--- /dev/null
+++ b/tests/macros/tgettype.nim
@@ -0,0 +1,20 @@
+discard """
+msg: '''ObjectTy(Sym(Model), RecList(Sym(name), Sym(password)))
+BracketExpr(Sym(typeDesc), Sym(User))'''
+"""
+import strutils, macros
+
+type
+  Model = object of RootObj
+  User = object of Model
+    name : string
+    password : string
+
+macro testUser: expr =
+  return newLit(User.getType.lispRepr)
+
+macro testGeneric(T: typedesc[Model]): expr =
+  return newLit(T.getType.lispRepr)
+
+echo testUser
+echo User.testGeneric
diff --git a/tests/macros/tlexerex.nim b/tests/macros/tlexerex.nim
new file mode 100644
index 000000000..d348a4bcc
--- /dev/null
+++ b/tests/macros/tlexerex.nim
@@ -0,0 +1,16 @@
+
+import macros
+
+macro match*(s: cstring|string; pos: int; sections: untyped): untyped =
+  for sec in sections.children:
+    expectKind sec, nnkOfBranch
+    expectLen sec, 2
+  result = newStmtList()
+
+when isMainModule:
+  var input = "the input"
+  var pos = 0
+  match input, pos:
+  of r"[a-zA-Z_]\w+": echo "an identifier"
+  of r"\d+": echo "an integer"
+  of r".": echo "something else"
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/macros/typesapi2.nim b/tests/macros/typesapi2.nim
index 016295ba4..2e59d2154 100644
--- a/tests/macros/typesapi2.nim
+++ b/tests/macros/typesapi2.nim
@@ -1,4 +1,4 @@
-# tests to see if a symbol returned from macros.getType() can 
+# tests to see if a symbol returned from macros.getType() can
 # be used as a type
 import macros
 
@@ -20,7 +20,7 @@ static: assert iii is TestFN
 
 proc foo11 : testTypesym(void) =
     echo "HI!"
-static: assert foo11 is proc():void
+static: assert foo11 is (proc():void {.nimcall.})
 
 var sss: testTypesym(seq[int])
 static: assert sss is seq[int]
diff --git a/tests/manyloc/standalone/panicoverride.nim b/tests/manyloc/standalone/panicoverride.nim
index efd2b21f9..d9b3f4388 100644
--- a/tests/manyloc/standalone/panicoverride.nim
+++ b/tests/manyloc/standalone/panicoverride.nim
@@ -7,13 +7,13 @@ proc exit(code: int) {.importc, header: "<stdlib.h>", cdecl.}
 proc rawoutput(s: string) =
   printf("%s\n", s)
 
-proc panic(s: string) =
+proc panic(s: string) {.noreturn.} =
   rawoutput(s)
   exit(1)
 
 # Alternatively we also could implement these 2 here:
 #
-# template sysFatal(exceptn: typeDesc, message: string)
-# template sysFatal(exceptn: typeDesc, message, arg: string)
+# proc sysFatal(exceptn: typeDesc, message: string) {.noReturn.}
+# proc sysFatal(exceptn: typeDesc, message, arg: string) {.noReturn.}
 
 {.pop.}
diff --git a/tests/metatype/ttypedesc3.nim b/tests/metatype/ttypedesc3.nim
new file mode 100644
index 000000000..3d40b25b2
--- /dev/null
+++ b/tests/metatype/ttypedesc3.nim
@@ -0,0 +1,19 @@
+import typetraits
+
+type
+  Base = object of RootObj
+  Child = object of Base
+
+proc pr(T: typedesc[Base]) = echo "proc " & T.name
+method me(T: typedesc[Base]) = echo "method " & T.name
+iterator it(T: typedesc[Base]) = yield "yield " & T.name
+
+Base.pr
+Child.pr
+
+Base.me
+when false:
+  Child.me #<- bug #2710
+
+for s in Base.it: echo s
+for s in Child.it: echo s #<- bug #2662
diff --git a/tests/misc/tunsigned64mod.nim b/tests/misc/tunsigned64mod.nim
index 9ae0d535a..3007405a2 100644
--- a/tests/misc/tunsigned64mod.nim
+++ b/tests/misc/tunsigned64mod.nim
@@ -10,3 +10,17 @@ let t1 = v1 mod 2 # works
 let t2 = 7'u64 mod 2'u64 # works
 let t3 = v2 mod 2'u64 # Error: invalid type: 'range 0..1(uint64)
 let t4 = (v2 mod 2'u64).uint64 # works
+
+# bug #2550
+
+var x: uint # doesn't work
+echo x mod 2 == 0
+
+var y: uint64 # doesn't work
+echo y mod 2 == 0
+
+var z: uint32 # works
+echo z mod 2 == 0
+
+var a: int # works
+echo a mod 2 == 0
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/parallel/twrong_refcounts.nim b/tests/parallel/twrong_refcounts.nim
new file mode 100644
index 000000000..db32a96d8
--- /dev/null
+++ b/tests/parallel/twrong_refcounts.nim
@@ -0,0 +1,53 @@
+discard """
+  output: "Success"
+"""
+
+import math, threadPool
+
+# ---
+
+type
+  Person = object
+    age: int
+    friend: ref Person
+
+var
+  people: seq[ref Person] = @[]
+
+proc newPerson(age:int): ref Person =
+  result.new()
+  result.age = age
+
+proc greet(p:Person) =
+  #echo p.age, ", ", p.friend.age
+  p.friend.age += 1
+
+# ---
+
+proc setup =
+  for i in 0 .. <20:
+    people.add newPerson(i + 1)
+  for i in 0 .. <20:
+    people[i].friend = people[random(20)]
+
+proc update =
+  var countA: array[20, int]
+  var countB: array[20, int]
+
+  for i, p in people:
+    countA[i] = getRefCount(p)
+  parallel:
+    for i in 0 .. people.high:
+      spawn greet(people[i][])
+  for i, p in people:
+    countB[i] = getRefCount(p)
+
+  for i in 0 .. <20:
+    doAssert countA[i] == countB[i]
+  echo "Success"
+
+# ---
+
+when isMainModule:
+  setup()
+  update()
diff --git a/tests/parser/tinvcolonlocation1.nim b/tests/parser/tinvcolonlocation1.nim
new file mode 100644
index 000000000..cacde48bd
--- /dev/null
+++ b/tests/parser/tinvcolonlocation1.nim
@@ -0,0 +1,12 @@
+discard """
+  file: "tinvcolonlocation1.nim"
+  line: 8
+  column: 3
+  errormsg: "':' expected"
+"""
+try #<- missing ':'
+  echo "try"
+except:
+  echo "except"
+finally:
+  echo "finally"
diff --git a/tests/parser/tinvcolonlocation2.nim b/tests/parser/tinvcolonlocation2.nim
new file mode 100644
index 000000000..2b6a92b9d
--- /dev/null
+++ b/tests/parser/tinvcolonlocation2.nim
@@ -0,0 +1,15 @@
+discard """
+  file: "tinvcolonlocation2.nim"
+  line: 11
+  column: 1
+  errormsg: "':' expected"
+"""
+try:
+  echo "try"
+except #<- missing ':'
+  echo "except"
+finally:
+#<-- error will be here above, at the beginning of finally,
+#    since compiler tries to consome echo and part of except
+#    expression
+  echo "finally"
diff --git a/tests/parser/tinvcolonlocation3.nim b/tests/parser/tinvcolonlocation3.nim
new file mode 100644
index 000000000..2b30b1dbe
--- /dev/null
+++ b/tests/parser/tinvcolonlocation3.nim
@@ -0,0 +1,12 @@
+discard """
+  file: "tinvcolonlocation3.nim"
+  line: 12
+  column: 3
+  errormsg: "':' expected"
+"""
+try:
+  echo "try"
+except:
+  echo "except"
+finally #<- missing ':'
+  echo "finally"
diff --git a/tests/parser/tstrongspaces.nim b/tests/parser/tstrongspaces.nim
index 568abda4c..e70b91988 100644
--- a/tests/parser/tstrongspaces.nim
+++ b/tests/parser/tstrongspaces.nim
@@ -15,6 +15,10 @@ true
 tester args
 all
 all args
+19
+-3
+false
+-2
 '''
 """
 
@@ -67,3 +71,13 @@ const
 echo tester & " " & args|"all"
 echo "all"  |  tester & " " & args
 echo "all"|tester & " " & args
+
+# Test arrow like operators. See also tests/macros/tclosuremacro.nim
+proc `+->`(a, b: int): int = a + b*4
+template `===>`(a, b: int): expr = a - b shr 1
+
+echo 3 +-> 2 + 2 and 4
+var arrowed = 3+->2 + 2 and 4  # arrowed = 4
+echo arrowed ===> 15
+echo (2 * 3+->2) == (2*3 +-> 2)
+echo arrowed ===> 2 + 3+->2
diff --git a/tests/parser/ttupleunpack.nim b/tests/parser/ttupleunpack.nim
new file mode 100644
index 000000000..aaa06f9f4
--- /dev/null
+++ b/tests/parser/ttupleunpack.nim
@@ -0,0 +1,35 @@
+discard """
+  file: "ttupleunpack.nim"
+  output: ""
+  exitcode: 0
+"""
+
+proc returnsTuple(): (int, int, int) = (4, 2, 3)
+
+proc main2 =
+  let (x, _, z) = returnsTuple()
+
+proc main() =
+
+  proc foo(): tuple[x, y, z: int] =
+    return (4, 2, 3)
+
+  var (x, _, y) = foo()
+  doAssert x == 4
+  doAssert y == 3
+
+  var (a, _, _) = foo()
+  doAssert a == 4
+
+  var (aa, _, _) = foo()
+  doAssert aa == 4
+
+  iterator bar(): tuple[x, y, z: int] =
+    yield (1,2,3)
+
+  for x, y, _ in bar():
+    doAssert x == 1
+    doAssert y == 2
+
+main()
+main2()
diff --git a/tests/readme.txt b/tests/readme.txt
index 0d33a81c7..2cfc79f9a 100644
--- a/tests/readme.txt
+++ b/tests/readme.txt
@@ -3,8 +3,11 @@ Each test must have a filename of the form: ``t*.nim``
 

 Each test can contain a spec in a ``discard """"""`` block.

 

-The folder ``rodfiles`` contains special tests that test incremental 

+The folder ``rodfiles`` contains special tests that test incremental

 compilation via symbol files.

 

 The folder ``dll`` contains simple DLL tests.

 

+The folder ``realtimeGC`` contains a test for validating that the realtime GC

+can run properly without linking against the nimrtl.dll/so. It includes a C

+client and platform specific build files for manual compilation.

diff --git a/tests/realtimeGC/cmain.c b/tests/realtimeGC/cmain.c
new file mode 100644
index 000000000..e9a46d7ce
--- /dev/null
+++ b/tests/realtimeGC/cmain.c
@@ -0,0 +1,67 @@
+
+#ifdef WIN
+#include <windows.h>
+#else
+#include <dlfcn.h>
+#endif
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <time.h>
+
+#define RUNTIME (15*60)
+
+
+typedef void (*pFunc)(void);
+
+int main(int argc, char* argv[])
+{
+    int i;
+    void* hndl;
+    pFunc status;
+    pFunc count;
+    pFunc checkOccupiedMem;
+
+#ifdef WIN
+    hndl = (void*) LoadLibrary((char const*)"./tests/realtimeGC/shared.dll");
+    status = (pFunc)GetProcAddress((HMODULE) hndl, (char const*)"status");
+    count = (pFunc)GetProcAddress((HMODULE) hndl, (char const*)"count");
+    checkOccupiedMem = (pFunc)GetProcAddress((HMODULE) hndl, (char const*)"checkOccupiedMem");
+#else /* OSX || NIX */
+    hndl = (void*) dlopen((char const*)"./tests/realtimeGC/libshared.so", RTLD_LAZY);
+    status = (pFunc) dlsym(hndl, (char const*)"status");
+    count = (pFunc) dlsym(hndl, (char const*)"count");
+    checkOccupiedMem = (pFunc) dlsym(hndl, (char const*)"checkOccupiedMem");
+#endif
+
+    assert(hndl);
+    assert(status);
+    assert(count);
+    assert(checkOccupiedMem);
+
+    time_t startTime = time((time_t*)0);
+    time_t runTime = (time_t)(RUNTIME);
+    time_t accumTime = 0;
+    while (accumTime < runTime) {
+        for (i = 0; i < 10; i++)
+            count();
+        /* printf("1. sleeping...\n"); */
+        sleep(1);
+        for (i = 0; i < 10; i++)
+            status();
+        /* printf("2. sleeping...\n"); */
+        sleep(1);
+        checkOccupiedMem();
+        accumTime = time((time_t*)0) - startTime;
+        /* printf("--- Minutes left to run: %d\n", (int)(runTime-accumTime)/60); */
+    }
+    printf("Cleaning up the shared object pointer...\n");
+#ifdef WIN
+    FreeLibrary((HMODULE)hndl);
+#else /* OSX || NIX */
+    dlclose(hndl);
+#endif
+    printf("Done\n");
+    return 0;
+}
diff --git a/tests/realtimeGC/main.nim.cfg b/tests/realtimeGC/main.nim.cfg
new file mode 100644
index 000000000..fed4fa471
--- /dev/null
+++ b/tests/realtimeGC/main.nim.cfg
@@ -0,0 +1,6 @@
+
+--app:console
+--threads:on
+
+-d:release
+-d:useRealtimeGC
diff --git a/tests/realtimeGC/nmain.nim b/tests/realtimeGC/nmain.nim
new file mode 100644
index 000000000..c9f558dbc
--- /dev/null
+++ b/tests/realtimeGC/nmain.nim
@@ -0,0 +1,46 @@
+discard """
+  cmd: "nim $target --debuginfo $options $file"
+  output: "Done"
+"""
+
+import times, os, threadpool
+
+const RUNTIME = 15 * 60 # 15 minutes
+
+when defined(windows):
+  const dllname = "./tests/realtimeGC/shared.dll"
+elif defined(macosx):
+  const dllname = "./tests/realtimeGC/libshared.dylib"
+else:
+  const dllname = "./tests/realtimeGC/libshared.so"
+
+proc status() {.importc: "status", dynlib: dllname.}
+proc count() {.importc: "count", dynlib: dllname.}
+proc checkOccupiedMem() {.importc: "checkOccupiedMem", dynlib: dllname.}
+
+proc process() =
+  let startTime = getTime()
+  let runTime = cast[Time](RUNTIME) #
+  var accumTime: Time
+  while accumTime < runTime:
+    for i in 0..10:
+      count()
+    # echo("1. sleeping... ")
+    sleep(500)
+    for i in 0..10:
+      status()
+    # echo("2. sleeping... ")
+    sleep(500)
+    checkOccupiedMem()
+    accumTime = cast[Time]((getTime() - startTime))
+    # echo("--- Minutes left to run: ", int(int(runTime-accumTime)/60))
+
+proc main() =
+  process()
+  # parallel:
+  #   for i in 0..0:
+  #     spawn process()
+  # sync()
+  echo("Done")
+
+main()
diff --git a/tests/realtimeGC/readme.txt b/tests/realtimeGC/readme.txt
new file mode 100644
index 000000000..035a00001
--- /dev/null
+++ b/tests/realtimeGC/readme.txt
@@ -0,0 +1,21 @@
+Test the realtime GC without linking nimrtl.dll/so.

+

+Note, this is a long running test, default is 35 minutes. To change the

+the run time see RUNTIME in main.nim and main.c.

+

+You can build shared.nim, main.nim, and main.c by running make (nix systems)

+or maike.bat (Windows systems). They both assume GCC and that it's in your

+path. Output: shared.(dll/so), camin(.exe), nmain(.exe).

+

+To run the test: execute either nmain or cmain in a shell window.

+

+To build buy hand:

+

+  - build the shared object (shared.nim):

+

+    $ nim c shared.nim

+

+  - build the client executables:

+

+    $ nim c -o:nmain main.nim

+    $ gcc -o cmain main.c -ldl

diff --git a/tests/realtimeGC/shared.nim b/tests/realtimeGC/shared.nim
new file mode 100644
index 000000000..2d1dd6c3c
--- /dev/null
+++ b/tests/realtimeGC/shared.nim
@@ -0,0 +1,63 @@
+discard """
+  cmd: "nim $target --debuginfo --hints:on --app:lib $options $file"
+"""
+
+import strutils
+
+# Global state, accessing with threads, no locks. Don't do this at
+# home.
+var gCounter: uint64
+var gTxStatus: bool
+var gRxStatus: bool
+var gConnectStatus: bool
+var gPttStatus: bool
+var gComm1Status: bool
+var gComm2Status: bool
+
+proc getTxStatus(): string =
+  result = if gTxStatus: "On" else: "Off"
+  gTxStatus = not gTxStatus
+
+proc getRxStatus(): string =
+  result = if gRxStatus: "On" else: "Off"
+  gRxStatus = not gRxStatus
+
+proc getConnectStatus(): string =
+  result = if gConnectStatus: "Yes" else: "No"
+  gConnectStatus = not gConnectStatus
+
+proc getPttStatus(): string =
+  result = if gPttStatus: "PTT: On" else: "PTT: Off"
+  gPttStatus = not gPttStatus
+
+proc getComm1Status(): string =
+  result = if gComm1Status: "On" else: "Off"
+  gComm1Status = not gComm1Status
+
+proc getComm2Status(): string =
+  result = if gComm2Status: "On" else: "Off"
+  gComm2Status = not gComm2Status
+
+proc status() {.exportc: "status", dynlib.} =
+  var tx_status = getTxStatus()
+  var rx_status = getRxStatus()
+  var connected = getConnectStatus()
+  var ptt_status = getPttStatus()
+  var str1: string = "[PilotEdge] Connected: $1  TX: $2  RX: $3" % [connected, tx_status, rx_status]
+  var a = getComm1Status()
+  var b = getComm2Status()
+  var str2: string = "$1  COM1: $2  COM2: $3" % [ptt_status, a, b]
+  # echo(str1)
+  # echo(str2)
+
+proc count() {.exportc: "count", dynlib.} =
+  var temp: uint64
+  for i in 0..100_000:
+    temp += 1
+  gCounter += 1
+  # echo("gCounter: ", gCounter)
+
+proc checkOccupiedMem() {.exportc: "checkOccupiedMem", dynlib.} =
+  if getOccupiedMem() > 10_000_000:
+    quit 1
+  discard
diff --git a/tests/realtimeGC/shared.nim.cfg b/tests/realtimeGC/shared.nim.cfg
new file mode 100644
index 000000000..e153b26fa
--- /dev/null
+++ b/tests/realtimeGC/shared.nim.cfg
@@ -0,0 +1,5 @@
+--app:lib
+--threads:on
+
+-d:release
+-d:useRealtimeGC
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/template/tstmt_semchecked_twice.nim b/tests/template/tstmt_semchecked_twice.nim
new file mode 100644
index 000000000..05c16c3c9
--- /dev/null
+++ b/tests/template/tstmt_semchecked_twice.nim
@@ -0,0 +1,30 @@
+
+# bug #2585
+
+type
+    RenderPass = object
+       state: ref int
+
+    RenderData* = object
+        fb: int
+        walls: seq[RenderPass]
+
+    Mat2 = int
+    Vector2[T] = T
+    Pixels=int
+
+template use*(fb: int, st: stmt) : stmt =
+    echo "a ", $fb
+    st
+    echo "a ", $fb
+
+proc render(rdat: var RenderData; passes: var openarray[RenderPass]; proj: Mat2;
+            indexType = 1) =
+    for i in 0 .. <len(passes):
+        echo "blah ", repr(passes[i])
+
+
+
+proc render2*(rdat: var RenderData; screenSz: Vector2[Pixels]; proj: Mat2) =
+    use rdat.fb:
+        render(rdat, rdat.walls, proj, 1)
diff --git a/tests/testament/categories.nim b/tests/testament/categories.nim
index 4476fccf2..4de1edeee 100644
--- a/tests/testament/categories.nim
+++ b/tests/testament/categories.nim
@@ -138,6 +138,18 @@ proc gcTests(r: var TResults, cat: Category, options: string) =
   test "stackrefleak"
   test "cyclecollector"
 
+proc longGCTests(r: var TResults, cat: Category, options: string) =
+  when defined(windows):
+    let cOptions = "gcc -ldl -DWIN"
+  else:
+    let cOptions = "gcc -ldl"
+
+  var c = initResults()
+  # According to ioTests, this should compile the file
+  testNoSpec c, makeTest("tests/realtimeGC/shared", options, cat, actionCompile)
+  testC r, makeTest("tests/realtimeGC/cmain", cOptions, cat, actionRun)
+  testSpec r, makeTest("tests/realtimeGC/nmain", options & "--threads: on", cat, actionRun)
+
 # ------------------------- threading tests -----------------------------------
 
 proc threadTests(r: var TResults, cat: Category, options: string) =
@@ -226,7 +238,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)
 
@@ -340,6 +352,8 @@ proc processCategory(r: var TResults, cat: Category, options: string) =
     dllTests(r, cat, options)
   of "gc":
     gcTests(r, cat, options)
+  of "longgc":
+    longGCTests(r, cat, options)
   of "debugger":
     debuggerTests(r, cat, options)
   of "manyloc":
diff --git a/tests/testament/specs.nim b/tests/testament/specs.nim
index 2a8a4ea24..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
@@ -42,7 +43,8 @@ type
     action*: TTestAction
     file*, cmd*: string
     outp*: string
-    line*, exitCode*: int
+    line*, column*: int
+    exitCode*: int
     msg*: string
     ccodeCheck*: string
     err*: TResultEnum
@@ -77,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)
@@ -91,13 +93,18 @@ 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 = ""
   result.ccodeCheck = ""
   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":
@@ -108,7 +115,8 @@ proc parseSpec*(filename: string): TSpec =
       else: echo ignoreMsg(p, e)
     of "file": result.file = e.value
     of "line": discard parseInt(e.value, result.line)
-    of "output": 
+    of "column": discard parseInt(e.value, result.column)
+    of "output":
       result.action = actionRun
       result.outp = e.value
     of "outputsub":
@@ -117,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 7391b105e..0308ce940 100644
--- a/tests/testament/tester.nim
+++ b/tests/testament/tester.nim
@@ -50,7 +50,7 @@ type
 
 let
   pegLineError =
-    peg"{[^(]*} '(' {\d+} ', ' \d+ ') ' ('Error') ':' \s* {.*}"
+    peg"{[^(]*} '(' {\d+} ', ' {\d+} ') ' ('Error') ':' \s* {.*}"
   pegOtherError = peg"'Error:' \s* {.*}"
   pegSuccess = peg"'Hint: operation successful'.*"
   pegOfInterest = pegLineError / pegOtherError
@@ -77,16 +77,37 @@ proc callCompiler(cmdTemplate, filename, options: string,
   result.msg = ""
   result.file = ""
   result.outp = ""
-  result.line = -1
+  result.line = 0
+  result.column = 0
   if err =~ pegLineError:
     result.file = extractFilename(matches[0])
     result.line = parseInt(matches[1])
-    result.msg = matches[2]
+    result.column = parseInt(matches[2])
+    result.msg = matches[3]
   elif err =~ pegOtherError:
     result.msg = matches[0]
   elif suc =~ pegSuccess:
     result.err = reSuccess
 
+proc callCCompiler(cmdTemplate, filename, options: string,
+                  target: TTarget): TSpec =
+  let c = parseCmdLine(cmdTemplate % ["target", targetToCmd[target],
+                       "options", options, "file", filename.quoteShell])
+  var p = startProcess(command="gcc", args=c[5.. ^1],
+                       options={poStdErrToStdOut, poUsePath})
+  let outp = p.outputStream
+  var x = newStringOfCap(120)
+  result.nimout = ""
+  result.msg = ""
+  result.file = ""
+  result.outp = ""
+  result.line = -1
+  while outp.readLine(x.TaintedString) or running(p):
+    result.nimout.add(x & "\n")
+  close(p)
+  if p.peekExitCode == 0:
+    result.err = reSuccess
+
 proc initResults: TResults =
   result.total = 0
   result.passed = 0
@@ -130,8 +151,11 @@ proc cmpMsgs(r: var TResults, expected, given: TSpec, test: TTest) =
   elif extractFilename(expected.file) != extractFilename(given.file) and
       "internal error:" notin expected.msg:
     r.addResult(test, expected.file, given.file, reFilesDiffer)
-  elif expected.line != given.line and expected.line != 0:
-    r.addResult(test, $expected.line, $given.line, reLinesDiffer)
+  elif expected.line   != given.line   and expected.line   != 0 or
+       expected.column != given.column and expected.column != 0:
+    r.addResult(test, $expected.line & ':' & $expected.column,
+                      $given.line    & ':' & $given.column,
+                      reLinesDiffer)
   else:
     r.addResult(test, expected.msg, given.msg, reSuccess)
     inc(r.passed)
@@ -191,7 +215,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)
@@ -201,7 +230,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:
@@ -247,8 +276,22 @@ proc testNoSpec(r: var TResults, test: TTest) =
   r.addResult(test, "", given.msg, given.err)
   if given.err == reSuccess: inc(r.passed)
 
+proc testC(r: var TResults, test: TTest) =
+  # runs C code. Doesn't support any specs, just goes by exit code.
+  let tname = test.name.addFileExt(".c")
+  inc(r.total)
+  styledEcho "Processing ", fgCyan, extractFilename(tname)
+  var given = callCCompiler(cmdTemplate, test.name & ".c", test.options, test.target)
+  if given.err != reSuccess:
+    r.addResult(test, "", given.msg, given.err)
+  elif test.action == actionRun:
+    let exeFile = changeFileExt(test.name, ExeExt)
+    var (buf, exitCode) = execCmdEx(exeFile, options = {poStdErrToStdOut, poUseShell})
+    if exitCode != 0: given.err = reExitCodesDiffer
+  if given.err == reSuccess: inc(r.passed)
+
 proc makeTest(test, options: string, cat: Category, action = actionCompile,
-              target = targetC): TTest =
+              target = targetC, env: string = ""): TTest =
   # start with 'actionCompile', will be overwritten in the spec:
   result = TTest(cat: cat, name: test, options: options,
                  target: target, action: action)
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/tests/types/tisopr.nim b/tests/types/tisopr.nim
index 8b7fe4e46..b9acfa5fb 100644
--- a/tests/types/tisopr.nim
+++ b/tests/types/tisopr.nim
@@ -1,5 +1,11 @@
 discard """
-  output: '''true true false yes'''
+  output: '''true true false yes
+false
+false
+false
+true
+true
+no'''
 """
 
 proc IsVoid[T](): string =
@@ -28,7 +34,7 @@ no  s.items is iterator: float
 yes s.items is iterator: TNumber
 no  s.items is iterator: object
 
-type 
+type
   Iter[T] = iterator: T
 
 yes s.items is Iter[TNumber]
@@ -51,3 +57,34 @@ yes Foo[4, int] is Bar[int]
 no Foo[4, int] is Baz[4]
 yes Foo[4, float] is Baz[4]
 
+
+# bug #2505
+
+echo(8'i8 is int32)
+
+# bug #1853
+type SeqOrSet[E] = seq[E] or set[E]
+type SeqOfInt = seq[int]
+type SeqOrSetOfInt = SeqOrSet[int]
+
+# This prints "false", which seems less correct that (1) printing "true" or (2)
+# raising a compiler error.
+echo seq is SeqOrSet
+
+# This prints "false", as expected.
+echo seq is SeqOrSetOfInt
+
+# This prints "true", as expected.
+echo SeqOfInt is SeqOrSet
+
+# This causes an internal error (filename: compiler/semtypes.nim, line: 685).
+echo SeqOfInt is SeqOrSetOfInt
+
+# bug #2522
+proc test[T](x: T) =
+  when T is typedesc:
+    echo "yes"
+  else:
+    echo "no"
+
+test(7)
diff --git a/todo.txt b/todo.txt
index a61f932a9..4972015a7 100644
--- a/todo.txt
+++ b/todo.txt
@@ -1,7 +1,21 @@
-version 0.10.4
+version 0.11.2
 ==============
 
-- make 'nil' work for 'add' and 'len'
+- 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 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
 ===========
@@ -35,8 +49,6 @@ Low priority:
 Misc
 ----
 
-- make '--implicitStatic:on' the default; then we can also clean up the
-  'static[T]' mess in the compiler!
 - make tuple unpacking work in a non-var/let context
 - built-in 'getImpl'
 - prevent 'alloc(TypeWithGCedMemory)'
@@ -50,6 +62,7 @@ Bugs
 - scopes are still broken for generic instantiation!
 - blocks can "export" an identifier but the CCG generates {} for them ...
 - ConcreteTypes in a 'case' means we don't check for duplicated case branches
+- typedesc matches a generic type T!
 
 
 version 0.9.x
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 af44f91a1..22ea03157 100644
--- a/web/news.txt
+++ b/web/news.txt
@@ -3,333 +3,428 @@ 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.
-  - 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 ``miliseconds`` property of ``times.TimeInterval`` is now ``milliseconds``.
+    Code accessing that property is deprecated and code using ``miliseconds``
+    during object initialization or as a named parameter of ``initInterval()``
+    will need to be updated.
 
   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!
+The 1.0 release is expected by the end of this year. Rumors say it will be in
+summer 2015. What's left:
 
+* 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.
 
+Changes affecting backwards compatibility
+-----------------------------------------
 
-  Bugfixes
-  --------
+- 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'
+..
+
+  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.
+- Added sexp.nim to parse and generate sexp.
+
+
+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"