summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorMichael Voronin <survivor.mail@gmail.com>2018-05-10 13:15:33 +0300
committerGitHub <noreply@github.com>2018-05-10 13:15:33 +0300
commit1051e8d69dbf71e93f653fecd8da3b8587e9b3d4 (patch)
treec9dde28d0d516ad5d0282766cc0ec44461abcef7
parent5ea967d97a30f0084883d4efa81b05bea3e5d148 (diff)
parent9048bcc54b5fe8d0ae8c24b9cf7454cfa897ce5a (diff)
downloadNim-1051e8d69dbf71e93f653fecd8da3b8587e9b3d4.tar.gz
Merge pull request #4 from nim-lang/devel
#4
-rw-r--r--changelog.md20
-rw-r--r--compiler/ast.nim15
-rw-r--r--compiler/astalgo.nim16
-rw-r--r--compiler/cgen.nim4
-rw-r--r--compiler/destroyer.nim1
-rw-r--r--compiler/docgen.nim6
-rw-r--r--compiler/evaltempl.nim2
-rw-r--r--compiler/filter_tmpl.nim27
-rw-r--r--compiler/importer.nim13
-rw-r--r--compiler/lexer.nim36
-rw-r--r--compiler/main.nim13
-rw-r--r--compiler/modules.nim2
-rw-r--r--compiler/msgs.nim216
-rw-r--r--compiler/nimconf.nim2
-rw-r--r--compiler/nimfix/pretty.nim2
-rw-r--r--compiler/nimfix/prettybase.nim2
-rw-r--r--compiler/options.nim1
-rw-r--r--compiler/parser.nim46
-rw-r--r--compiler/passes.nim2
-rw-r--r--compiler/pbraces.nim1790
-rw-r--r--compiler/plugins/locals/locals.nim2
-rw-r--r--compiler/pragmas.nim2
-rw-r--r--compiler/renderer.nim2
-rw-r--r--compiler/reorder.nim8
-rw-r--r--compiler/scriptconfig.nim2
-rw-r--r--compiler/sem.nim6
-rw-r--r--compiler/semdata.nim1
-rw-r--r--compiler/semexprs.nim39
-rw-r--r--compiler/semmagic.nim4
-rw-r--r--compiler/semstmts.nim9
-rw-r--r--compiler/sigmatch.nim14
-rw-r--r--compiler/syntaxes.nim29
-rw-r--r--compiler/types.nim4
-rw-r--r--compiler/vm.nim51
-rw-r--r--compiler/vmdef.nim8
-rw-r--r--compiler/vmgen.nim6
-rw-r--r--doc/manual.rst8
-rw-r--r--koch.nim2
-rw-r--r--lib/core/macros.nim2
-rw-r--r--lib/deprecated/pure/ftpclient.nim2
-rw-r--r--lib/packages/docutils/rst.nim4
-rw-r--r--lib/packages/docutils/rstast.nim3
-rw-r--r--lib/pure/algorithm.nim64
-rw-r--r--lib/pure/asyncfutures.nim2
-rw-r--r--lib/pure/asynchttpserver.nim3
-rw-r--r--lib/pure/asyncnet.nim2
-rw-r--r--lib/pure/cgi.nim2
-rw-r--r--lib/pure/collections/sets.nim14
-rw-r--r--lib/pure/colors.nim2
-rw-r--r--lib/pure/complex.nim2
-rw-r--r--lib/pure/db_common.nim3
-rw-r--r--lib/pure/dynlib.nim6
-rw-r--r--lib/pure/encodings.nim2
-rw-r--r--lib/pure/events.nim3
-rw-r--r--lib/pure/hashes.nim1
-rw-r--r--lib/pure/htmlparser.nim1
-rw-r--r--lib/pure/httpclient.nim18
-rw-r--r--lib/pure/httpcore.nim4
-rw-r--r--lib/pure/httpserver.nim2
-rw-r--r--lib/pure/includes/asynccommon.nim4
-rw-r--r--lib/pure/includes/oserr.nim44
-rw-r--r--lib/pure/json.nim15
-rw-r--r--lib/pure/lexbase.nim2
-rw-r--r--lib/pure/logging.nim4
-rw-r--r--lib/pure/marshal.nim1
-rw-r--r--lib/pure/math.nim18
-rw-r--r--lib/pure/memfiles.nim2
-rw-r--r--lib/pure/mersenne.nim2
-rw-r--r--lib/pure/mimetypes.nim2
-rw-r--r--lib/pure/nativesockets.nim5
-rw-r--r--lib/pure/net.nim11
-rw-r--r--lib/pure/nimprof.nim2
-rw-r--r--lib/pure/oids.nim6
-rw-r--r--lib/pure/options.nim8
-rw-r--r--lib/pure/os.nim16
-rw-r--r--lib/pure/ospaths.nim5
-rw-r--r--lib/pure/osproc.nim33
-rw-r--r--lib/pure/parsecfg.nim3
-rw-r--r--lib/pure/parsecsv.nim2
-rw-r--r--lib/pure/parseopt.nim2
-rw-r--r--lib/pure/parseopt2.nim4
-rw-r--r--lib/pure/parsesql.nim2
-rw-r--r--lib/pure/parseutils.nim2
-rw-r--r--lib/pure/parsexml.nim3
-rw-r--r--lib/pure/pegs.nim12
-rw-r--r--lib/pure/ropes.nim2
-rw-r--r--lib/pure/scgi.nim3
-rw-r--r--lib/pure/selectors.nim8
-rw-r--r--lib/pure/smtp.nim2
-rw-r--r--lib/pure/stats.nim2
-rw-r--r--lib/pure/streams.nim31
-rw-r--r--lib/pure/strtabs.nim19
-rw-r--r--lib/pure/strutils.nim532
-rw-r--r--lib/pure/subexes.nim3
-rw-r--r--lib/pure/terminal.nim73
-rw-r--r--lib/pure/times.nim22
-rw-r--r--lib/pure/uri.nim56
-rw-r--r--lib/pure/xmldom.nim21
-rw-r--r--lib/pure/xmlparser.nim2
-rw-r--r--lib/pure/xmltree.nim12
-rw-r--r--lib/system.nim5
-rw-r--r--lib/system/assign.nim12
-rw-r--r--lib/system/deepcopy.nim10
-rw-r--r--lib/system/gc.nim2
-rw-r--r--lib/system/osalloc.nim2
-rw-r--r--lib/system/sysstr.nim2
-rw-r--r--lib/wrappers/openssl.nim2
-rw-r--r--tests/async/tasyncawait.nim12
-rw-r--r--tests/collections/thashes.nim4
-rw-r--r--tests/collections/tsets.nim52
-rw-r--r--tests/exprs/tstmtexprs.nim2
-rw-r--r--tests/generics/module_with_generics.nim14
-rw-r--r--tests/generics/t5602_inheritence.nim8
-rw-r--r--tests/macros/tstructuredlogging.nim154
-rw-r--r--tests/macros/ttemplatesymbols.nim173
-rw-r--r--tests/misc/tsimplesort.nim10
-rw-r--r--tests/modules/definitions.nim4
-rw-r--r--tests/modules/proxy_module.nim3
-rw-r--r--tests/overload/tparam_forwarding.nim16
-rw-r--r--tests/parser/tbraces.nim432
-rw-r--r--tests/parser/tcommand_as_expr.nim13
-rw-r--r--tests/parser/twrongcmdsyntax.nim2
-rw-r--r--tests/stdlib/ttimes.nim6
-rw-r--r--tests/testament/tester.nim8
-rw-r--r--tests/threads/tthreadvars.nim78
-rw-r--r--tests/trmacros/thoist.nim2
-rw-r--r--tests/typerel/texplicitcmp.nim4
-rw-r--r--tests/vm/tref.nim12
-rw-r--r--tools/finish.nim27
-rw-r--r--tools/niminst/buildsh.tmpl4
130 files changed, 1469 insertions, 3159 deletions
diff --git a/changelog.md b/changelog.md
index 6cd0faf52..cbefbc421 100644
--- a/changelog.md
+++ b/changelog.md
@@ -17,6 +17,9 @@
 - The ``not nil`` type annotation now has to be enabled explicitly
   via ``{.experimental: "notnil"}`` as we are still not pleased with how this
   feature works with Nim's containers.
+- The parser now warns about inconsistent spacing around binary operators as
+  these can easily be confused with unary operators. This warning will likely
+  become an error in the future.
 
 
 #### Breaking changes in the standard library
@@ -38,6 +41,9 @@
 
 #### Breaking changes in the compiler
 
+- The undocumented ``#? braces`` parsing mode was removed.
+- The undocumented PHP backend was removed.
+
 ### Library additions
 
 - ``re.split`` now also supports the ``maxsplit`` parameter for consistency
@@ -63,6 +69,11 @@
   fields.
 - ``system.SomeReal`` is now called ``SomeFloat`` for consistency and
   correctness.
+- ``algorithm.smartBinarySearch`` and ``algorithm.binarySearch`` is
+  now joined in ``binarySearch``. ``smartbinarySearch`` is now
+  deprecated.
+- The `terminal` module now exports additional procs for generating ANSI color
+  codes as strings.
 
 ### Language additions
 
@@ -86,11 +97,18 @@
 
 - ``nil`` for strings/seqs is finally gone. Instead the default value for
   these is ``"" / @[]``.
+
 - Accessing the binary zero terminator in Nim's native strings
   is now invalid. Internally a Nim string still has the trailing zero for
   zero-copy interoperability with ``cstring``. Compile your code with the
-  next switch ``--laxStrings:on`` if you need a transition period.
+  new switch ``--laxStrings:on`` if you need a transition period.
+
+- The command syntax now supports keyword arguments after the first comma.
+
+- Thread-local variables can now be declared inside procs. This implies all
+  the effects of the `global` pragma.
 
+- Nim now supports `except` clause in the export statement.
 
 ### Tool changes
 
diff --git a/compiler/ast.nim b/compiler/ast.nim
index b8202abe6..2cace380d 100644
--- a/compiler/ast.nim
+++ b/compiler/ast.nim
@@ -1615,6 +1615,19 @@ proc originatingModule*(s: PSym): PSym =
 proc isRoutine*(s: PSym): bool {.inline.} =
   result = s.kind in skProcKinds
 
+proc isCompileTimeProc*(s: PSym): bool {.inline.} =
+  result = s.kind == skMacro or
+           s.kind == skProc and sfCompileTime in s.flags
+
+proc requiredParams*(s: PSym): int =
+  # Returns the number of required params (without default values)
+  # XXX: Perhaps we can store this in the `offset` field of the
+  # symbol instead?
+  for i in 1 ..< s.typ.len:
+    if s.typ.n[i].sym.ast != nil:
+      return i - 1
+  return s.typ.len - 1
+
 proc hasPattern*(s: PSym): bool {.inline.} =
   result = isRoutine(s) and s.ast.sons[patternPos].kind != nkEmpty
 
@@ -1671,7 +1684,7 @@ proc isException*(t: PType): bool =
 
   var base = t
   while base != nil:
-    if base.sym.magic == mException:
+    if base.sym != nil and base.sym.magic == mException:
       return true
     base = base.lastSon
   return false
diff --git a/compiler/astalgo.nim b/compiler/astalgo.nim
index 196ac8690..a35fa4fbb 100644
--- a/compiler/astalgo.nim
+++ b/compiler/astalgo.nim
@@ -69,22 +69,22 @@ proc debug*(n: PNode) {.deprecated.}
 
 template mdbg*: bool {.dirty.} =
   when compiles(c.module):
-    c.module.fileIdx == gProjectMainIdx
+    c.module.fileIdx.int32 == gProjectMainIdx
   elif compiles(c.c.module):
-    c.c.module.fileIdx == gProjectMainIdx
+    c.c.module.fileIdx.int32 == gProjectMainIdx
   elif compiles(m.c.module):
-    m.c.module.fileIdx == gProjectMainIdx
+    m.c.module.fileIdx.int32 == gProjectMainIdx
   elif compiles(cl.c.module):
-    cl.c.module.fileIdx == gProjectMainIdx
+    cl.c.module.fileIdx.int32 == gProjectMainIdx
   elif compiles(p):
     when compiles(p.lex):
-      p.lex.fileIdx == gProjectMainIdx
+      p.lex.fileIdx.int32 == gProjectMainIdx
     else:
-      p.module.module.fileIdx == gProjectMainIdx
+      p.module.module.fileIdx.int32 == gProjectMainIdx
   elif compiles(m.module.fileIdx):
-    m.module.fileIdx == gProjectMainIdx
+    m.module.fileIdx.int32 == gProjectMainIdx
   elif compiles(L.fileIdx):
-    L.fileIdx == gProjectMainIdx
+    L.fileIdx.int32 == gProjectMainIdx
   else:
     error()
 
diff --git a/compiler/cgen.nim b/compiler/cgen.nim
index ff3e6714d..693930fbc 100644
--- a/compiler/cgen.nim
+++ b/compiler/cgen.nim
@@ -265,7 +265,7 @@ proc rdCharLoc(a: TLoc): Rope =
 
 proc genObjectInit(p: BProc, section: TCProcSection, t: PType, a: TLoc,
                    takeAddr: bool) =
-  if p.module.compileToCpp and t.isException:
+  if p.module.compileToCpp and t.isException and not isDefined("noCppExceptions"):
     # init vtable in Exception object for polymorphic exceptions
     includeHeader(p.module, "<new>")
     linefmt(p, section, "new ($1) $2;$n", rdLoc(a), getTypeDesc(p.module, t))
@@ -746,7 +746,7 @@ proc genProcAux(m: BModule, prc: PSym) =
     else:
       fillResult(resNode)
       assignParam(p, res)
-      resetLoc(p, res.loc)
+      if sfNoInit notin prc.flags: resetLoc(p, res.loc)
       if skipTypes(res.typ, abstractInst).kind == tyArray:
         #incl(res.loc.flags, lfIndirect)
         res.loc.storage = OnUnknown
diff --git a/compiler/destroyer.nim b/compiler/destroyer.nim
index ffa3e37e5..cd16469de 100644
--- a/compiler/destroyer.nim
+++ b/compiler/destroyer.nim
@@ -430,6 +430,7 @@ proc injectDestructorCalls*(owner: PSym; n: PNode): PNode =
   c.tmp.typ = c.tmpObj
   c.destroys = newNodeI(nkStmtList, n.info)
   c.topLevelVars = newNodeI(nkVarSection, n.info)
+  c.toDropBit = initTable[int, PSym]()
   let cfg = constructCfg(owner, n)
   shallowCopy(c.g, cfg)
   c.jumpTargets = initIntSet()
diff --git a/compiler/docgen.nim b/compiler/docgen.nim
index 6f3dcde8b..e1a70a23e 100644
--- a/compiler/docgen.nim
+++ b/compiler/docgen.nim
@@ -790,7 +790,7 @@ proc writeOutputJson*(d: PDoc, filename, outExt: string,
       discard "fixme: error report"
 
 proc commandDoc*() =
-  var ast = parseFile(gProjectMainIdx.FileIndex, newIdentCache())
+  var ast = parseFile(gProjectMainIdx.FileIndex, newIdentCache(), newConfigRef())
   if ast == nil: return
   var d = newDocumentor(gProjectFull, options.gConfigVars)
   d.hasToc = true
@@ -840,7 +840,7 @@ proc commandRst2TeX*() =
   commandRstAux(gProjectFull, TexExt)
 
 proc commandJson*() =
-  var ast = parseFile(gProjectMainIdx.FileIndex, newIdentCache())
+  var ast = parseFile(gProjectMainIdx.FileIndex, newIdentCache(), newConfigRef())
   if ast == nil: return
   var d = newDocumentor(gProjectFull, options.gConfigVars)
   d.hasToc = true
@@ -855,7 +855,7 @@ proc commandJson*() =
     writeRope(content, getOutFile(gProjectFull, JsonExt), useWarning = false)
 
 proc commandTags*() =
-  var ast = parseFile(gProjectMainIdx.FileIndex, newIdentCache())
+  var ast = parseFile(gProjectMainIdx.FileIndex, newIdentCache(), newConfigRef())
   if ast == nil: return
   var d = newDocumentor(gProjectFull, options.gConfigVars)
   d.hasToc = true
diff --git a/compiler/evaltempl.nim b/compiler/evaltempl.nim
index fbb7eb2e6..502430815 100644
--- a/compiler/evaltempl.nim
+++ b/compiler/evaltempl.nim
@@ -63,7 +63,7 @@ proc evalTemplateArgs(n: PNode, s: PSym; fromHlo: bool): PNode =
   # if the template has zero arguments, it can be called without ``()``
   # `n` is then a nkSym or something similar
   var totalParams = case n.kind
-    of nkCall, nkInfix, nkPrefix, nkPostfix, nkCommand, nkCallStrLit: n.len-1
+    of nkCallKinds: n.len-1
     else: 0
 
   var
diff --git a/compiler/filter_tmpl.nim b/compiler/filter_tmpl.nim
index 51ccb8390..545bea950 100644
--- a/compiler/filter_tmpl.nim
+++ b/compiler/filter_tmpl.nim
@@ -45,7 +45,6 @@ proc scanPar(p: var TTmplParser, d: int) =
   let hi = p.x.len - 1
   while i <= hi:
     case p.x[i]
-    of '\0': break
     of '(': inc(p.par)
     of ')': dec(p.par)
     of '[': inc(p.bracket)
@@ -64,16 +63,22 @@ const
 
 proc parseLine(p: var TTmplParser) =
   var j = 0
-  while p.x[j] == ' ': inc(j)
+  let hi = p.x.len - 1
+
+  if hi == 0:
+    return
+
+  while j <= hi and p.x[j] == ' ': inc(j)
+
   if p.x[0] == p.nimDirective and p.x[1] == '?':
     newLine(p)
   elif p.x[j] == p.nimDirective:
     newLine(p)
     inc(j)
-    while p.x[j] == ' ': inc(j)
+    while j <= hi and p.x[j] == ' ': inc(j)
     let d = j
     var keyw = ""
-    while p.x[j] in PatternChars:
+    while j <= hi and p.x[j] in PatternChars:
       add(keyw, p.x[j])
       inc(j)
 
@@ -127,10 +132,8 @@ proc parseLine(p: var TTmplParser) =
       llStreamWrite(p.outp, "(\"")
       inc(p.emitPar)
     p.state = psTempl
-    while true:
+    while j <= hi:
       case p.x[j]
-      of '\0':
-        break
       of '\x01'..'\x1F', '\x80'..'\xFF':
         llStreamWrite(p.outp, "\\x")
         llStreamWrite(p.outp, toHex(ord(p.x[j]), 2))
@@ -157,11 +160,8 @@ proc parseLine(p: var TTmplParser) =
             llStreamWrite(p.outp, '(')
             inc(j)
             var curly = 0
-            while true:
+            while j <= hi:
               case p.x[j]
-              of '\0':
-                localError(p.info, errXExpected, "}")
-                break
               of '{':
                 inc(j)
                 inc(curly)
@@ -174,6 +174,9 @@ proc parseLine(p: var TTmplParser) =
               else:
                 llStreamWrite(p.outp, p.x[j])
                 inc(j)
+            if curly > 0:
+              localError(p.info, errXExpected, "}")
+              break
             llStreamWrite(p.outp, ')')
             llStreamWrite(p.outp, p.conc)
             llStreamWrite(p.outp, '\"')
@@ -182,7 +185,7 @@ proc parseLine(p: var TTmplParser) =
             llStreamWrite(p.outp, p.conc)
             llStreamWrite(p.outp, p.toStr)
             llStreamWrite(p.outp, '(')
-            while p.x[j] in PatternChars:
+            while j <= hi and p.x[j] in PatternChars:
               llStreamWrite(p.outp, p.x[j])
               inc(j)
             llStreamWrite(p.outp, ')')
diff --git a/compiler/importer.nim b/compiler/importer.nim
index f4903e6c4..a5c361864 100644
--- a/compiler/importer.nim
+++ b/compiler/importer.nim
@@ -16,6 +16,13 @@ import
 proc evalImport*(c: PContext, n: PNode): PNode
 proc evalFrom*(c: PContext, n: PNode): PNode
 
+proc readExceptSet*(n: PNode): IntSet =
+  assert n.kind in {nkImportExceptStmt, nkExportExceptStmt}
+  result = initIntSet()
+  for i in 1 ..< n.len:
+    let ident = lookups.considerQuotedIdent(n[i])
+    result.incl(ident.id)
+
 proc importPureEnumField*(c: PContext; s: PSym) =
   var check = strTableGet(c.importTable.symbols, s.name)
   if check == nil:
@@ -198,9 +205,5 @@ proc evalImportExcept*(c: PContext, n: PNode): PNode =
   if m != nil:
     n.sons[0] = newSymNode(m)
     addDecl(c, m, n.info)               # add symbol to symbol table of module
-    var exceptSet = initIntSet()
-    for i in countup(1, sonsLen(n) - 1):
-      let ident = lookups.considerQuotedIdent(n.sons[i])
-      exceptSet.incl(ident.id)
-    importAllSymbolsExcept(c, m, exceptSet)
+    importAllSymbolsExcept(c, m, readExceptSet(n))
     #importForwarded(c, m.ast, exceptSet)
diff --git a/compiler/lexer.nim b/compiler/lexer.nim
index 0478ed574..a65587390 100644
--- a/compiler/lexer.nim
+++ b/compiler/lexer.nim
@@ -144,13 +144,12 @@ type
     cache*: IdentCache
     when defined(nimsuggest):
       previousToken: TLineInfo
+    config*: ConfigRef
 
 when defined(nimpretty):
   var
     gIndentationWidth*: int
 
-var gLinesCompiled*: int  # all lines that have been compiled
-
 proc getLineInfo*(L: TLexer, tok: TToken): TLineInfo {.inline.} =
   result = newLineInfo(L.fileIdx, tok.line, tok.col)
   when defined(nimpretty):
@@ -222,7 +221,7 @@ proc fillToken(L: var TToken) =
     L.commentOffsetB = 0
 
 proc openLexer*(lex: var TLexer, fileIdx: FileIndex, inputstream: PLLStream;
-                 cache: IdentCache) =
+                 cache: IdentCache; config: ConfigRef) =
   openBaseLexer(lex, inputstream)
   lex.fileIdx = fileidx
   lex.indentAhead = - 1
@@ -231,13 +230,15 @@ proc openLexer*(lex: var TLexer, fileIdx: FileIndex, inputstream: PLLStream;
   lex.cache = cache
   when defined(nimsuggest):
     lex.previousToken.fileIndex = fileIdx
+  lex.config = config
 
 proc openLexer*(lex: var TLexer, filename: string, inputstream: PLLStream;
-                cache: IdentCache) =
-  openLexer(lex, filename.fileInfoIdx, inputstream, cache)
+                cache: IdentCache; config: ConfigRef) =
+  openLexer(lex, filename.fileInfoIdx, inputstream, cache, config)
 
 proc closeLexer*(lex: var TLexer) =
-  inc(gLinesCompiled, lex.lineNumber)
+  if lex.config != nil:
+    inc(lex.config.linesCompiled, lex.lineNumber)
   closeBaseLexer(lex)
 
 proc getLineInfo(L: TLexer): TLineInfo =
@@ -576,17 +577,18 @@ proc getNumber(L: var TLexer, result: var TToken) =
         result.iNumber = parseBiggestInt(result.literal)
 
       # Explicit bounds checks
-      let outOfRange = case result.tokType:
-      of tkInt8Lit: (result.iNumber < int8.low or result.iNumber > int8.high)
-      of tkUInt8Lit: (result.iNumber < BiggestInt(uint8.low) or
-                      result.iNumber > BiggestInt(uint8.high))
-      of tkInt16Lit: (result.iNumber < int16.low or result.iNumber > int16.high)
-      of tkUInt16Lit: (result.iNumber < BiggestInt(uint16.low) or
-                      result.iNumber > BiggestInt(uint16.high))
-      of tkInt32Lit: (result.iNumber < int32.low or result.iNumber > int32.high)
-      of tkUInt32Lit: (result.iNumber < BiggestInt(uint32.low) or
-                      result.iNumber > BiggestInt(uint32.high))
-      else: false
+      let outOfRange =
+        case result.tokType
+        of tkInt8Lit: (result.iNumber < int8.low or result.iNumber > int8.high)
+        of tkUInt8Lit: (result.iNumber < BiggestInt(uint8.low) or
+                        result.iNumber > BiggestInt(uint8.high))
+        of tkInt16Lit: (result.iNumber < int16.low or result.iNumber > int16.high)
+        of tkUInt16Lit: (result.iNumber < BiggestInt(uint16.low) or
+                        result.iNumber > BiggestInt(uint16.high))
+        of tkInt32Lit: (result.iNumber < int32.low or result.iNumber > int32.high)
+        of tkUInt32Lit: (result.iNumber < BiggestInt(uint32.low) or
+                        result.iNumber > BiggestInt(uint32.high))
+        else: false
 
       if outOfRange: lexMessageLitNum(L, errNumberOutOfRange, startpos)
 
diff --git a/compiler/main.nim b/compiler/main.nim
index 401099fc3..f23a3a88e 100644
--- a/compiler/main.nim
+++ b/compiler/main.nim
@@ -129,9 +129,10 @@ proc commandEval(graph: ModuleGraph; cache: IdentCache; exp: string) =
     interactivePasses(graph, cache)
     compileSystemModule(graph, cache)
   let echoExp = "echo \"eval\\t\", " & "repr(" & exp & ")"
-  evalNim(graph, echoExp.parseString(cache), makeStdinModule(graph), cache)
+  evalNim(graph, echoExp.parseString(cache, graph.config),
+    makeStdinModule(graph), cache)
 
-proc commandScan(cache: IdentCache) =
+proc commandScan(cache: IdentCache, config: ConfigRef) =
   var f = addFileExt(mainCommandArg(), NimExt)
   var stream = llStreamOpen(f, fmRead)
   if stream != nil:
@@ -139,7 +140,7 @@ proc commandScan(cache: IdentCache) =
       L: TLexer
       tok: TToken
     initToken(tok)
-    openLexer(L, f, stream, cache)
+    openLexer(L, f, stream, cache, config)
     while true:
       rawGetTok(L, tok)
       printTok(tok)
@@ -265,11 +266,11 @@ proc mainCommand*(graph: ModuleGraph; cache: IdentCache) =
   of "parse":
     gCmd = cmdParse
     wantMainModule()
-    discard parseFile(FileIndex gProjectMainIdx, cache)
+    discard parseFile(FileIndex gProjectMainIdx, cache, graph.config)
   of "scan":
     gCmd = cmdScan
     wantMainModule()
-    commandScan(cache)
+    commandScan(cache, graph.config)
     msgWriteln("Beware: Indentation tokens depend on the parser's state!")
   of "secret":
     gCmd = cmdInteractive
@@ -291,7 +292,7 @@ proc mainCommand*(graph: ModuleGraph; cache: IdentCache) =
       let usedMem = formatSize(getMaxMem()) & " peakmem"
     else:
       let usedMem = formatSize(getTotalMem())
-    rawMessage(hintSuccessX, [$gLinesCompiled,
+    rawMessage(hintSuccessX, [$graph.config.linesCompiled,
                formatFloat(epochTime() - gLastCmdTime, ffDecimal, 3),
                usedMem,
                if condSyms.isDefined("release"): "Release Build"
diff --git a/compiler/modules.nim b/compiler/modules.nim
index 56bfdf662..7fe2336dd 100644
--- a/compiler/modules.nim
+++ b/compiler/modules.nim
@@ -107,7 +107,7 @@ proc importModule*(graph: ModuleGraph; s: PSym, fileIdx: FileIndex;
 
 proc includeModule*(graph: ModuleGraph; s: PSym, fileIdx: FileIndex;
                     cache: IdentCache): PNode {.procvar.} =
-  result = syntaxes.parseFile(fileIdx, cache)
+  result = syntaxes.parseFile(fileIdx, cache, graph.config)
   graph.addDep(s, fileIdx)
   graph.addIncludeDep(s.position.FileIndex, fileIdx)
 
diff --git a/compiler/msgs.nim b/compiler/msgs.nim
index 5da375c1c..b6cd05e06 100644
--- a/compiler/msgs.nim
+++ b/compiler/msgs.nim
@@ -131,7 +131,7 @@ type
     warnEachIdentIsTuple, warnShadowIdent,
     warnProveInit, warnProveField, warnProveIndex, warnGcUnsafe, warnGcUnsafe2,
     warnUninit, warnGcMem, warnDestructor, warnLockLevel, warnResultShadowed,
-    warnUser,
+    warnInconsistentSpacing, warnUser,
     hintSuccess, hintSuccessX,
     hintLineTooLong, hintXDeclaredButNotUsed, hintConvToBaseNotNeeded,
     hintConvFromXtoItselfNotNeeded, hintExprAlwaysX, hintQuitCalled,
@@ -146,7 +146,7 @@ const
     errUnknown: "unknown error",
     errInternal: "internal error: $1",
     errIllFormedAstX: "illformed AST: $1",
-    errCannotOpenFile: "cannot open \'$1\'",
+    errCannotOpenFile: "cannot open '$1'",
     errGenerated: "$1",
     errStringLiteralExpected: "string literal expected",
     errIntLiteralExpected: "integer literal expected",
@@ -160,39 +160,39 @@ const
     errNumberOutOfRange: "number $1 out of valid range",
     errNnotAllowedInCharacter: "\\n not allowed in character literal",
     errClosingBracketExpected: "closing ']' expected, but end of file reached",
-    errMissingFinalQuote: "missing final \' for character literal",
-    errIdentifierExpected: "identifier expected, but found \'$1\'",
-    errNewlineExpected: "newline expected, but found \'$1\'",
+    errMissingFinalQuote: "missing final ' for character literal",
+    errIdentifierExpected: "identifier expected, but found '$1'",
+    errNewlineExpected: "newline expected, but found '$1'",
     errInvalidModuleName: "invalid module name: '$1'",
-    errOperatorExpected: "operator expected, but found \'$1\'",
-    errTokenExpected: "\'$1\' expected",
-    errRecursiveDependencyX: "recursive dependency: \'$1\'",
-    errOnOrOffExpected: "\'on\' or \'off\' expected",
-    errNoneSpeedOrSizeExpected: "\'none\', \'speed\' or \'size\' expected",
+    errOperatorExpected: "operator expected, but found '$1'",
+    errTokenExpected: "'$1' expected",
+    errRecursiveDependencyX: "recursive dependency: '$1'",
+    errOnOrOffExpected: "'on' or 'off' expected",
+    errNoneSpeedOrSizeExpected: "'none', 'speed' or 'size' expected",
     errInvalidPragma: "invalid pragma",
-    errUnknownPragma: "unknown pragma: \'$1\'",
-    errInvalidDirectiveX: "invalid directive: \'$1\'",
-    errAtPopWithoutPush: "\'pop\' without a \'push\' pragma",
+    errUnknownPragma: "unknown pragma: '$1'",
+    errInvalidDirectiveX: "invalid directive: '$1'",
+    errAtPopWithoutPush: "'pop' without a 'push' pragma",
     errEmptyAsm: "empty asm statement",
     errInvalidIndentation: "invalid indentation",
     errExceptionAlreadyHandled: "exception already handled",
     errYieldNotAllowedHere: "'yield' only allowed in an iterator",
     errYieldNotAllowedInTryStmt: "'yield' cannot be used within 'try' in a non-inlined iterator",
-    errInvalidNumberOfYieldExpr: "invalid number of \'yield\' expressions",
+    errInvalidNumberOfYieldExpr: "invalid number of 'yield' expressions",
     errCannotReturnExpr: "current routine cannot return an expression",
     errNoReturnWithReturnTypeNotAllowed: "routines with NoReturn pragma are not allowed to have return type",
-    errAttemptToRedefine: "redefinition of \'$1\'",
-    errStmtInvalidAfterReturn: "statement not allowed after \'return\', \'break\', \'raise\', \'continue\' or proc call with noreturn pragma",
+    errAttemptToRedefine: "redefinition of '$1'",
+    errStmtInvalidAfterReturn: "statement not allowed after 'return', 'break', 'raise', 'continue' or proc call with noreturn pragma",
     errStmtExpected: "statement expected",
-    errInvalidLabel: "\'$1\' is no label",
-    errInvalidCmdLineOption: "invalid command line option: \'$1\'",
-    errCmdLineArgExpected: "argument for command line option expected: \'$1\'",
-    errCmdLineNoArgExpected: "invalid argument for command line option: \'$1\'",
-    errInvalidVarSubstitution: "invalid variable substitution in \'$1\'",
-    errUnknownVar: "unknown variable: \'$1\'",
-    errUnknownCcompiler: "unknown C compiler: \'$1\'",
-    errOnOrOffExpectedButXFound: "\'on\' or \'off\' expected, but \'$1\' found",
-    errOnOffOrListExpectedButXFound: "\'on\', \'off\' or \'list\' expected, but \'$1\' found",
+    errInvalidLabel: "'$1' is no label",
+    errInvalidCmdLineOption: "invalid command line option: '$1'",
+    errCmdLineArgExpected: "argument for command line option expected: '$1'",
+    errCmdLineNoArgExpected: "invalid argument for command line option: '$1'",
+    errInvalidVarSubstitution: "invalid variable substitution in '$1'",
+    errUnknownVar: "unknown variable: '$1'",
+    errUnknownCcompiler: "unknown C compiler: '$1'",
+    errOnOrOffExpectedButXFound: "'on' or 'off' expected, but '$1' found",
+    errOnOffOrListExpectedButXFound: "'on', 'off' or 'list' expected, but '$1' found",
     errNoneBoehmRefcExpectedButXFound: "'none', 'boehm' or 'refc' expected, but '$1' found",
     errNoneSpeedOrSizeExpectedButXFound: "'none', 'speed' or 'size' expected, but '$1' found",
     errGuiConsoleOrLibExpectedButXFound: "'gui', 'console' or 'lib' expected, but '$1' found",
@@ -201,19 +201,19 @@ const
     errGenOutExpectedButXFound: "'c', 'c++' or 'yaml' expected, but '$1' found",
     errArgsNeedRunOption: "arguments can only be given if the '--run' option is selected",
     errInvalidMultipleAsgn: "multiple assignment is not allowed",
-    errColonOrEqualsExpected: "\':\' or \'=\' expected, but found \'$1\'",
-    errExprExpected: "expression expected, but found \'$1\'",
-    errUndeclaredField: "undeclared field: \'$1\'",
-    errUndeclaredRoutine: "attempting to call undeclared routine: \'$1\'",
-    errUseQualifier: "ambiguous identifier: \'$1\' -- use a qualifier",
+    errColonOrEqualsExpected: "':' or '=' expected, but found '$1'",
+    errExprExpected: "expression expected, but found '$1'",
+    errUndeclaredField: "undeclared field: '$1'",
+    errUndeclaredRoutine: "attempting to call undeclared routine: '$1'",
+    errUseQualifier: "ambiguous identifier: '$1' -- use a qualifier",
     errTypeExpected: "type expected",
-    errSystemNeeds: "system module needs \'$1\'",
+    errSystemNeeds: "system module needs '$1'",
     errExecutionOfProgramFailed: "execution of an external program failed: '$1'",
-    errNotOverloadable: "overloaded \'$1\' leads to ambiguous calls",
-    errInvalidArgForX: "invalid argument for \'$1\'",
+    errNotOverloadable: "overloaded '$1' leads to ambiguous calls",
+    errInvalidArgForX: "invalid argument for '$1'",
     errStmtHasNoEffect: "statement has no effect",
-    errXExpectsTypeOrValue: "\'$1\' expects a type or value",
-    errXExpectsArrayType: "\'$1\' expects an array type",
+    errXExpectsTypeOrValue: "'$1' expects a type or value",
+    errXExpectsArrayType: "'$1' expects an array type",
     errIteratorCannotBeInstantiated: "'$1' cannot be instantiated because its body has not been compiled yet",
     errExprXAmbiguous: "expression '$1' ambiguous in this context",
     errConstantDivisionByZero: "division by zero",
@@ -221,26 +221,26 @@ const
     errOrdinalOrFloatTypeExpected: "ordinal or float type expected",
     errOverOrUnderflow: "over- or underflow",
     errCannotEvalXBecauseIncompletelyDefined: "cannot evaluate '$1' because type is not defined completely",
-    errChrExpectsRange0_255: "\'chr\' expects an int in the range 0..255",
-    errDynlibRequiresExportc: "\'dynlib\' requires \'exportc\'",
-    errUndeclaredFieldX: "undeclared field: \'$1\'",
+    errChrExpectsRange0_255: "'chr' expects an int in the range 0..255",
+    errDynlibRequiresExportc: "'dynlib' requires 'exportc'",
+    errUndeclaredFieldX: "undeclared field: '$1'",
     errNilAccess: "attempt to access a nil address",
     errIndexOutOfBounds: "index out of bounds",
     errIndexTypesDoNotMatch: "index types do not match",
-    errBracketsInvalidForType: "\'[]\' operator invalid for this type",
+    errBracketsInvalidForType: "'[]' operator invalid for this type",
     errValueOutOfSetBounds: "value out of set bounds",
-    errFieldInitTwice: "field initialized twice: \'$1\'",
-    errFieldNotInit: "field \'$1\' not initialized",
-    errExprXCannotBeCalled: "expression \'$1\' cannot be called",
+    errFieldInitTwice: "field initialized twice: '$1'",
+    errFieldNotInit: "field '$1' not initialized",
+    errExprXCannotBeCalled: "expression '$1' cannot be called",
     errExprHasNoType: "expression has no type",
-    errExprXHasNoType: "expression \'$1\' has no type (or is ambiguous)",
-    errCastNotInSafeMode: "\'cast\' not allowed in safe mode",
+    errExprXHasNoType: "expression '$1' has no type (or is ambiguous)",
+    errCastNotInSafeMode: "'cast' not allowed in safe mode",
     errExprCannotBeCastToX: "expression cannot be cast to $1",
     errCommaOrParRiExpected: "',' or ')' expected",
-    errCurlyLeOrParLeExpected: "\'{\' or \'(\' expected",
-    errSectionExpected: "section (\'type\', \'proc\', etc.) expected",
+    errCurlyLeOrParLeExpected: "'{' or '(' expected",
+    errSectionExpected: "section ('type', 'proc', etc.) expected",
     errRangeExpected: "range expected",
-    errMagicOnlyInSystem: "\'magic\' only allowed in system module",
+    errMagicOnlyInSystem: "'magic' only allowed in system module",
     errPowerOfTwoExpected: "power of two expected",
     errStringMayNotBeEmpty: "string literal may not be empty",
     errCallConvExpected: "calling convention expected",
@@ -257,51 +257,51 @@ const
     errWrongNumberOfVariables: "wrong number of variables",
     errExprCannotBeRaised: "only a 'ref object' can be raised",
     errBreakOnlyInLoop: "'break' only allowed in loop construct",
-    errTypeXhasUnknownSize: "type \'$1\' has unknown size",
+    errTypeXhasUnknownSize: "type '$1' has unknown size",
     errConstNeedsConstExpr: "a constant can only be initialized with a constant expression",
     errConstNeedsValue: "a constant needs a value",
     errResultCannotBeOpenArray: "the result type cannot be on open array",
-    errSizeTooBig: "computing the type\'s size produced an overflow",
+    errSizeTooBig: "computing the type's size produced an overflow",
     errSetTooBig: "set is too large",
     errBaseTypeMustBeOrdinal: "base type of a set must be an ordinal",
     errInheritanceOnlyWithNonFinalObjects: "inheritance only works with non-final objects",
     errInheritanceOnlyWithEnums: "inheritance only works with an enum",
-    errIllegalRecursionInTypeX: "illegal recursion in type \'$1\'",
-    errCannotInstantiateX: "cannot instantiate: \'$1\'",
+    errIllegalRecursionInTypeX: "illegal recursion in type '$1'",
+    errCannotInstantiateX: "cannot instantiate: '$1'",
     errExprHasNoAddress: "expression has no address",
     errXStackEscape: "address of '$1' may not escape its stack frame",
-    errVarForOutParamNeededX: "for a \'var\' type a variable needs to be passed; but '$1' is immutable",
+    errVarForOutParamNeededX: "for a 'var' type a variable needs to be passed; but '$1' is immutable",
     errPureTypeMismatch: "type mismatch",
     errTypeMismatch: "type mismatch: got <",
     errButExpected: "but expected one of: ",
-    errButExpectedX: "but expected \'$1\'",
+    errButExpectedX: "but expected '$1'",
     errAmbiguousCallXYZ: "ambiguous call; both $1 and $2 match for: $3",
     errWrongNumberOfArguments: "wrong number of arguments",
     errWrongNumberOfArgumentsInCall: "wrong number of arguments in call to '$1'",
     errMissingGenericParamsForTemplate: "'$1' has unspecified generic parameters",
-    errXCannotBePassedToProcVar: "\'$1\' cannot be passed to a procvar",
+    errXCannotBePassedToProcVar: "'$1' cannot be passed to a procvar",
     errPragmaOnlyInHeaderOfProcX: "pragmas are only allowed in the header of a proc; redefinition of $1",
-    errImplOfXNotAllowed: "implementation of \'$1\' is not allowed",
-    errImplOfXexpected: "implementation of \'$1\' expected",
+    errImplOfXNotAllowed: "implementation of '$1' is not allowed",
+    errImplOfXexpected: "implementation of '$1' expected",
     errNoSymbolToBorrowFromFound: "no symbol to borrow from found",
     errDiscardValueX: "value of type '$1' has to be discarded",
     errInvalidDiscard: "statement returns no value that can be discarded",
     errIllegalConvFromXtoY: "conversion from $1 to $2 is invalid",
-    errCannotBindXTwice: "cannot bind parameter \'$1\' twice",
+    errCannotBindXTwice: "cannot bind parameter '$1' twice",
     errInvalidOrderInArrayConstructor: "invalid order in array constructor",
-    errInvalidOrderInEnumX: "invalid order in enum \'$1\'",
-    errEnumXHasHoles: "enum \'$1\' has holes",
-    errExceptExpected: "\'except\' or \'finally\' expected",
-    errInvalidTry: "after catch all \'except\' or \'finally\' no section may follow",
-    errOptionExpected: "option expected, but found \'$1\'",
-    errXisNoLabel: "\'$1\' is not a label",
+    errInvalidOrderInEnumX: "invalid order in enum '$1'",
+    errEnumXHasHoles: "enum '$1' has holes",
+    errExceptExpected: "'except' or 'finally' expected",
+    errInvalidTry: "after catch all 'except' or 'finally' no section may follow",
+    errOptionExpected: "option expected, but found '$1'",
+    errXisNoLabel: "'$1' is not a label",
     errNotAllCasesCovered: "not all cases are covered",
-    errUnknownSubstitionVar: "unknown substitution variable: \'$1\'",
+    errUnknownSubstitionVar: "unknown substitution variable: '$1'",
     errComplexStmtRequiresInd: "complex statement requires indentation",
-    errXisNotCallable: "\'$1\' is not callable",
+    errXisNotCallable: "'$1' is not callable",
     errNoPragmasAllowedForX: "no pragmas allowed for $1",
     errNoGenericParamsAllowedForX: "no generic parameters allowed for $1",
-    errInvalidParamKindX: "invalid param kind: \'$1\'",
+    errInvalidParamKindX: "invalid param kind: '$1'",
     errDefaultArgumentInvalid: "default argument invalid",
     errNamedParamHasToBeIdent: "named parameter has to be an identifier",
     errNoReturnTypeForX: "no return type allowed for $1",
@@ -309,24 +309,24 @@ const
     errInvalidPragmaX: "invalid pragma: $1",
     errXNotAllowedHere: "$1 not allowed here",
     errInvalidControlFlowX: "invalid control flow: $1",
-    errXisNoType: "invalid type: \'$1\'",
+    errXisNoType: "invalid type: '$1'",
     errCircumNeedsPointer: "'[]' needs a pointer or reference type",
     errInvalidExpression: "invalid expression",
-    errInvalidExpressionX: "invalid expression: \'$1\'",
-    errEnumHasNoValueX: "enum has no value \'$1\'",
+    errInvalidExpressionX: "invalid expression: '$1'",
+    errEnumHasNoValueX: "enum has no value '$1'",
     errNamedExprExpected: "named expression expected",
     errNamedExprNotAllowed: "named expression not allowed here",
-    errXExpectsOneTypeParam: "\'$1\' expects one type parameter",
+    errXExpectsOneTypeParam: "'$1' expects one type parameter",
     errArrayExpectsTwoTypeParams: "array expects two type parameters",
-    errInvalidVisibilityX: "invalid visibility: \'$1\'",
+    errInvalidVisibilityX: "invalid visibility: '$1'",
     errInitHereNotAllowed: "initialization not allowed here",
-    errXCannotBeAssignedTo: "\'$1\' cannot be assigned to",
-    errIteratorNotAllowed: "iterators can only be defined at the module\'s top level",
+    errXCannotBeAssignedTo: "'$1' cannot be assigned to",
+    errIteratorNotAllowed: "iterators can only be defined at the module's top level",
     errXNeedsReturnType: "$1 needs a return type",
     errNoReturnTypeDeclared: "no return type declared",
     errNoCommand: "no command given",
-    errInvalidCommandX: "invalid command: \'$1\'",
-    errXOnlyAtModuleScope: "\'$1\' is only allowed at top level",
+    errInvalidCommandX: "invalid command: '$1'",
+    errXOnlyAtModuleScope: "'$1' is only allowed at top level",
     errXNeedsParamObjectType: "'$1' needs a parameter that has an object type",
     errTemplateInstantiationTooNested: "template instantiation too nested, try --evalTemplateLimit:N",
     errMacroInstantiationTooNested: "macro instantiation too nested, try --evalMacroLimit:N",
@@ -334,17 +334,17 @@ const
     errInvalidIndexValueForTuple: "invalid index value for tuple subscript",
     errCommandExpectsFilename: "command expects a filename argument",
     errMainModuleMustBeSpecified: "please, specify a main module in the project configuration file",
-    errXExpected: "\'$1\' expected",
-    errTIsNotAConcreteType: "\'$1\' is not a concrete type.",
-    errCastToANonConcreteType: "cannot cast to a non concrete type: \'$1\'",
+    errXExpected: "'$1' expected",
+    errTIsNotAConcreteType: "'$1' is not a concrete type.",
+    errCastToANonConcreteType: "cannot cast to a non concrete type: '$1'",
     errInvalidSectionStart: "invalid section start",
     errGridTableNotImplemented: "grid table is not implemented",
     errGeneralParseError: "general parse error",
     errNewSectionExpected: "new section expected",
-    errWhitespaceExpected: "whitespace expected, got \'$1\'",
-    errXisNoValidIndexFile: "\'$1\' is no valid index file",
-    errCannotRenderX: "cannot render reStructuredText element \'$1\'",
-    errVarVarTypeNotAllowed: "type \'var var\' is not allowed",
+    errWhitespaceExpected: "whitespace expected, got '$1'",
+    errXisNoValidIndexFile: "'$1' is no valid index file",
+    errCannotRenderX: "cannot render reStructuredText element '$1'",
+    errVarVarTypeNotAllowed: "type 'var var' is not allowed",
     errInstantiateXExplicitly: "instantiate '$1' explicitly",
     errOnlyACallOpCanBeDelegator: "only a call operator can be a delegator",
     errUsingNoSymbol: "'$1' is not a variable, constant or a proc name",
@@ -354,26 +354,26 @@ const
                                    "A destructor must be associated will all instantiations of a generic type",
     errInlineIteratorsAsProcParams: "inline iterators can be used as parameters only for " &
                                     "templates, macros and other inline iterators",
-    errXExpectsTwoArguments: "\'$1\' expects two arguments",
-    errXExpectsObjectTypes: "\'$1\' expects object types",
-    errXcanNeverBeOfThisSubtype: "\'$1\' can never be of this subtype",
+    errXExpectsTwoArguments: "'$1' expects two arguments",
+    errXExpectsObjectTypes: "'$1' expects object types",
+    errXcanNeverBeOfThisSubtype: "'$1' can never be of this subtype",
     errTooManyIterations: "interpretation requires too many iterations; " &
       "if you are sure this is not a bug in your code edit " &
       "compiler/vmdef.MaxLoopIterations and rebuild the compiler",
-    errCannotInterpretNodeX: "cannot evaluate \'$1\'",
-    errFieldXNotFound: "field \'$1\' cannot be found",
-    errInvalidConversionFromTypeX: "invalid conversion from type \'$1\'",
+    errCannotInterpretNodeX: "cannot evaluate '$1'",
+    errFieldXNotFound: "field '$1' cannot be found",
+    errInvalidConversionFromTypeX: "invalid conversion from type '$1'",
     errAssertionFailed: "assertion failed",
-    errCannotGenerateCodeForX: "cannot generate code for \'$1\'",
+    errCannotGenerateCodeForX: "cannot generate code for '$1'",
     errXRequiresOneArgument: "$1 requires one parameter",
     errUnhandledExceptionX: "unhandled exception: $1",
     errCyclicTree: "macro returned a cyclic abstract syntax tree",
-    errXisNoMacroOrTemplate: "\'$1\' is no macro or template",
-    errXhasSideEffects: "\'$1\' can have side effects",
+    errXisNoMacroOrTemplate: "'$1' is no macro or template",
+    errXhasSideEffects: "'$1' can have side effects",
     errIteratorExpected: "iterator within for loop context expected",
     errLetNeedsInit: "'let' symbol requires an initialization",
     errThreadvarCannotInit: "a thread var cannot be initialized explicitly; this would only run for the main thread",
-    errWrongSymbolX: "usage of \'$1\' is a user-defined error",
+    errWrongSymbolX: "usage of '$1' is a user-defined error",
     errIllegalCaptureX: "illegal capture '$1'",
     errXCannotBeClosure: "'$1' cannot have 'closure' calling convention",
     errXMustBeCompileTime: "'$1' can only be used in compile-time context",
@@ -384,22 +384,22 @@ const
                                 "it is used as an operand to another routine and the types " &
                                 "of the generic paramers can be inferred from the expected signature.",
     errProcHasNoConcreteType: "'$1' doesn't have a concrete type, due to unspecified generic parameters.",
-    errCompilerDoesntSupportTarget: "The current compiler \'$1\' doesn't support the requested compilation target",
+    errCompilerDoesntSupportTarget: "The current compiler '$1' doesn't support the requested compilation target",
     errInOutFlagNotExtern: "The `$1` modifier can be used only with imported types",
     errUser: "$1",
-    warnCannotOpenFile: "cannot open \'$1\'",
+    warnCannotOpenFile: "cannot open '$1'",
     warnOctalEscape: "octal escape sequences do not exist; leading zero is ignored",
-    warnXIsNeverRead: "\'$1\' is never read",
-    warnXmightNotBeenInit: "\'$1\' might not have been initialized",
+    warnXIsNeverRead: "'$1' is never read",
+    warnXmightNotBeenInit: "'$1' might not have been initialized",
     warnDeprecated: "$1 is deprecated",
     warnConfigDeprecated: "config file '$1' is deprecated",
-    warnSmallLshouldNotBeUsed: "\'l\' should not be used as an identifier; may look like \'1\' (one)",
-    warnUnknownMagic: "unknown magic \'$1\' might crash the compiler",
-    warnRedefinitionOfLabel: "redefinition of label \'$1\'",
-    warnUnknownSubstitutionX: "unknown substitution \'$1\'",
-    warnLanguageXNotSupported: "language \'$1\' not supported",
-    warnFieldXNotSupported: "field \'$1\' not supported",
-    warnCommentXIgnored: "comment \'$1\' ignored",
+    warnSmallLshouldNotBeUsed: "'l' should not be used as an identifier; may look like '1' (one)",
+    warnUnknownMagic: "unknown magic '$1' might crash the compiler",
+    warnRedefinitionOfLabel: "redefinition of label '$1'",
+    warnUnknownSubstitutionX: "unknown substitution '$1'",
+    warnLanguageXNotSupported: "language '$1' not supported",
+    warnFieldXNotSupported: "field '$1' not supported",
+    warnCommentXIgnored: "comment '$1' ignored",
     warnTypelessParam: "'$1' has no type. Typeless parameters are deprecated; only allowed for 'template'",
     warnUseBase: "use {.base.} for base methods; baseless methods are deprecated",
     warnWriteToForeignHeap: "write to foreign heap",
@@ -416,19 +416,20 @@ const
     warnDestructor: "usage of a type with a destructor in a non destructible context. This will become a compile time error in the future.",
     warnLockLevel: "$1",
     warnResultShadowed: "Special variable 'result' is shadowed.",
+    warnInconsistentSpacing: "Number of spaces around '$#' is not consistent",
     warnUser: "$1",
     hintSuccess: "operation successful",
     hintSuccessX: "operation successful ($# lines compiled; $# sec total; $#; $#)",
     hintLineTooLong: "line too long",
-    hintXDeclaredButNotUsed: "\'$1\' is declared but not used",
+    hintXDeclaredButNotUsed: "'$1' is declared but not used",
     hintConvToBaseNotNeeded: "conversion to base object is not needed",
     hintConvFromXtoItselfNotNeeded: "conversion from $1 to itself is pointless",
-    hintExprAlwaysX: "expression evaluates always to \'$1\'",
+    hintExprAlwaysX: "expression evaluates always to '$1'",
     hintQuitCalled: "quit() called",
     hintProcessing: "$1",
     hintCodeBegin: "generated code listing:",
     hintCodeEnd: "end of listing",
-    hintConf: "used config file \'$1\'",
+    hintConf: "used config file '$1'",
     hintPath: "added path: '$1'",
     hintConditionAlwaysTrue: "condition is always true: '$1'",
     hintName: "name should be: '$1'",
@@ -454,7 +455,8 @@ const
     "TypelessParam", "UseBase", "WriteToForeignHeap",
     "UnsafeCode", "EachIdentIsTuple", "ShadowIdent",
     "ProveInit", "ProveField", "ProveIndex", "GcUnsafe", "GcUnsafe2", "Uninit",
-    "GcMem", "Destructor", "LockLevel", "ResultShadowed", "User"]
+    "GcMem", "Destructor", "LockLevel", "ResultShadowed",
+    "Spacing", "User"]
 
   HintsToStr* = ["Success", "SuccessX", "LineTooLong",
     "XDeclaredButNotUsed", "ConvToBaseNotNeeded", "ConvFromXtoItselfNotNeeded",
diff --git a/compiler/nimconf.nim b/compiler/nimconf.nim
index bdf558134..dc8d082b3 100644
--- a/compiler/nimconf.nim
+++ b/compiler/nimconf.nim
@@ -205,7 +205,7 @@ proc readConfigFile(filename: string; cache: IdentCache; config: ConfigRef) =
   stream = llStreamOpen(filename, fmRead)
   if stream != nil:
     initToken(tok)
-    openLexer(L, filename, stream, cache)
+    openLexer(L, filename, stream, cache, config)
     tok.tokType = tkEof       # to avoid a pointless warning
     confTok(L, tok, config)           # read in the first token
     while tok.tokType != tkEof: parseAssignment(L, tok, config)
diff --git a/compiler/nimfix/pretty.nim b/compiler/nimfix/pretty.nim
index 4627264dc..7af2a86dc 100644
--- a/compiler/nimfix/pretty.nim
+++ b/compiler/nimfix/pretty.nim
@@ -13,7 +13,7 @@
 import
   strutils, os, intsets, strtabs
 
-import "../compiler" / [options, ast, astalgo, msgs, semdata, ropes, idents]
+import ".." / [options, ast, astalgo, msgs, semdata, ropes, idents]
 import prettybase
 
 type
diff --git a/compiler/nimfix/prettybase.nim b/compiler/nimfix/prettybase.nim
index ecb4b0093..c32dbe623 100644
--- a/compiler/nimfix/prettybase.nim
+++ b/compiler/nimfix/prettybase.nim
@@ -8,7 +8,7 @@
 #
 
 import strutils, lexbase, streams
-import "../compiler" / [ast, msgs, idents]
+import ".." / [ast, msgs, idents]
 from os import splitFile
 
 type
diff --git a/compiler/options.nim b/compiler/options.nim
index 5baaa1bfd..f8cb735ae 100644
--- a/compiler/options.nim
+++ b/compiler/options.nim
@@ -113,6 +113,7 @@ type
     notnil
 
   ConfigRef* = ref object ## eventually all global configuration should be moved here
+    linesCompiled*: int  # all lines that have been compiled
     cppDefines*: HashSet[string]
     headerFile*: string
     features*: set[Feature]
diff --git a/compiler/parser.nim b/compiler/parser.nim
index ac0a57770..0a3815f13 100644
--- a/compiler/parser.nim
+++ b/compiler/parser.nim
@@ -27,7 +27,7 @@ when isMainModule:
   outp.close
 
 import
-  llstream, lexer, idents, strutils, ast, astalgo, msgs
+  llstream, lexer, idents, strutils, ast, astalgo, msgs, options
 
 type
   TParser* = object            # A TParser object represents a file that
@@ -84,20 +84,20 @@ proc getTok(p: var TParser) =
   p.hasProgress = true
 
 proc openParser*(p: var TParser, fileIdx: FileIndex, inputStream: PLLStream,
-                 cache: IdentCache;
+                 cache: IdentCache; config: ConfigRef;
                  strongSpaces=false) =
   ## Open a parser, using the given arguments to set up its internal state.
   ##
   initToken(p.tok)
-  openLexer(p.lex, fileIdx, inputStream, cache)
+  openLexer(p.lex, fileIdx, inputStream, cache, config)
   getTok(p)                   # read the first token
   p.firstTok = true
   p.strongSpaces = strongSpaces
 
 proc openParser*(p: var TParser, filename: string, inputStream: PLLStream,
-                 cache: IdentCache;
+                 cache: IdentCache; config: ConfigRef;
                  strongSpaces=false) =
-  openParser(p, filename.fileInfoIdx, inputStream, cache, strongSpaces)
+  openParser(p, filename.fileInfoIdx, inputStream, cache, config, strongSpaces)
 
 proc closeParser(p: var TParser) =
   ## Close a parser, freeing up its resources.
@@ -268,13 +268,9 @@ proc isUnary(p: TParser): bool =
 proc checkBinary(p: TParser) {.inline.} =
   ## Check if the current parser token is a binary operator.
   # we don't check '..' here as that's too annoying
-  if p.strongSpaces and p.tok.tokType == tkOpr:
+  if p.tok.tokType == tkOpr:
     if p.tok.strongSpaceB > 0 and p.tok.strongSpaceA != p.tok.strongSpaceB:
-      parMessage(p, errGenerated,
-                 "Number of spaces around '$#' not consistent" %
-                 prettyTok(p.tok))
-    elif p.tok.strongSpaceA notin {0,1,2,4,8}:
-      parMessage(p, errGenerated, "Number of spaces must be 0,1,2,4 or 8")
+      parMessage(p, warnInconsistentSpacing, prettyTok(p.tok))
 
 #| module = stmt ^* (';' / IND{=})
 #|
@@ -706,10 +702,17 @@ proc namedParams(p: var TParser, callee: PNode,
   # progress guaranteed
   exprColonEqExprListAux(p, endTok, result)
 
-proc commandParam(p: var TParser): PNode =
+proc commandParam(p: var TParser, isFirstParam: var bool): PNode =
   result = parseExpr(p)
   if p.tok.tokType == tkDo:
     result = postExprBlocks(p, result)
+  elif p.tok.tokType == tkEquals and not isFirstParam:
+    let lhs = result
+    result = newNodeP(nkExprEqExpr, p)
+    getTok(p)
+    addSon(result, lhs)
+    addSon(result, parseExpr(p))
+  isFirstParam = false
 
 proc primarySuffix(p: var TParser, r: PNode, baseIndent: int): PNode =
   #| primarySuffix = '(' (exprColonEqExpr comma?)* ')' doBlocks?
@@ -744,17 +747,19 @@ proc primarySuffix(p: var TParser, r: PNode, baseIndent: int): PNode =
       # progress guaranteed
       somePar()
       result = namedParams(p, result, nkCurlyExpr, tkCurlyRi)
-    of tkSymbol, tkAccent, tkIntLit..tkCharLit, tkNil, tkCast, tkAddr, tkType:
-      if p.inPragma == 0:
+    of tkSymbol, tkAccent, tkIntLit..tkCharLit, tkNil, tkCast, tkAddr, tkType,
+       tkOpr, tkDotDot:
+      if p.inPragma == 0 and (isUnary(p) or p.tok.tokType notin {tkOpr, tkDotDot}):
         # actually parsing {.push hints:off.} as {.push(hints:off).} is a sweet
         # solution, but pragmas.nim can't handle that
         let a = result
         result = newNodeP(nkCommand, p)
         addSon(result, a)
+        var isFirstParam = true
         when true:
           # progress NOT guaranteed
           p.hasProgress = false
-          addSon result, commandParam(p)
+          addSon result, commandParam(p, isFirstParam)
           if not p.hasProgress: break
         else:
           while p.tok.tokType != tkEof:
@@ -1306,17 +1311,18 @@ proc parseExprStmt(p: var TParser): PNode =
     addSon(result, b)
   else:
     # simpleExpr parsed 'p a' from 'p a, b'?
+    var isFirstParam = false
     if p.tok.indent < 0 and p.tok.tokType == tkComma and a.kind == nkCommand:
       result = a
       while true:
         getTok(p)
         optInd(p, result)
-        addSon(result, commandParam(p))
+        addSon(result, commandParam(p, isFirstParam))
         if p.tok.tokType != tkComma: break
     elif p.tok.indent < 0 and isExprStart(p):
       result = newNode(nkCommand, a.info, @[a])
       while true:
-        addSon(result, commandParam(p))
+        addSon(result, commandParam(p, isFirstParam))
         if p.tok.tokType != tkComma: break
         getTok(p)
         optInd(p, result)
@@ -2181,8 +2187,8 @@ proc parseTopLevelStmt(p: var TParser): PNode =
       if result.kind == nkEmpty: parMessage(p, errExprExpected, p.tok)
       break
 
-proc parseString*(s: string; cache: IdentCache; filename: string = "";
-                  line: int = 0;
+proc parseString*(s: string; cache: IdentCache; config: ConfigRef;
+                  filename: string = ""; line: int = 0;
                   errorHandler: TErrorHandler = nil): PNode =
   ## Parses a string into an AST, returning the top node.
   ## `filename` and `line`, although optional, provide info so that the
@@ -2195,7 +2201,7 @@ proc parseString*(s: string; cache: IdentCache; filename: string = "";
   # XXX for now the builtin 'parseStmt/Expr' functions do not know about strong
   # spaces...
   parser.lex.errorHandler = errorHandler
-  openParser(parser, filename, stream, cache, false)
+  openParser(parser, filename, stream, cache, config, false)
 
   result = parser.parseAll
   closeParser(parser)
diff --git a/compiler/passes.nim b/compiler/passes.nim
index 6ff3f2bb5..b104cd132 100644
--- a/compiler/passes.nim
+++ b/compiler/passes.nim
@@ -207,7 +207,7 @@ proc processModule*(graph: ModuleGraph; module: PSym, stream: PLLStream,
     else:
       s = stream
     while true:
-      openParsers(p, fileIdx, s, cache)
+      openParsers(p, fileIdx, s, cache, graph.config)
 
       if sfSystemModule notin module.flags:
         # XXX what about caching? no processing then? what if I change the
diff --git a/compiler/pbraces.nim b/compiler/pbraces.nim
deleted file mode 100644
index fe438d58b..000000000
--- a/compiler/pbraces.nim
+++ /dev/null
@@ -1,1790 +0,0 @@
-#
-#
-#           The Nim Compiler
-#        (c) Copyright 2017 Andreas Rumpf
-#
-#    See the file "copying.txt", included in this
-#    distribution, for details about the copyright.
-#
-
-# This module implements the parser of the braces Nim syntax.
-
-import
-  llstream, lexer, idents, strutils, ast, astalgo, msgs
-
-from parser import TParser
-
-proc getTok(p: var TParser) =
-  ## Get the next token from the parser's lexer, and store it in the parser's
-  ## `tok` member.
-  rawGetTok(p.lex, p.tok)
-
-proc openParser*(p: var TParser, fileIdx: FileIndex, inputStream: PLLStream;
-                 cache: IdentCache) =
-  ## Open a parser, using the given arguments to set up its internal state.
-  ##
-  initToken(p.tok)
-  openLexer(p.lex, fileIdx, inputStream, cache)
-  getTok(p)                   # read the first token
-  p.lex.allowTabs = true
-
-proc openParser*(p: var TParser, filename: string, inputStream: PLLStream;
-                 cache: IdentCache) =
-  openParser(p, filename.fileInfoIdx, inputStream, cache)
-
-proc closeParser*(p: var TParser) =
-  ## Close a parser, freeing up its resources.
-  closeLexer(p.lex)
-
-proc parMessage(p: TParser, msg: TMsgKind, arg = "") =
-  ## Produce and emit the parser message `arg` to output.
-  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`
-  parMessage(p, msg, prettyTok(tok))
-
-proc rawSkipComment(p: var TParser, node: PNode) =
-  if p.tok.tokType == tkComment:
-    if node != nil:
-      if node.comment == nil: node.comment = ""
-      add(node.comment, p.tok.literal)
-    else:
-      parMessage(p, errInternal, "skipComment")
-    getTok(p)
-
-proc skipComment(p: var TParser, node: PNode) =
-  rawSkipComment(p, node)
-
-proc flexComment(p: var TParser, node: PNode) =
-  rawSkipComment(p, node)
-
-proc skipInd(p: var TParser) = discard
-proc optPar(p: var TParser) = discard
-
-proc optInd(p: var TParser, n: PNode) =
-  skipComment(p, n)
-
-proc getTokNoInd(p: var TParser) =
-  getTok(p)
-
-proc expectIdentOrKeyw(p: TParser) =
-  if p.tok.tokType != tkSymbol and not isKeyword(p.tok.tokType):
-    lexMessage(p.lex, errIdentifierExpected, prettyTok(p.tok))
-
-proc expectIdent(p: TParser) =
-  if p.tok.tokType != tkSymbol:
-    lexMessage(p.lex, errIdentifierExpected, prettyTok(p.tok))
-
-proc eat(p: var TParser, tokType: TTokType) =
-  ## Move the parser to the next token if the current token is of type
-  ## `tokType`, otherwise error.
-  if p.tok.tokType == tokType:
-    getTok(p)
-  else:
-    lexMessageTok(p.lex, errTokenExpected, p.tok, TokTypeToStr[tokType])
-
-proc parLineInfo(p: TParser): TLineInfo =
-  ## Retrieve the line information associated with the parser's current state.
-  result = getLineInfo(p.lex, p.tok)
-
-proc indAndComment(p: var TParser, n: PNode) =
-  rawSkipComment(p, n)
-
-proc newNodeP(kind: TNodeKind, p: TParser): PNode =
-  result = newNodeI(kind, parLineInfo(p))
-
-proc newIntNodeP(kind: TNodeKind, intVal: BiggestInt, p: TParser): PNode =
-  result = newNodeP(kind, p)
-  result.intVal = intVal
-
-proc newFloatNodeP(kind: TNodeKind, floatVal: BiggestFloat,
-                   p: TParser): PNode =
-  result = newNodeP(kind, p)
-  result.floatVal = floatVal
-
-proc newStrNodeP(kind: TNodeKind, strVal: string, p: TParser): PNode =
-  result = newNodeP(kind, p)
-  result.strVal = strVal
-
-proc newIdentNodeP(ident: PIdent, p: TParser): PNode =
-  result = newNodeP(nkIdent, p)
-  result.ident = ident
-
-proc parseExpr(p: var TParser): PNode
-proc parseStmt(p: var TParser): PNode
-proc parseTypeDesc(p: var TParser): PNode
-proc parseDoBlocks(p: var TParser, call: PNode)
-proc parseParamList(p: var TParser, retColon = true): PNode
-proc parseStmtPragma(p: var TParser): PNode
-proc parseCase(p: var TParser): PNode
-proc parseTry(p: var TParser): PNode
-
-proc isSigilLike(tok: TToken): bool {.inline.} =
-  result = tok.tokType == tkOpr and tok.ident.s[0] == '@'
-
-proc isAt(tok: TToken): bool {.inline.} =
-  tok.tokType == tkOpr and tok.ident.s == "@" and tok.strongSpaceB == 0
-
-proc isRightAssociative(tok: TToken): bool {.inline.} =
-  ## Determines whether the token is right assocative.
-  result = tok.tokType == tkOpr and tok.ident.s[0] == '^'
-  # or (let L = tok.ident.s.len; L > 1 and tok.ident.s[L-1] == '>'))
-
-proc getPrecedence(tok: TToken): int =
-  ## Calculates the precedence of the given token.
-  template considerStrongSpaces(x): untyped = x
-
-  case tok.tokType
-  of tkOpr:
-    let L = tok.ident.s.len
-    let relevantChar = tok.ident.s[0]
-
-    # arrow like?
-    if L > 1 and tok.ident.s[L-1] == '>' and
-      tok.ident.s[L-2] in {'-', '~', '='}: return considerStrongSpaces(1)
-
-    template considerAsgn(value: untyped) =
-      result = if tok.ident.s[L-1] == '=': 1 else: value
-
-    case relevantChar
-    of '$', '^': considerAsgn(10)
-    of '*', '%', '/', '\\': considerAsgn(9)
-    of '~': result = 8
-    of '+', '-', '|': considerAsgn(8)
-    of '&': considerAsgn(7)
-    of '=', '<', '>', '!': result = 5
-    of '.': considerAsgn(6)
-    of '?': result = 2
-    else: considerAsgn(2)
-  of tkDiv, tkMod, tkShl, tkShr: result = 9
-  of tkIn, tkNotin, tkIs, tkIsnot, tkNot, tkOf, tkAs: result = 5
-  of tkDotDot: result = 6
-  of tkAnd: result = 4
-  of tkOr, tkXor, tkPtr, tkRef: result = 3
-  else: return -10
-  result = considerStrongSpaces(result)
-
-proc isOperator(tok: TToken): bool =
-  ## Determines if the given token is an operator type token.
-  tok.tokType in {tkOpr, tkDiv, tkMod, tkShl, tkShr, tkIn, tkNotin, tkIs,
-                  tkIsnot, tkNot, tkOf, tkAs, tkDotDot, tkAnd, tkOr, tkXor}
-
-proc isUnary(p: TParser): bool =
-  ## Check if the current parser token is a unary operator
-  if p.tok.tokType in {tkOpr, tkDotDot}:
-      result = true
-
-proc checkBinary(p: TParser) {.inline.} =
-  ## Check if the current parser token is a binary operator.
-  # we don't check '..' here as that's too annoying
-  discard
-
-#| module = stmt ^* (';' / IND{=})
-#|
-#| comma = ',' COMMENT?
-#| semicolon = ';' COMMENT?
-#| colon = ':' COMMENT?
-#| colcom = ':' COMMENT?
-#|
-#| operator =  OP0 | OP1 | OP2 | OP3 | OP4 | OP5 | OP6 | OP7 | OP8 | OP9
-#|          | 'or' | 'xor' | 'and'
-#|          | 'is' | 'isnot' | 'in' | 'notin' | 'of'
-#|          | 'div' | 'mod' | 'shl' | 'shr' | 'not' | 'static' | '..'
-#|
-#| prefixOperator = operator
-#|
-#| optInd = COMMENT?
-#| optPar = (IND{>} | IND{=})?
-#|
-#| simpleExpr = arrowExpr (OP0 optInd arrowExpr)*
-#| arrowExpr = assignExpr (OP1 optInd assignExpr)*
-#| assignExpr = orExpr (OP2 optInd orExpr)*
-#| orExpr = andExpr (OP3 optInd andExpr)*
-#| andExpr = cmpExpr (OP4 optInd cmpExpr)*
-#| cmpExpr = sliceExpr (OP5 optInd sliceExpr)*
-#| sliceExpr = ampExpr (OP6 optInd ampExpr)*
-#| ampExpr = plusExpr (OP7 optInd plusExpr)*
-#| plusExpr = mulExpr (OP8 optInd mulExpr)*
-#| mulExpr = dollarExpr (OP9 optInd dollarExpr)*
-#| dollarExpr = primary (OP10 optInd primary)*
-
-proc colcom(p: var TParser, n: PNode) =
-  skipComment(p, n)
-
-proc parseSymbol(p: var TParser, allowNil = false): PNode =
-  #| symbol = '`' (KEYW|IDENT|literal|(operator|'('|')'|'['|']'|'{'|'}'|'=')+)+ '`'
-  #|        | IDENT | 'addr' | 'type'
-  case p.tok.tokType
-  of tkSymbol, tkAddr, tkType:
-    result = newIdentNodeP(p.tok.ident, p)
-    getTok(p)
-  of tkAccent:
-    result = newNodeP(nkAccQuoted, p)
-    getTok(p)
-    while true:
-      case p.tok.tokType
-      of tkAccent:
-        if result.len == 0:
-          parMessage(p, errIdentifierExpected, p.tok)
-        break
-      of tkOpr, tkDot, tkDotDot, tkEquals, tkParLe..tkParDotRi:
-        var accm = ""
-        while p.tok.tokType in {tkOpr, tkDot, tkDotDot, tkEquals,
-                                tkParLe..tkParDotRi}:
-          accm.add(tokToStr(p.tok))
-          getTok(p)
-        result.add(newIdentNodeP(p.lex.cache.getIdent(accm), p))
-      of tokKeywordLow..tokKeywordHigh, tkSymbol, tkIntLit..tkCharLit:
-        result.add(newIdentNodeP(p.lex.cache.getIdent(tokToStr(p.tok)), p))
-        getTok(p)
-      else:
-        parMessage(p, errIdentifierExpected, p.tok)
-        break
-    eat(p, tkAccent)
-  else:
-    if allowNil and p.tok.tokType == tkNil:
-      result = newNodeP(nkNilLit, p)
-      getTok(p)
-    else:
-      parMessage(p, errIdentifierExpected, p.tok)
-      # BUGFIX: We must consume a token here to prevent endless loops!
-      # But: this really sucks for idetools and keywords, so we don't do it
-      # if it is a keyword:
-      if not isKeyword(p.tok.tokType): getTok(p)
-      result = ast.emptyNode
-
-proc colonOrEquals(p: var TParser, a: PNode): PNode =
-  if p.tok.tokType == tkColon:
-    result = newNodeP(nkExprColonExpr, p)
-    getTok(p)
-    #optInd(p, result)
-    addSon(result, a)
-    addSon(result, parseExpr(p))
-  elif p.tok.tokType == tkEquals:
-    result = newNodeP(nkExprEqExpr, p)
-    getTok(p)
-    #optInd(p, result)
-    addSon(result, a)
-    addSon(result, parseExpr(p))
-  else:
-    result = a
-
-proc exprColonEqExpr(p: var TParser): PNode =
-  #| exprColonEqExpr = expr (':'|'=' expr)?
-  var a = parseExpr(p)
-  result = colonOrEquals(p, a)
-
-proc exprList(p: var TParser, endTok: TTokType, result: PNode) =
-  #| exprList = expr ^+ comma
-  getTok(p)
-  optInd(p, result)
-  while (p.tok.tokType != endTok) and (p.tok.tokType != tkEof):
-    var a = parseExpr(p)
-    addSon(result, a)
-    if p.tok.tokType != tkComma: break
-    getTok(p)
-    optInd(p, a)
-
-proc dotExpr(p: var TParser, a: PNode): PNode =
-  #| dotExpr = expr '.' optInd symbol
-  var info = p.parLineInfo
-  getTok(p)
-  result = newNodeI(nkDotExpr, info)
-  optInd(p, result)
-  addSon(result, a)
-  addSon(result, parseSymbol(p))
-
-proc qualifiedIdent(p: var TParser): PNode =
-  #| qualifiedIdent = symbol ('.' optInd symbol)?
-  result = parseSymbol(p)
-  if p.tok.tokType == tkDot: result = dotExpr(p, result)
-
-proc exprColonEqExprListAux(p: var TParser, endTok: TTokType, result: PNode) =
-  assert(endTok in {tkCurlyLe, tkCurlyRi, tkCurlyDotRi, tkBracketRi, tkParRi})
-  getTok(p)
-  optInd(p, result)
-  while p.tok.tokType != endTok and p.tok.tokType != tkEof:
-    var a = exprColonEqExpr(p)
-    addSon(result, a)
-    if p.tok.tokType != tkComma: break
-    getTok(p)
-    skipComment(p, a)
-  optPar(p)
-  eat(p, endTok)
-
-proc exprColonEqExprList(p: var TParser, kind: TNodeKind,
-                         endTok: TTokType): PNode =
-  #| exprColonEqExprList = exprColonEqExpr (comma exprColonEqExpr)* (comma)?
-  result = newNodeP(kind, p)
-  exprColonEqExprListAux(p, endTok, result)
-
-proc setOrTableConstr(p: var TParser): PNode =
-  result = newNodeP(nkCurly, p)
-  getTok(p)
-  optInd(p, result)
-  if p.tok.tokType == tkColon:
-    getTok(p) # skip ':'
-    result.kind = nkTableConstr
-  else:
-    while p.tok.tokType notin {tkBracketDotRi, tkEof}:
-      var a = exprColonEqExpr(p)
-      if a.kind == nkExprColonExpr: result.kind = nkTableConstr
-      addSon(result, a)
-      if p.tok.tokType != tkComma: break
-      getTok(p)
-      skipComment(p, a)
-  optPar(p)
-  eat(p, tkBracketDotRi)
-
-proc parseCast(p: var TParser): PNode =
-  #| castExpr = 'cast' '[' optInd typeDesc optPar ']' '(' optInd expr optPar ')'
-  result = newNodeP(nkCast, p)
-  getTok(p)
-  eat(p, tkBracketLe)
-  optInd(p, result)
-  addSon(result, parseTypeDesc(p))
-  optPar(p)
-  eat(p, tkBracketRi)
-  eat(p, tkParLe)
-  optInd(p, result)
-  addSon(result, parseExpr(p))
-  optPar(p)
-  eat(p, tkParRi)
-
-proc setBaseFlags(n: PNode, base: TNumericalBase) =
-  case base
-  of base10: discard
-  of base2: incl(n.flags, nfBase2)
-  of base8: incl(n.flags, nfBase8)
-  of base16: incl(n.flags, nfBase16)
-
-proc parseGStrLit(p: var TParser, a: PNode): PNode =
-  case p.tok.tokType
-  of tkGStrLit:
-    result = newNodeP(nkCallStrLit, p)
-    addSon(result, a)
-    addSon(result, newStrNodeP(nkRStrLit, p.tok.literal, p))
-    getTok(p)
-  of tkGTripleStrLit:
-    result = newNodeP(nkCallStrLit, p)
-    addSon(result, a)
-    addSon(result, newStrNodeP(nkTripleStrLit, p.tok.literal, p))
-    getTok(p)
-  else:
-    result = a
-
-type
-  TPrimaryMode = enum pmNormal, pmTypeDesc, pmTypeDef, pmSkipSuffix
-
-proc complexOrSimpleStmt(p: var TParser): PNode
-proc simpleExpr(p: var TParser, mode = pmNormal): PNode
-
-proc semiStmtList(p: var TParser, result: PNode) =
-  inc p.inSemiStmtList
-  result.add(complexOrSimpleStmt(p))
-  while p.tok.tokType == tkSemiColon:
-    getTok(p)
-    optInd(p, result)
-    result.add(complexOrSimpleStmt(p))
-  dec p.inSemiStmtList
-  result.kind = nkStmtListExpr
-
-proc parsePar(p: var TParser): PNode =
-  #| parKeyw = 'discard' | 'include' | 'if' | 'while' | 'case' | 'try'
-  #|         | 'finally' | 'except' | 'for' | 'block' | 'const' | 'let'
-  #|         | 'when' | 'var' | 'mixin'
-  #| par = '(' optInd
-  #|           ( &parKeyw complexOrSimpleStmt ^+ ';'
-  #|           | ';' complexOrSimpleStmt ^+ ';'
-  #|           | pragmaStmt
-  #|           | simpleExpr ( ('=' expr (';' complexOrSimpleStmt ^+ ';' )? )
-  #|                        | (':' expr (',' exprColonEqExpr     ^+ ',' )? ) ) )
-  #|           optPar ')'
-  #
-  # unfortunately it's ambiguous: (expr: expr) vs (exprStmt); however a
-  # leading ';' could be used to enforce a 'stmt' context ...
-  result = newNodeP(nkPar, p)
-  getTok(p)
-  optInd(p, result)
-  if p.tok.tokType in {tkDiscard, tkInclude, tkIf, tkWhile, tkCase,
-                       tkTry, tkDefer, tkFinally, tkExcept, tkFor, tkBlock,
-                       tkConst, tkLet, tkWhen, tkVar,
-                       tkMixin}:
-    # XXX 'bind' used to be an expression, so we exclude it here;
-    # tests/reject/tbind2 fails otherwise.
-    semiStmtList(p, result)
-  elif p.tok.tokType == tkSemiColon:
-    # '(;' enforces 'stmt' context:
-    getTok(p)
-    optInd(p, result)
-    semiStmtList(p, result)
-  elif p.tok.tokType == tkCurlyDotLe:
-    result.add(parseStmtPragma(p))
-  elif p.tok.tokType != tkParRi:
-    var a = simpleExpr(p)
-    if p.tok.tokType == tkEquals:
-      # special case: allow assignments
-      getTok(p)
-      optInd(p, result)
-      let b = parseExpr(p)
-      let asgn = newNodeI(nkAsgn, a.info, 2)
-      asgn.sons[0] = a
-      asgn.sons[1] = b
-      result.add(asgn)
-      if p.tok.tokType == tkSemiColon:
-        semiStmtList(p, result)
-    elif p.tok.tokType == tkSemiColon:
-      # stmt context:
-      result.add(a)
-      semiStmtList(p, result)
-    else:
-      a = colonOrEquals(p, a)
-      result.add(a)
-      if p.tok.tokType == tkComma:
-        getTok(p)
-        skipComment(p, a)
-        while p.tok.tokType != tkParRi and p.tok.tokType != tkEof:
-          var a = exprColonEqExpr(p)
-          addSon(result, a)
-          if p.tok.tokType != tkComma: break
-          getTok(p)
-          skipComment(p, a)
-  optPar(p)
-  eat(p, tkParRi)
-
-proc identOrLiteral(p: var TParser, mode: TPrimaryMode): PNode =
-  #| literal = | INT_LIT | INT8_LIT | INT16_LIT | INT32_LIT | INT64_LIT
-  #|           | UINT_LIT | UINT8_LIT | UINT16_LIT | UINT32_LIT | UINT64_LIT
-  #|           | FLOAT_LIT | FLOAT32_LIT | FLOAT64_LIT
-  #|           | STR_LIT | RSTR_LIT | TRIPLESTR_LIT
-  #|           | CHAR_LIT
-  #|           | NIL
-  #| generalizedLit = GENERALIZED_STR_LIT | GENERALIZED_TRIPLESTR_LIT
-  #| identOrLiteral = generalizedLit | symbol | literal
-  #|                | par | arrayConstr | setOrTableConstr
-  #|                | castExpr
-  #| tupleConstr = '(' optInd (exprColonEqExpr comma?)* optPar ')'
-  #| arrayConstr = '[' optInd (exprColonEqExpr comma?)* optPar ']'
-  case p.tok.tokType
-  of tkSymbol, tkType, tkAddr:
-    result = newIdentNodeP(p.tok.ident, p)
-    getTok(p)
-    result = parseGStrLit(p, result)
-  of tkAccent:
-    result = parseSymbol(p)       # literals
-  of tkIntLit:
-    result = newIntNodeP(nkIntLit, p.tok.iNumber, p)
-    setBaseFlags(result, p.tok.base)
-    getTok(p)
-  of tkInt8Lit:
-    result = newIntNodeP(nkInt8Lit, p.tok.iNumber, p)
-    setBaseFlags(result, p.tok.base)
-    getTok(p)
-  of tkInt16Lit:
-    result = newIntNodeP(nkInt16Lit, p.tok.iNumber, p)
-    setBaseFlags(result, p.tok.base)
-    getTok(p)
-  of tkInt32Lit:
-    result = newIntNodeP(nkInt32Lit, p.tok.iNumber, p)
-    setBaseFlags(result, p.tok.base)
-    getTok(p)
-  of tkInt64Lit:
-    result = newIntNodeP(nkInt64Lit, p.tok.iNumber, p)
-    setBaseFlags(result, p.tok.base)
-    getTok(p)
-  of tkUIntLit:
-    result = newIntNodeP(nkUIntLit, p.tok.iNumber, p)
-    setBaseFlags(result, p.tok.base)
-    getTok(p)
-  of tkUInt8Lit:
-    result = newIntNodeP(nkUInt8Lit, p.tok.iNumber, p)
-    setBaseFlags(result, p.tok.base)
-    getTok(p)
-  of tkUInt16Lit:
-    result = newIntNodeP(nkUInt16Lit, p.tok.iNumber, p)
-    setBaseFlags(result, p.tok.base)
-    getTok(p)
-  of tkUInt32Lit:
-    result = newIntNodeP(nkUInt32Lit, p.tok.iNumber, p)
-    setBaseFlags(result, p.tok.base)
-    getTok(p)
-  of tkUInt64Lit:
-    result = newIntNodeP(nkUInt64Lit, p.tok.iNumber, p)
-    setBaseFlags(result, p.tok.base)
-    getTok(p)
-  of tkFloatLit:
-    result = newFloatNodeP(nkFloatLit, p.tok.fNumber, p)
-    setBaseFlags(result, p.tok.base)
-    getTok(p)
-  of tkFloat32Lit:
-    result = newFloatNodeP(nkFloat32Lit, p.tok.fNumber, p)
-    setBaseFlags(result, p.tok.base)
-    getTok(p)
-  of tkFloat64Lit:
-    result = newFloatNodeP(nkFloat64Lit, p.tok.fNumber, p)
-    setBaseFlags(result, p.tok.base)
-    getTok(p)
-  of tkFloat128Lit:
-    result = newFloatNodeP(nkFloat128Lit, p.tok.fNumber, p)
-    setBaseFlags(result, p.tok.base)
-    getTok(p)
-  of tkStrLit:
-    result = newStrNodeP(nkStrLit, p.tok.literal, p)
-    getTok(p)
-  of tkRStrLit:
-    result = newStrNodeP(nkRStrLit, p.tok.literal, p)
-    getTok(p)
-  of tkTripleStrLit:
-    result = newStrNodeP(nkTripleStrLit, p.tok.literal, p)
-    getTok(p)
-  of tkCharLit:
-    result = newIntNodeP(nkCharLit, ord(p.tok.literal[0]), p)
-    getTok(p)
-  of tkNil:
-    result = newNodeP(nkNilLit, p)
-    getTok(p)
-  of tkParLe:
-    # () constructor
-    if mode in {pmTypeDesc, pmTypeDef}:
-      result = exprColonEqExprList(p, nkPar, tkParRi)
-    else:
-      result = parsePar(p)
-  of tkBracketDotLe:
-    # {} constructor
-    result = setOrTableConstr(p)
-  of tkBracketLe:
-    # [] constructor
-    result = exprColonEqExprList(p, nkBracket, tkBracketRi)
-  of tkCast:
-    result = parseCast(p)
-  else:
-    parMessage(p, errExprExpected, p.tok)
-    getTok(p)  # we must consume a token here to prevend endless loops!
-    result = ast.emptyNode
-
-proc namedParams(p: var TParser, callee: PNode,
-                 kind: TNodeKind, endTok: TTokType): PNode =
-  let a = callee
-  result = newNodeP(kind, p)
-  addSon(result, a)
-  exprColonEqExprListAux(p, endTok, result)
-
-proc parseMacroColon(p: var TParser, x: PNode): PNode
-proc primarySuffix(p: var TParser, r: PNode): PNode =
-  #| primarySuffix = '(' (exprColonEqExpr comma?)* ')' doBlocks?
-  #|       | doBlocks
-  #|       | '.' optInd symbol generalizedLit?
-  #|       | '[' optInd indexExprList optPar ']'
-  #|       | '{' optInd indexExprList optPar '}'
-  #|       | &( '`'|IDENT|literal|'cast'|'addr'|'type') expr # command syntax
-  result = r
-
-  template somePar() = discard
-  while p.tok.indent < 0:
-    case p.tok.tokType
-    of tkParLe:
-      somePar()
-      result = namedParams(p, result, nkCall, tkParRi)
-      if result.len > 1 and result.sons[1].kind == nkExprColonExpr:
-        result.kind = nkObjConstr
-      else:
-        parseDoBlocks(p, result)
-    of tkDo:
-      var a = result
-      result = newNodeP(nkCall, p)
-      addSon(result, a)
-      parseDoBlocks(p, result)
-    of tkDot:
-      result = dotExpr(p, result)
-      result = parseGStrLit(p, result)
-    of tkBracketLe:
-      somePar()
-      result = namedParams(p, result, nkBracketExpr, tkBracketRi)
-    of tkBracketDotLe:
-      somePar()
-      result = namedParams(p, result, nkCurlyExpr, tkBracketDotRi)
-    of tkSymbol, tkAccent, tkIntLit..tkCharLit, tkNil, tkCast, tkAddr, tkType:
-      if p.inPragma == 0:
-        # actually parsing {.push hints:off.} as {.push(hints:off).} is a sweet
-        # solution, but pragmas.nim can't handle that
-        let a = result
-        result = newNodeP(nkCommand, p)
-        addSon(result, a)
-        when true:
-          addSon result, parseExpr(p)
-        else:
-          while p.tok.tokType != tkEof:
-            let x = parseExpr(p)
-            addSon(result, x)
-            if p.tok.tokType != tkComma: break
-            getTok(p)
-            optInd(p, x)
-          if p.tok.tokType == tkDo:
-            parseDoBlocks(p, result)
-          else:
-            result = parseMacroColon(p, result)
-      break
-    else:
-      break
-
-proc primary(p: var TParser, mode: TPrimaryMode): PNode
-proc simpleExprAux(p: var TParser, limit: int, mode: TPrimaryMode): PNode
-
-proc parseOperators(p: var TParser, headNode: PNode,
-                    limit: int, mode: TPrimaryMode): PNode =
-  result = headNode
-  # expand while operators have priorities higher than 'limit'
-  var opPrec = getPrecedence(p.tok)
-  let modeB = if mode == pmTypeDef: pmTypeDesc else: mode
-  # the operator itself must not start on a new line:
-  while opPrec >= limit and p.tok.indent < 0 and not isAt(p.tok):
-    checkBinary(p)
-    var leftAssoc = 1-ord(isRightAssociative(p.tok))
-    var a = newNodeP(nkInfix, p)
-    var opNode = newIdentNodeP(p.tok.ident, p) # skip operator:
-    getTok(p)
-    optInd(p, a)
-    # read sub-expression with higher priority:
-    var b = simpleExprAux(p, opPrec + leftAssoc, modeB)
-    addSon(a, opNode)
-    addSon(a, result)
-    addSon(a, b)
-    result = a
-    opPrec = getPrecedence(p.tok)
-
-proc simpleExprAux(p: var TParser, limit: int, mode: TPrimaryMode): PNode =
-  result = primary(p, mode)
-  result = parseOperators(p, result, limit, mode)
-
-proc simpleExpr(p: var TParser, mode = pmNormal): PNode =
-  result = simpleExprAux(p, -1, mode)
-
-proc parseIfExpr(p: var TParser, kind: TNodeKind): PNode =
-  #| condExpr = expr colcom expr optInd
-  #|         ('elif' expr colcom expr optInd)*
-  #|          'else' colcom expr
-  #| ifExpr = 'if' condExpr
-  #| whenExpr = 'when' condExpr
-  result = newNodeP(kind, p)
-  while true:
-    getTok(p)                 # skip `if`, `elif`
-    var branch = newNodeP(nkElifExpr, p)
-    addSon(branch, parseExpr(p))
-    colcom(p, branch)
-    addSon(branch, parseExpr(p))
-    optInd(p, branch)
-    addSon(result, branch)
-    if p.tok.tokType != tkElif: break
-  var branch = newNodeP(nkElseExpr, p)
-  eat(p, tkElse)
-  colcom(p, branch)
-  addSon(branch, parseExpr(p))
-  addSon(result, branch)
-
-proc parsePragma(p: var TParser): PNode =
-  result = newNodeP(nkPragma, p)
-  inc p.inPragma
-  if isAt(p.tok):
-    while isAt(p.tok):
-      getTok(p)
-      var a = parseExpr(p)
-      optInd(p, a)
-      if a.kind in nkCallKinds and a.len == 2:
-        let repaired = newNodeI(nkExprColonExpr, a.info)
-        repaired.add a[0]
-        repaired.add a[1]
-        a = repaired
-      addSon(result, a)
-      skipComment(p, a)
-  else:
-    getTok(p)
-    optInd(p, result)
-    while p.tok.tokType notin {tkCurlyDotRi, tkCurlyRi, tkEof}:
-      var a = exprColonEqExpr(p)
-      addSon(result, a)
-      if p.tok.tokType == tkComma:
-        getTok(p)
-        skipComment(p, a)
-    optPar(p)
-    if p.tok.tokType in {tkCurlyDotRi, tkCurlyRi}: getTok(p)
-    else: parMessage(p, errTokenExpected, ".}")
-  dec p.inPragma
-
-proc identVis(p: var TParser; allowDot=false): PNode =
-  #| identVis = symbol opr?  # postfix position
-  #| identVisDot = symbol '.' optInd symbol opr?
-  var a = parseSymbol(p)
-  if p.tok.tokType == tkOpr:
-    result = newNodeP(nkPostfix, p)
-    addSon(result, newIdentNodeP(p.tok.ident, p))
-    addSon(result, a)
-    getTok(p)
-  elif p.tok.tokType == tkDot and allowDot:
-    result = dotExpr(p, a)
-  else:
-    result = a
-
-proc identWithPragma(p: var TParser; allowDot=false): PNode =
-  #| identWithPragma = identVis pragma?
-  #| identWithPragmaDot = identVisDot pragma?
-  var a = identVis(p, allowDot)
-  if p.tok.tokType == tkCurlyDotLe or isAt(p.tok):
-    result = newNodeP(nkPragmaExpr, p)
-    addSon(result, a)
-    addSon(result, parsePragma(p))
-  else:
-    result = a
-
-type
-  TDeclaredIdentFlag = enum
-    withPragma,               # identifier may have pragma
-    withBothOptional          # both ':' and '=' parts are optional
-  TDeclaredIdentFlags = set[TDeclaredIdentFlag]
-
-proc parseIdentColonEquals(p: var TParser, flags: TDeclaredIdentFlags): PNode =
-  #| declColonEquals = identWithPragma (comma identWithPragma)* comma?
-  #|                   (':' optInd typeDesc)? ('=' optInd expr)?
-  #| identColonEquals = ident (comma ident)* comma?
-  #|      (':' optInd typeDesc)? ('=' optInd expr)?)
-  var a: PNode
-  result = newNodeP(nkIdentDefs, p)
-  while true:
-    case p.tok.tokType
-    of tkSymbol, tkAccent:
-      if withPragma in flags: a = identWithPragma(p)
-      else: a = parseSymbol(p)
-      if a.kind == nkEmpty: return
-    else: break
-    addSon(result, a)
-    if p.tok.tokType != tkComma: break
-    getTok(p)
-    optInd(p, a)
-  if p.tok.tokType == tkColon:
-    getTok(p)
-    optInd(p, result)
-    addSon(result, parseTypeDesc(p))
-  else:
-    addSon(result, ast.emptyNode)
-    if p.tok.tokType != tkEquals and withBothOptional notin flags:
-      parMessage(p, errColonOrEqualsExpected, p.tok)
-  if p.tok.tokType == tkEquals:
-    getTok(p)
-    optInd(p, result)
-    addSon(result, parseExpr(p))
-  else:
-    addSon(result, ast.emptyNode)
-
-proc parseTuple(p: var TParser): PNode =
-  result = newNodeP(nkTupleTy, p)
-  getTok(p)
-  if p.tok.tokType in {tkBracketLe, tkCurlyLe}:
-    let usedCurly = p.tok.tokType == tkCurlyLe
-    getTok(p)
-    optInd(p, result)
-    while p.tok.tokType in {tkSymbol, tkAccent}:
-      var a = parseIdentColonEquals(p, {})
-      addSon(result, a)
-      if p.tok.tokType notin {tkComma, tkSemiColon}: break
-      getTok(p)
-      skipComment(p, a)
-    optPar(p)
-    if usedCurly: eat(p, tkCurlyRi)
-    else: eat(p, tkBracketRi)
-  else:
-    result = newNodeP(nkTupleClassTy, p)
-
-proc parseParamList(p: var TParser, retColon = true): PNode =
-  #| paramList = '(' declColonEquals ^* (comma/semicolon) ')'
-  #| paramListArrow = paramList? ('->' optInd typeDesc)?
-  #| paramListColon = paramList? (':' optInd typeDesc)?
-  var a: PNode
-  result = newNodeP(nkFormalParams, p)
-  addSon(result, ast.emptyNode) # return type
-  let hasParLe = p.tok.tokType == tkParLe and p.tok.indent < 0
-  if hasParLe:
-    getTok(p)
-    optInd(p, result)
-    while true:
-      case p.tok.tokType
-      of tkSymbol, tkAccent:
-        a = parseIdentColonEquals(p, {withBothOptional, withPragma})
-      of tkParRi:
-        break
-      else:
-        parMessage(p, errTokenExpected, ")")
-        break
-      addSon(result, a)
-      if p.tok.tokType notin {tkComma, tkSemiColon}: break
-      getTok(p)
-      skipComment(p, a)
-    optPar(p)
-    eat(p, tkParRi)
-  let hasRet = if retColon: p.tok.tokType == tkColon
-               else: p.tok.tokType == tkOpr and p.tok.ident.s == "->"
-  if hasRet and p.tok.indent < 0:
-    getTok(p)
-    optInd(p, result)
-    result.sons[0] = parseTypeDesc(p)
-  elif not retColon and not hasParle:
-    # Mark as "not there" in order to mark for deprecation in the semantic pass:
-    result = ast.emptyNode
-
-proc optPragmas(p: var TParser): PNode =
-  if p.tok.tokType == tkCurlyDotLe or isAt(p.tok):
-    result = parsePragma(p)
-  else:
-    result = ast.emptyNode
-
-proc parseDoBlock(p: var TParser): PNode =
-  #| doBlock = 'do' paramListArrow pragmas? colcom stmt
-  let info = parLineInfo(p)
-  getTok(p)
-  let params = parseParamList(p, retColon=false)
-  let pragmas = optPragmas(p)
-  colcom(p, result)
-  result = newProcNode(nkDo, info, parseStmt(p),
-                       params = params,
-                       pragmas = pragmas)
-
-proc parseDoBlocks(p: var TParser, call: PNode) =
-  #| doBlocks = doBlock ^* IND{=}
-  while p.tok.tokType == tkDo:
-    addSon(call, parseDoBlock(p))
-
-proc parseCurlyStmt(p: var TParser): PNode =
-  result = newNodeP(nkStmtList, p)
-  eat(p, tkCurlyLe)
-  result.add parseStmt(p)
-  while p.tok.tokType notin {tkEof, tkCurlyRi}:
-    if p.tok.tokType == tkSemicolon: getTok(p)
-    elif p.tok.indent < 0: break
-    result.add parseStmt(p)
-  eat(p, tkCurlyRi)
-
-proc parseProcExpr(p: var TParser, isExpr: bool): PNode =
-  #| procExpr = 'proc' paramListColon pragmas? ('=' COMMENT? stmt)?
-  # either a proc type or a anonymous proc
-  let info = parLineInfo(p)
-  getTok(p)
-  let hasSignature = p.tok.tokType in {tkParLe, tkColon} and p.tok.indent < 0
-  let params = parseParamList(p)
-  let pragmas = optPragmas(p)
-  if p.tok.tokType == tkCurlyLe and isExpr:
-    result = newProcNode(nkLambda, info, parseCurlyStmt(p),
-                         params = params,
-                         pragmas = pragmas)
-  else:
-    result = newNodeI(nkProcTy, info)
-    if hasSignature:
-      addSon(result, params)
-      addSon(result, pragmas)
-
-proc isExprStart(p: TParser): bool =
-  case p.tok.tokType
-  of tkSymbol, tkAccent, tkOpr, tkNot, tkNil, tkCast, tkIf,
-     tkProc, tkIterator, tkBind, tkAddr,
-     tkParLe, tkBracketLe, tkCurlyLe, tkIntLit..tkCharLit, tkVar, tkRef, tkPtr,
-     tkTuple, tkObject, tkType, tkWhen, tkCase, tkOut:
-    result = true
-  else: result = false
-
-proc parseSymbolList(p: var TParser, result: PNode, allowNil = false) =
-  while true:
-    var s = parseSymbol(p, allowNil)
-    if s.kind == nkEmpty: break
-    addSon(result, s)
-    if p.tok.tokType != tkComma: break
-    getTok(p)
-    optInd(p, s)
-
-proc parseTypeDescKAux(p: var TParser, kind: TNodeKind,
-                       mode: TPrimaryMode): PNode =
-  #| distinct = 'distinct' optInd typeDesc
-  result = newNodeP(kind, p)
-  getTok(p)
-  optInd(p, result)
-  if not isOperator(p.tok) and isExprStart(p):
-    addSon(result, primary(p, mode))
-  if kind == nkDistinctTy and p.tok.tokType == tkSymbol:
-    var nodeKind: TNodeKind
-    if p.tok.ident.s == "with":
-      nodeKind = nkWith
-    elif p.tok.ident.s == "without":
-      nodeKind = nkWithout
-    else:
-      return result
-    getTok(p)
-    let list = newNodeP(nodeKind, p)
-    result.addSon list
-    parseSymbolList(p, list, allowNil = true)
-
-proc parseExpr(p: var TParser): PNode =
-  #| expr = (ifExpr
-  #|       | whenExpr
-  #|       | caseExpr
-  #|       | tryExpr)
-  #|       / simpleExpr
-  case p.tok.tokType:
-  of tkIf: result = parseIfExpr(p, nkIfExpr)
-  of tkWhen: result = parseIfExpr(p, nkWhenExpr)
-  of tkCase: result = parseCase(p)
-  of tkTry: result = parseTry(p)
-  else: result = simpleExpr(p)
-
-proc parseEnum(p: var TParser): PNode
-proc parseObject(p: var TParser): PNode
-proc parseTypeClass(p: var TParser): PNode
-
-proc primary(p: var TParser, mode: TPrimaryMode): PNode =
-  #| typeKeyw = 'var' | 'out' | 'ref' | 'ptr' | 'shared' | 'tuple'
-  #|          | 'proc' | 'iterator' | 'distinct' | 'object' | 'enum'
-  #| primary = typeKeyw typeDescK
-  #|         /  prefixOperator* identOrLiteral primarySuffix*
-  #|         / 'static' primary
-  #|         / 'bind' primary
-  if isOperator(p.tok):
-    let isSigil = isSigilLike(p.tok)
-    result = newNodeP(nkPrefix, p)
-    var a = newIdentNodeP(p.tok.ident, p)
-    addSon(result, a)
-    getTok(p)
-    optInd(p, a)
-    if isSigil:
-      #XXX prefix operators
-      addSon(result, primary(p, pmSkipSuffix))
-      result = primarySuffix(p, result)
-    else:
-      addSon(result, primary(p, pmNormal))
-    return
-
-  case p.tok.tokType:
-  of tkTuple: result = parseTuple(p)
-  of tkProc: result = parseProcExpr(p, mode notin {pmTypeDesc, pmTypeDef})
-  of tkIterator:
-    result = parseProcExpr(p, mode notin {pmTypeDesc, pmTypeDef})
-    if result.kind == nkLambda: result.kind = nkIteratorDef
-    else: result.kind = nkIteratorTy
-  of tkEnum:
-    if mode == pmTypeDef:
-      result = parseEnum(p)
-    else:
-      result = newNodeP(nkEnumTy, p)
-      getTok(p)
-  of tkObject:
-    if mode == pmTypeDef:
-      result = parseObject(p)
-    else:
-      result = newNodeP(nkObjectTy, p)
-      getTok(p)
-  of tkConcept:
-    if mode == pmTypeDef:
-      result = parseTypeClass(p)
-    else:
-      parMessage(p, errInvalidToken, p.tok)
-  of tkStatic:
-    let info = parLineInfo(p)
-    getTokNoInd(p)
-    let next = primary(p, pmNormal)
-    if next.kind == nkBracket and next.sonsLen == 1:
-      result = newNode(nkStaticTy, info, @[next.sons[0]])
-    else:
-      result = newNode(nkStaticExpr, info, @[next])
-  of tkBind:
-    result = newNodeP(nkBind, p)
-    getTok(p)
-    optInd(p, result)
-    addSon(result, primary(p, pmNormal))
-  of tkVar: result = parseTypeDescKAux(p, nkVarTy, mode)
-  of tkOut: result = parseTypeDescKAux(p, nkVarTy, mode)
-  of tkRef: result = parseTypeDescKAux(p, nkRefTy, mode)
-  of tkPtr: result = parseTypeDescKAux(p, nkPtrTy, mode)
-  of tkDistinct: result = parseTypeDescKAux(p, nkDistinctTy, mode)
-  else:
-    result = identOrLiteral(p, mode)
-    if mode != pmSkipSuffix:
-      result = primarySuffix(p, result)
-
-proc parseTypeDesc(p: var TParser): PNode =
-  #| typeDesc = simpleExpr
-  result = simpleExpr(p, pmTypeDesc)
-
-proc parseTypeDefAux(p: var TParser): PNode =
-  #| typeDefAux = simpleExpr
-  #|            | 'concept' typeClass
-  result = simpleExpr(p, pmTypeDef)
-
-proc makeCall(n: PNode): PNode =
-  ## Creates a call if the given node isn't already a call.
-  if n.kind in nkCallKinds:
-    result = n
-  else:
-    result = newNodeI(nkCall, n.info)
-    result.add n
-
-proc parseMacroColon(p: var TParser, x: PNode): PNode =
-  #| macroColon = ':' stmt? ( IND{=} 'of' exprList ':' stmt
-  #|                        | IND{=} 'elif' expr ':' stmt
-  #|                        | IND{=} 'except' exprList ':' stmt
-  #|                        | IND{=} 'else' ':' stmt )*
-  result = x
-  if p.tok.tokType == tkColon and p.tok.indent < 0:
-    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)
-      stmtList.add body
-      #addSon(result, makeStmtList(body))
-    while true:
-      var b: PNode
-      case p.tok.tokType
-      of tkOf:
-        b = newNodeP(nkOfBranch, p)
-        exprList(p, tkCurlyLe, b)
-      of tkElif:
-        b = newNodeP(nkElifBranch, p)
-        getTok(p)
-        optInd(p, b)
-        addSon(b, parseExpr(p))
-      of tkExcept:
-        b = newNodeP(nkExceptBranch, p)
-        exprList(p, tkCurlyLe, b)
-      of tkElse:
-        b = newNodeP(nkElse, p)
-        getTok(p)
-      else: break
-      addSon(b, parseCurlyStmt(p))
-      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
-  #|          (( '=' optInd expr )
-  #|          / ( expr ^+ comma
-  #|              doBlocks
-  #|               / macroColon
-  #|            ))?
-  var a = simpleExpr(p)
-  if p.tok.tokType == tkEquals:
-    getTok(p)
-    optInd(p, result)
-    var b = parseExpr(p)
-    result = newNodeI(nkAsgn, a.info)
-    addSon(result, a)
-    addSon(result, b)
-  else:
-    # simpleExpr parsed 'p a' from 'p a, b'?
-    if p.tok.indent < 0 and p.tok.tokType == tkComma and a.kind == nkCommand:
-      result = a
-      while true:
-        getTok(p)
-        optInd(p, result)
-        var e = parseExpr(p)
-        addSon(result, e)
-        if p.tok.tokType != tkComma: break
-    elif p.tok.indent < 0 and isExprStart(p):
-      if a.kind == nkCommand:
-        result = a
-      else:
-        result = newNode(nkCommand, a.info, @[a])
-      while true:
-        var e = parseExpr(p)
-        addSon(result, e)
-        if p.tok.tokType != tkComma: break
-        getTok(p)
-        optInd(p, result)
-    else:
-      result = a
-    if p.tok.tokType == tkDo and p.tok.indent < 0:
-      result = makeCall(result)
-      parseDoBlocks(p, result)
-      return result
-    result = parseMacroColon(p, result)
-
-proc parseModuleName(p: var TParser, kind: TNodeKind): PNode =
-  result = parseExpr(p)
-
-proc parseImport(p: var TParser, kind: TNodeKind): PNode =
-  #| importStmt = 'import' optInd expr
-  #|               ((comma expr)*
-  #|               / 'except' optInd (expr ^+ comma))
-  result = newNodeP(kind, p)
-  getTok(p)                   # skip `import` or `export`
-  optInd(p, result)
-  var a = parseModuleName(p, kind)
-  addSon(result, a)
-  if p.tok.tokType in {tkComma, tkExcept}:
-    if p.tok.tokType == tkExcept:
-      result.kind = succ(kind)
-    getTok(p)
-    optInd(p, result)
-    while true:
-      # was: while p.tok.tokType notin {tkEof, tkSad, tkDed}:
-      a = parseModuleName(p, kind)
-      if a.kind == nkEmpty: break
-      addSon(result, a)
-      if p.tok.tokType != tkComma: break
-      getTok(p)
-      optInd(p, a)
-  #expectNl(p)
-
-proc parseIncludeStmt(p: var TParser): PNode =
-  #| includeStmt = 'include' optInd expr ^+ comma
-  result = newNodeP(nkIncludeStmt, p)
-  getTok(p)                   # skip `import` or `include`
-  optInd(p, result)
-  while true:
-    # was: while p.tok.tokType notin {tkEof, tkSad, tkDed}:
-    var a = parseExpr(p)
-    if a.kind == nkEmpty: break
-    addSon(result, a)
-    if p.tok.tokType != tkComma: break
-    getTok(p)
-    optInd(p, a)
-  #expectNl(p)
-
-proc parseFromStmt(p: var TParser): PNode =
-  #| fromStmt = 'from' moduleName 'import' optInd expr (comma expr)*
-  result = newNodeP(nkFromStmt, p)
-  getTok(p)                   # skip `from`
-  optInd(p, result)
-  var a = parseModuleName(p, nkImportStmt)
-  addSon(result, a)           #optInd(p, a);
-  eat(p, tkImport)
-  optInd(p, result)
-  while true:
-    # p.tok.tokType notin {tkEof, tkSad, tkDed}:
-    a = parseExpr(p)
-    if a.kind == nkEmpty: break
-    addSon(result, a)
-    if p.tok.tokType != tkComma: break
-    getTok(p)
-    optInd(p, a)
-  #expectNl(p)
-
-proc parseReturnOrRaise(p: var TParser, kind: TNodeKind): PNode =
-  #| returnStmt = 'return' optInd expr?
-  #| raiseStmt = 'raise' optInd expr?
-  #| yieldStmt = 'yield' optInd expr?
-  #| discardStmt = 'discard' optInd expr?
-  #| breakStmt = 'break' optInd expr?
-  #| continueStmt = 'break' optInd expr?
-  result = newNodeP(kind, p)
-  getTok(p)
-  if p.tok.tokType == tkComment:
-    skipComment(p, result)
-    addSon(result, ast.emptyNode)
-  elif p.tok.indent >= 0 or not isExprStart(p):
-    # NL terminates:
-    addSon(result, ast.emptyNode)
-  else:
-    addSon(result, parseExpr(p))
-
-proc parseIfOrWhen(p: var TParser, kind: TNodeKind): PNode =
-  #| condStmt = expr colcom stmt COMMENT?
-  #|            (IND{=} 'elif' expr colcom stmt)*
-  #|            (IND{=} 'else' colcom stmt)?
-  #| ifStmt = 'if' condStmt
-  #| whenStmt = 'when' condStmt
-  result = newNodeP(kind, p)
-  while true:
-    getTok(p)                 # skip `if`, `when`, `elif`
-    var branch = newNodeP(nkElifBranch, p)
-    optInd(p, branch)
-    addSon(branch, parseExpr(p))
-    colcom(p, branch)
-    addSon(branch, parseCurlyStmt(p))
-    skipComment(p, branch)
-    addSon(result, branch)
-    if p.tok.tokType != tkElif: break
-  if p.tok.tokType == tkElse:
-    var branch = newNodeP(nkElse, p)
-    eat(p, tkElse)
-    addSon(branch, parseCurlyStmt(p))
-    addSon(result, branch)
-
-proc parseWhile(p: var TParser): PNode =
-  #| whileStmt = 'while' expr colcom stmt
-  result = newNodeP(nkWhileStmt, p)
-  getTok(p)
-  optInd(p, result)
-  addSon(result, parseExpr(p))
-  colcom(p, result)
-  addSon(result, parseCurlyStmt(p))
-
-proc parseCase(p: var TParser): PNode =
-  #| ofBranch = 'of' exprList colcom stmt
-  #| ofBranches = ofBranch (IND{=} ofBranch)*
-  #|                       (IND{=} 'elif' expr colcom stmt)*
-  #|                       (IND{=} 'else' colcom stmt)?
-  #| caseStmt = 'case' expr ':'? COMMENT?
-  #|             (IND{>} ofBranches DED
-  #|             | IND{=} ofBranches)
-  var
-    b: PNode
-    inElif= false
-  result = newNodeP(nkCaseStmt, p)
-  getTok(p)
-  addSon(result, parseExpr(p))
-  eat(p, tkCurlyLe)
-  skipComment(p, result)
-
-  while true:
-    case p.tok.tokType
-    of tkOf:
-      if inElif: break
-      b = newNodeP(nkOfBranch, p)
-      exprList(p, tkCurlyLe, b)
-    of tkElif:
-      inElif = true
-      b = newNodeP(nkElifBranch, p)
-      getTok(p)
-      optInd(p, b)
-      addSon(b, parseExpr(p))
-    of tkElse:
-      b = newNodeP(nkElse, p)
-      getTok(p)
-    else: break
-    skipComment(p, b)
-    addSon(b, parseCurlyStmt(p))
-    addSon(result, b)
-    if b.kind == nkElse: break
-  eat(p, tkCurlyRi)
-
-proc parseTry(p: var TParser): PNode =
-  #| tryStmt = 'try' colcom stmt &(IND{=}? 'except'|'finally')
-  #|            (IND{=}? 'except' exprList colcom stmt)*
-  #|            (IND{=}? 'finally' colcom stmt)?
-  #| tryExpr = 'try' colcom stmt &(optInd 'except'|'finally')
-  #|            (optInd 'except' exprList colcom stmt)*
-  #|            (optInd 'finally' colcom stmt)?
-  result = newNodeP(nkTryStmt, p)
-  getTok(p)
-  colcom(p, result)
-  addSon(result, parseCurlyStmt(p))
-  var b: PNode = nil
-  while true:
-    case p.tok.tokType
-    of tkExcept:
-      b = newNodeP(nkExceptBranch, p)
-      exprList(p, tkCurlyLe, b)
-    of tkFinally:
-      b = newNodeP(nkFinally, p)
-      getTok(p)
-    else: break
-    skipComment(p, b)
-    addSon(b, parseCurlyStmt(p))
-    addSon(result, b)
-    if b.kind == nkFinally: break
-  if b == nil: parMessage(p, errTokenExpected, "except")
-
-proc parseFor(p: var TParser): PNode =
-  #| forStmt = 'for' (identWithPragma ^+ comma) 'in' expr colcom stmt
-  result = newNodeP(nkForStmt, p)
-  getTokNoInd(p)
-  var a = identWithPragma(p)
-  addSon(result, a)
-  while p.tok.tokType == tkComma:
-    getTok(p)
-    optInd(p, a)
-    a = identWithPragma(p)
-    addSon(result, a)
-  eat(p, tkIn)
-  addSon(result, parseExpr(p))
-  colcom(p, result)
-  addSon(result, parseCurlyStmt(p))
-
-proc parseBlock(p: var TParser): PNode =
-  #| blockStmt = 'block' symbol? colcom stmt
-  result = newNodeP(nkBlockStmt, p)
-  getTokNoInd(p)
-  if p.tok.tokType == tkCurlyLe: addSon(result, ast.emptyNode)
-  else: addSon(result, parseSymbol(p))
-  colcom(p, result)
-  addSon(result, parseCurlyStmt(p))
-
-proc parseStaticOrDefer(p: var TParser; k: TNodeKind): PNode =
-  #| staticStmt = 'static' colcom stmt
-  #| deferStmt = 'defer' colcom stmt
-  result = newNodeP(k, p)
-  getTok(p)
-  colcom(p, result)
-  addSon(result, parseCurlyStmt(p))
-
-proc parseAsm(p: var TParser): PNode =
-  #| asmStmt = 'asm' pragma? (STR_LIT | RSTR_LIT | TRIPLE_STR_LIT)
-  result = newNodeP(nkAsmStmt, p)
-  getTokNoInd(p)
-  if p.tok.tokType == tkCurlyDotLe or isAt(p.tok): addSon(result, parsePragma(p))
-  else: addSon(result, ast.emptyNode)
-  case p.tok.tokType
-  of tkStrLit: addSon(result, newStrNodeP(nkStrLit, p.tok.literal, p))
-  of tkRStrLit: addSon(result, newStrNodeP(nkRStrLit, p.tok.literal, p))
-  of tkTripleStrLit: addSon(result,
-                            newStrNodeP(nkTripleStrLit, p.tok.literal, p))
-  else:
-    parMessage(p, errStringLiteralExpected)
-    addSon(result, ast.emptyNode)
-    return
-  getTok(p)
-
-proc parseGenericParam(p: var TParser): PNode =
-  #| genericParam = symbol (comma symbol)* (colon expr)? ('=' optInd expr)?
-  var a: PNode
-  result = newNodeP(nkIdentDefs, p)
-  while true:
-    case p.tok.tokType
-    of tkIn, tkOut:
-      let t = p.tok.tokType
-      getTok(p)
-      expectIdent(p)
-      a = parseSymbol(p)
-    of tkSymbol, tkAccent:
-      a = parseSymbol(p)
-      if a.kind == nkEmpty: return
-    else: break
-    addSon(result, a)
-    if p.tok.tokType != tkComma: break
-    getTok(p)
-    optInd(p, a)
-  if p.tok.tokType == tkColon:
-    getTok(p)
-    optInd(p, result)
-    addSon(result, parseExpr(p))
-  else:
-    addSon(result, ast.emptyNode)
-  if p.tok.tokType == tkEquals:
-    getTok(p)
-    optInd(p, result)
-    addSon(result, parseExpr(p))
-  else:
-    addSon(result, ast.emptyNode)
-
-proc parseGenericParamList(p: var TParser): PNode =
-  #| genericParamList = '[' optInd
-  #|   genericParam ^* (comma/semicolon) optPar ']'
-  result = newNodeP(nkGenericParams, p)
-  getTok(p)
-  optInd(p, result)
-  while p.tok.tokType in {tkSymbol, tkAccent}:
-    var a = parseGenericParam(p)
-    addSon(result, a)
-    if p.tok.tokType notin {tkComma, tkSemiColon}: break
-    getTok(p)
-    skipComment(p, a)
-  optPar(p)
-  eat(p, tkBracketRi)
-
-proc parsePattern(p: var TParser): PNode =
-  eat(p, tkBracketDotLe)
-  result = parseStmt(p)
-  eat(p, tkBracketDotRi)
-
-proc validInd(p: TParser): bool = p.tok.indent < 0
-
-proc parseRoutine(p: var TParser, kind: TNodeKind): PNode =
-  #| indAndComment = (IND{>} COMMENT)? | COMMENT?
-  #| routine = optInd identVis pattern? genericParamList?
-  #|   paramListColon pragma? ('=' COMMENT? stmt)? indAndComment
-  result = newNodeP(kind, p)
-  getTok(p)
-  optInd(p, result)
-  addSon(result, identVis(p))
-  if p.tok.tokType == tkBracketDotLe and p.validInd:
-    addSon(result, p.parsePattern)
-  else:
-    addSon(result, ast.emptyNode)
-  if p.tok.tokType == tkBracketLe and p.validInd:
-    result.add(p.parseGenericParamList)
-  else:
-    addSon(result, ast.emptyNode)
-  addSon(result, p.parseParamList)
-  if (p.tok.tokType == tkCurlyDotLe or isAt(p.tok)) and p.validInd:
-    addSon(result, p.parsePragma)
-  else:
-    addSon(result, ast.emptyNode)
-  # empty exception tracking:
-  addSon(result, ast.emptyNode)
-  if p.tok.tokType == tkCurlyLe:
-    addSon(result, parseCurlyStmt(p))
-  else:
-    addSon(result, ast.emptyNode)
-  indAndComment(p, result)
-
-proc newCommentStmt(p: var TParser): PNode =
-  #| commentStmt = COMMENT
-  result = newNodeP(nkCommentStmt, p)
-  result.comment = p.tok.literal
-  getTok(p)
-
-type
-  TDefParser = proc (p: var TParser): PNode {.nimcall.}
-
-proc parseSection(p: var TParser, kind: TNodeKind,
-                  defparser: TDefParser): PNode =
-  #| section(p) = COMMENT? p / (IND{>} (p / COMMENT)^+IND{=} DED)
-  result = newNodeP(kind, p)
-  if kind != nkTypeSection: getTok(p)
-  skipComment(p, result)
-  if p.tok.tokType == tkParLe:
-    getTok(p)
-    skipComment(p, result)
-    while true:
-      case p.tok.tokType
-      of tkSymbol, tkAccent, tkParLe:
-        var a = defparser(p)
-        skipComment(p, a)
-        addSon(result, a)
-      of tkComment:
-        var a = newCommentStmt(p)
-        addSon(result, a)
-      of tkParRi: break
-      else:
-        parMessage(p, errIdentifierExpected, p.tok)
-        break
-    eat(p, tkParRi)
-    if result.len == 0: parMessage(p, errIdentifierExpected, p.tok)
-  elif p.tok.tokType in {tkSymbol, tkAccent, tkBracketLe}:
-    # tkBracketLe is allowed for ``var [x, y] = ...`` tuple parsing
-    addSon(result, defparser(p))
-  else:
-    parMessage(p, errIdentifierExpected, p.tok)
-
-proc parseConstant(p: var TParser): PNode =
-  #| constant = identWithPragma (colon typedesc)? '=' optInd expr indAndComment
-  result = newNodeP(nkConstDef, p)
-  addSon(result, identWithPragma(p))
-  if p.tok.tokType == tkColon:
-    getTok(p)
-    optInd(p, result)
-    addSon(result, parseTypeDesc(p))
-  else:
-    addSon(result, ast.emptyNode)
-  eat(p, tkEquals)
-  optInd(p, result)
-  addSon(result, parseExpr(p))
-  indAndComment(p, result)
-
-proc parseEnum(p: var TParser): PNode =
-  #| enum = 'enum' optInd (symbol optInd ('=' optInd expr COMMENT?)? comma?)+
-  result = newNodeP(nkEnumTy, p)
-  getTok(p)
-  addSon(result, ast.emptyNode)
-  optInd(p, result)
-  flexComment(p, result)
-  eat(p, tkCurlyLe)
-  optInd(p, result)
-  while p.tok.tokType notin {tkEof, tkCurlyRi}:
-    var a = parseSymbol(p)
-    if a.kind == nkEmpty: return
-    if p.tok.tokType == tkEquals:
-      getTok(p)
-      optInd(p, a)
-      var b = a
-      a = newNodeP(nkEnumFieldDef, p)
-      addSon(a, b)
-      addSon(a, parseExpr(p))
-      if p.tok.indent < 0:
-        rawSkipComment(p, a)
-    if p.tok.tokType == tkComma:
-      getTok(p)
-      rawSkipComment(p, a)
-    addSon(result, a)
-  eat(p, tkCurlyRi)
-  if result.len <= 1:
-    lexMessageTok(p.lex, errIdentifierExpected, p.tok, prettyTok(p.tok))
-
-proc parseObjectPart(p: var TParser; needsCurly: bool): PNode
-proc parseObjectWhen(p: var TParser): PNode =
-  result = newNodeP(nkRecWhen, p)
-  while true:
-    getTok(p)                 # skip `when`, `elif`
-    var branch = newNodeP(nkElifBranch, p)
-    optInd(p, branch)
-    addSon(branch, parseExpr(p))
-    colcom(p, branch)
-    addSon(branch, parseObjectPart(p, true))
-    flexComment(p, branch)
-    addSon(result, branch)
-    if p.tok.tokType != tkElif: break
-  if p.tok.tokType == tkElse:
-    var branch = newNodeP(nkElse, p)
-    eat(p, tkElse)
-    colcom(p, branch)
-    addSon(branch, parseObjectPart(p, true))
-    flexComment(p, branch)
-    addSon(result, branch)
-
-proc parseObjectCase(p: var TParser): PNode =
-  result = newNodeP(nkRecCase, p)
-  getTokNoInd(p)
-  var a = newNodeP(nkIdentDefs, p)
-  addSon(a, identWithPragma(p))
-  eat(p, tkColon)
-  addSon(a, parseTypeDesc(p))
-  addSon(a, ast.emptyNode)
-  addSon(result, a)
-  eat(p, tkCurlyLe)
-  flexComment(p, result)
-  while true:
-    var b: PNode
-    case p.tok.tokType
-    of tkOf:
-      b = newNodeP(nkOfBranch, p)
-      exprList(p, tkColon, b)
-    of tkElse:
-      b = newNodeP(nkElse, p)
-      getTok(p)
-    else: break
-    colcom(p, b)
-    var fields = parseObjectPart(p, true)
-    if fields.kind == nkEmpty:
-      parMessage(p, errIdentifierExpected, p.tok)
-      fields = newNodeP(nkNilLit, p) # don't break further semantic checking
-    addSon(b, fields)
-    addSon(result, b)
-    if b.kind == nkElse: break
-  eat(p, tkCurlyRi)
-
-proc parseObjectPart(p: var TParser; needsCurly: bool): PNode =
-  if p.tok.tokType == tkCurlyLe:
-    result = newNodeP(nkRecList, p)
-    getTok(p)
-    rawSkipComment(p, result)
-    while true:
-      case p.tok.tokType
-      of tkCase, tkWhen, tkSymbol, tkAccent, tkNil, tkDiscard:
-        addSon(result, parseObjectPart(p, false))
-      of tkCurlyRi: break
-      else:
-        parMessage(p, errIdentifierExpected, p.tok)
-        break
-    eat(p, tkCurlyRi)
-  else:
-    if needsCurly:
-      parMessage(p, errTokenExpected, "{")
-    case p.tok.tokType
-    of tkWhen:
-      result = parseObjectWhen(p)
-    of tkCase:
-      result = parseObjectCase(p)
-    of tkSymbol, tkAccent:
-      result = parseIdentColonEquals(p, {withPragma})
-      if p.tok.indent < 0: rawSkipComment(p, result)
-    of tkNil, tkDiscard:
-      result = newNodeP(nkNilLit, p)
-      getTok(p)
-    else:
-      result = ast.emptyNode
-
-proc parseObject(p: var TParser): PNode =
-  result = newNodeP(nkObjectTy, p)
-  getTok(p)
-  if (p.tok.tokType == tkCurlyDotLe or isAt(p.tok)) and p.validInd:
-    addSon(result, parsePragma(p))
-  else:
-    addSon(result, ast.emptyNode)
-  if p.tok.tokType == tkOf and p.tok.indent < 0:
-    var a = newNodeP(nkOfInherit, p)
-    getTok(p)
-    addSon(a, parseTypeDesc(p))
-    addSon(result, a)
-  else:
-    addSon(result, ast.emptyNode)
-  skipComment(p, result)
-  # an initial IND{>} HAS to follow:
-  addSon(result, parseObjectPart(p, true))
-
-proc parseTypeClassParam(p: var TParser): PNode =
-  if p.tok.tokType in {tkOut, tkVar}:
-    result = newNodeP(nkVarTy, p)
-    getTok(p)
-    result.addSon(p.parseSymbol)
-  else:
-    result = p.parseSymbol
-
-proc parseTypeClass(p: var TParser): PNode =
-  #| typeClassParam = ('var' | 'out')? symbol
-  #| typeClass = typeClassParam ^* ',' (pragma)? ('of' typeDesc ^* ',')?
-  #|               &IND{>} stmt
-  result = newNodeP(nkTypeClassTy, p)
-  getTok(p)
-  var args = newNodeP(nkArgList, p)
-  addSon(result, args)
-  addSon(args, p.parseTypeClassParam)
-  while p.tok.tokType == tkComma:
-    getTok(p)
-    addSon(args, p.parseTypeClassParam)
-  if (p.tok.tokType == tkCurlyDotLe or isAt(p.tok)) and p.validInd:
-    addSon(result, parsePragma(p))
-  else:
-    addSon(result, ast.emptyNode)
-  if p.tok.tokType == tkOf and p.tok.indent < 0:
-    var a = newNodeP(nkOfInherit, p)
-    getTok(p)
-    while true:
-      addSon(a, parseTypeDesc(p))
-      if p.tok.tokType != tkComma: break
-      getTok(p)
-    addSon(result, a)
-  else:
-    addSon(result, ast.emptyNode)
-  if p.tok.tokType == tkComment:
-    skipComment(p, result)
-  addSon(result, parseCurlyStmt(p))
-
-proc parseTypeDef(p: var TParser): PNode =
-  #|
-  #| typeDef = identWithPragmaDot genericParamList? '=' optInd typeDefAux
-  #|             indAndComment?
-  result = newNodeP(nkTypeDef, p)
-  addSon(result, identWithPragma(p, allowDot=true))
-  if p.tok.tokType == tkBracketLe and p.validInd:
-    addSon(result, parseGenericParamList(p))
-  else:
-    addSon(result, ast.emptyNode)
-  if p.tok.tokType == tkEquals:
-    getTok(p)
-    optInd(p, result)
-    addSon(result, parseTypeDefAux(p))
-  else:
-    addSon(result, ast.emptyNode)
-  indAndComment(p, result)    # special extension!
-
-proc parseVarTuple(p: var TParser): PNode =
-  #| varTuple = '(' optInd identWithPragma ^+ comma optPar ')' '=' optInd expr
-  result = newNodeP(nkVarTuple, p)
-  getTok(p)                   # skip '('
-  optInd(p, result)
-  while p.tok.tokType in {tkSymbol, tkAccent}:
-    var a = identWithPragma(p)
-    addSon(result, a)
-    if p.tok.tokType != tkComma: break
-    getTok(p)
-    skipComment(p, a)
-  addSon(result, ast.emptyNode)         # no type desc
-  optPar(p)
-  eat(p, tkBracketRi)
-  eat(p, tkEquals)
-  optInd(p, result)
-  addSon(result, parseExpr(p))
-
-proc parseVariable(p: var TParser): PNode =
-  #| variable = (varTuple / identColonEquals) indAndComment
-  if p.tok.tokType == tkBracketLe: result = parseVarTuple(p)
-  else: result = parseIdentColonEquals(p, {withPragma})
-  indAndComment(p, result)
-
-proc parseBind(p: var TParser, k: TNodeKind): PNode =
-  #| bindStmt = 'bind' optInd qualifiedIdent ^+ comma
-  #| mixinStmt = 'mixin' optInd qualifiedIdent ^+ comma
-  result = newNodeP(k, p)
-  getTok(p)
-  optInd(p, result)
-  while true:
-    var a = qualifiedIdent(p)
-    addSon(result, a)
-    if p.tok.tokType != tkComma: break
-    getTok(p)
-    optInd(p, a)
-
-proc parseStmtPragma(p: var TParser): PNode =
-  result = parsePragma(p)
-  if p.tok.tokType == tkCurlyLe:
-    let a = result
-    result = newNodeI(nkPragmaBlock, a.info)
-    getTok(p)
-    skipComment(p, result)
-    result.add a
-    result.add parseStmt(p)
-    eat(p, tkCurlyRi)
-
-proc simpleStmt(p: var TParser): PNode =
-  case p.tok.tokType
-  of tkReturn: result = parseReturnOrRaise(p, nkReturnStmt)
-  of tkRaise: result = parseReturnOrRaise(p, nkRaiseStmt)
-  of tkYield: result = parseReturnOrRaise(p, nkYieldStmt)
-  of tkDiscard: result = parseReturnOrRaise(p, nkDiscardStmt)
-  of tkBreak: result = parseReturnOrRaise(p, nkBreakStmt)
-  of tkContinue: result = parseReturnOrRaise(p, nkContinueStmt)
-  of tkCurlyDotLe: result = parseStmtPragma(p)
-  of tkImport: result = parseImport(p, nkImportStmt)
-  of tkExport: result = parseImport(p, nkExportStmt)
-  of tkFrom: result = parseFromStmt(p)
-  of tkInclude: result = parseIncludeStmt(p)
-  of tkComment: result = newCommentStmt(p)
-  else:
-    if isExprStart(p): result = parseExprStmt(p)
-    else: result = ast.emptyNode
-  if result.kind notin {nkEmpty, nkCommentStmt}: skipComment(p, result)
-
-proc complexOrSimpleStmt(p: var TParser): PNode =
-  case p.tok.tokType
-  of tkIf: result = parseIfOrWhen(p, nkIfStmt)
-  of tkWhile: result = parseWhile(p)
-  of tkCase: result = parseCase(p)
-  of tkTry: result = parseTry(p)
-  of tkFor: result = parseFor(p)
-  of tkBlock: result = parseBlock(p)
-  of tkStatic: result = parseStaticOrDefer(p, nkStaticStmt)
-  of tkDefer: result = parseStaticOrDefer(p, nkDefer)
-  of tkAsm: result = parseAsm(p)
-  of tkProc: result = parseRoutine(p, nkProcDef)
-  of tkMethod: result = parseRoutine(p, nkMethodDef)
-  of tkIterator: result = parseRoutine(p, nkIteratorDef)
-  of tkMacro: result = parseRoutine(p, nkMacroDef)
-  of tkTemplate: result = parseRoutine(p, nkTemplateDef)
-  of tkConverter: result = parseRoutine(p, nkConverterDef)
-  of tkType:
-    getTok(p)
-    if p.tok.tokType == tkBracketLe:
-      getTok(p)
-      result = newNodeP(nkTypeOfExpr, p)
-      result.addSon(primary(p, pmTypeDesc))
-      eat(p, tkBracketRi)
-      result = parseOperators(p, result, -1, pmNormal)
-    else:
-      result = parseSection(p, nkTypeSection, parseTypeDef)
-  of tkConst: result = parseSection(p, nkConstSection, parseConstant)
-  of tkLet: result = parseSection(p, nkLetSection, parseVariable)
-  of tkWhen: result = parseIfOrWhen(p, nkWhenStmt)
-  of tkVar: result = parseSection(p, nkVarSection, parseVariable)
-  of tkBind: result = parseBind(p, nkBindStmt)
-  of tkMixin: result = parseBind(p, nkMixinStmt)
-  of tkUsing: result = parseSection(p, nkUsingStmt, parseVariable)
-  else: result = simpleStmt(p)
-
-proc parseStmt(p: var TParser): PNode =
-  result = complexOrSimpleStmt(p)
-
-proc parseAll*(p: var TParser): PNode =
-  ## Parses the rest of the input stream held by the parser into a PNode.
-  result = newNodeP(nkStmtList, p)
-  while p.tok.tokType != tkEof:
-    var a = complexOrSimpleStmt(p)
-    if a.kind != nkEmpty:
-      addSon(result, a)
-    else:
-      parMessage(p, errExprExpected, p.tok)
-      # bugfix: consume a token here to prevent an endless loop:
-      getTok(p)
-
-proc parseTopLevelStmt*(p: var TParser): PNode =
-  ## Implements an iterator which, when called repeatedly, returns the next
-  ## top-level statement or emptyNode if end of stream.
-  result = ast.emptyNode
-  while true:
-    case p.tok.tokType
-    of tkSemiColon: getTok(p)
-    of tkEof: break
-    else:
-      result = complexOrSimpleStmt(p)
-      if result.kind == nkEmpty: parMessage(p, errExprExpected, p.tok)
-      break
diff --git a/compiler/plugins/locals/locals.nim b/compiler/plugins/locals/locals.nim
index 9cbb61186..ff7f3be58 100644
--- a/compiler/plugins/locals/locals.nim
+++ b/compiler/plugins/locals/locals.nim
@@ -9,7 +9,7 @@
 
 ## The builtin 'system.locals' implemented as a plugin.
 
-import "../../"  / [pluginsupport, ast, astalgo,
+import "../../" / [pluginsupport, ast, astalgo,
   magicsys, lookups, semdata, lowerings]
 
 proc semLocals(c: PContext, n: PNode): PNode =
diff --git a/compiler/pragmas.nim b/compiler/pragmas.nim
index 5aa903771..0b8bcd374 100644
--- a/compiler/pragmas.nim
+++ b/compiler/pragmas.nim
@@ -777,7 +777,7 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int,
         incl(sym.flags, sfRegister)
       of wThreadVar:
         noVal(it)
-        incl(sym.flags, sfThread)
+        incl(sym.flags, {sfThread, sfGlobal})
       of wDeadCodeElimUnused: discard  # deprecated, dead code elim always on
       of wNoForward: pragmaNoForward(c, it)
       of wReorder: pragmaNoForward(c, it, sfReorder)
diff --git a/compiler/renderer.nim b/compiler/renderer.nim
index 95a622d4e..996168412 100644
--- a/compiler/renderer.nim
+++ b/compiler/renderer.nim
@@ -342,7 +342,7 @@ proc atom(g: TSrcGen; n: PNode): string =
   of nkIdent: result = n.ident.s
   of nkSym: result = n.sym.name.s
   of nkStrLit: result = ""; result.addQuoted(n.strVal)
-  of nkRStrLit: result = "r\"" & replace(n.strVal, "\"", "\"\"")  & '\"'
+  of nkRStrLit: result = "r\"" & replace(n.strVal, "\"", "\"\"") & '\"'
   of nkTripleStrLit: result = "\"\"\"" & n.strVal & "\"\"\""
   of nkCharLit:
     result = "\'"
diff --git a/compiler/reorder.nim b/compiler/reorder.nim
index 56d8d5886..2542a08ea 100644
--- a/compiler/reorder.nim
+++ b/compiler/reorder.nim
@@ -137,7 +137,7 @@ proc hasIncludes(n:PNode): bool =
 
 proc includeModule*(graph: ModuleGraph; s: PSym, fileIdx: FileIndex;
                     cache: IdentCache): PNode {.procvar.} =
-  result = syntaxes.parseFile(fileIdx, cache)
+  result = syntaxes.parseFile(fileIdx, cache, graph.config)
   graph.addDep(s, fileIdx)
   graph.addIncludeDep(FileIndex s.position, fileIdx)
 
@@ -273,9 +273,9 @@ proc hasCommand(n: PNode): bool =
   of nkStmtList, nkStmtListExpr, nkWhenStmt, nkElifBranch, nkElse,
       nkStaticStmt, nkLetSection, nkConstSection, nkVarSection,
       nkIdentDefs:
-        for a in n:
-          if a.hasCommand:
-            return true
+    for a in n:
+      if a.hasCommand:
+        return true
   else:
     return false
 
diff --git a/compiler/scriptconfig.nim b/compiler/scriptconfig.nim
index c533f4cb4..6ef42f15e 100644
--- a/compiler/scriptconfig.nim
+++ b/compiler/scriptconfig.nim
@@ -28,7 +28,7 @@ proc listDirs(a: VmArgs, filter: set[PathComponent]) =
 proc setupVM*(module: PSym; cache: IdentCache; scriptName: string;
               config: ConfigRef): PEvalContext =
   # For Nimble we need to export 'setupVM'.
-  result = newCtx(module, cache)
+  result = newCtx(module, cache, config)
   result.mode = emRepl
   registerAdditionalOps(result)
 
diff --git a/compiler/sem.nim b/compiler/sem.nim
index 52282d0e4..d8e5b7f20 100644
--- a/compiler/sem.nim
+++ b/compiler/sem.nim
@@ -313,7 +313,7 @@ proc tryConstExpr(c: PContext, n: PNode): PNode =
   msgs.gErrorMax = high(int)
 
   try:
-    result = evalConstExpr(c.module, c.cache, e)
+    result = evalConstExpr(c.module, c.cache, c.graph.config, e)
     if result == nil or result.kind == nkEmpty:
       result = nil
     else:
@@ -334,7 +334,7 @@ proc semConstExpr(c: PContext, n: PNode): PNode =
   result = getConstExpr(c.module, e)
   if result == nil:
     #if e.kind == nkEmpty: globalError(n.info, errConstExprExpected)
-    result = evalConstExpr(c.module, c.cache, e)
+    result = evalConstExpr(c.module, c.cache, c.graph.config, e)
     if result == nil or result.kind == nkEmpty:
       if e.info != n.info:
         pushInfoContext(n.info)
@@ -439,7 +439,7 @@ proc semMacroExpr(c: PContext, n, nOrig: PNode, sym: PSym,
 
   #if c.evalContext == nil:
   #  c.evalContext = c.createEvalContext(emStatic)
-  result = evalMacroCall(c.module, c.cache, n, nOrig, sym)
+  result = evalMacroCall(c.module, c.cache, c.graph.config, n, nOrig, sym)
   if efNoSemCheck notin flags:
     result = semAfterMacroCall(c, n, result, sym, flags)
   result = wrapInComesFrom(nOrig.info, sym, result)
diff --git a/compiler/semdata.nim b/compiler/semdata.nim
index fc0488814..62be471f7 100644
--- a/compiler/semdata.nim
+++ b/compiler/semdata.nim
@@ -89,6 +89,7 @@ type
     ambiguousSymbols*: IntSet  # ids of all ambiguous symbols (cannot
                                # store this info in the syms themselves!)
     inGenericContext*: int     # > 0 if we are in a generic type
+    inStaticContext*: int      # > 0 if we are inside a static: block
     inUnrolledContext*: int    # > 0 if we are unrolling a loop
     compilesContextId*: int    # > 0 if we are in a ``compiles`` magic
     compilesContextIdGenerator*: int
diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim
index feca087fc..1ef284a77 100644
--- a/compiler/semexprs.nim
+++ b/compiler/semexprs.nim
@@ -605,12 +605,12 @@ proc evalAtCompileTime(c: PContext, n: PNode): PNode =
       call.add(a)
     #echo "NOW evaluating at compile time: ", call.renderTree
     if sfCompileTime in callee.flags:
-      result = evalStaticExpr(c.module, c.cache, call, c.p.owner)
+      result = evalStaticExpr(c.module, c.cache, c.graph.config, call, c.p.owner)
       if result.isNil:
         localError(n.info, errCannotInterpretNodeX, renderTree(call))
       else: result = fixupTypeAfterEval(c, result, n)
     else:
-      result = evalConstExpr(c.module, c.cache, call)
+      result = evalConstExpr(c.module, c.cache, c.graph.config, call)
       if result.isNil: result = n
       else: result = fixupTypeAfterEval(c, result, n)
     #if result != n:
@@ -619,7 +619,7 @@ proc evalAtCompileTime(c: PContext, n: PNode): PNode =
 proc semStaticExpr(c: PContext, n: PNode): PNode =
   let a = semExpr(c, n.sons[0])
   if a.findUnresolvedStatic != nil: return a
-  result = evalStaticExpr(c.module, c.cache, a, c.p.owner)
+  result = evalStaticExpr(c.module, c.cache, c.graph.config, a, c.p.owner)
   if result.isNil:
     localError(n.info, errCannotInterpretNodeX, renderTree(n))
     result = emptyNode
@@ -960,18 +960,20 @@ proc semSym(c: PContext, n: PNode, sym: PSym, flags: TExprFlags): PNode =
     else:
       result = newSymNode(s, n.info)
   of skMacro:
-    if efNoEvaluateGeneric in flags and s.ast[genericParamsPos].len > 0:
+    if efNoEvaluateGeneric in flags and s.ast[genericParamsPos].len > 0 or
+       (n.kind notin nkCallKinds and s.requiredParams > 0):
       markUsed(n.info, s, c.graph.usageSym)
       styleCheckUse(n.info, s)
-      result = newSymNode(s, n.info)
+      result = symChoice(c, n, s, scClosed)
     else:
       result = semMacroExpr(c, n, n, s, flags)
   of skTemplate:
     if efNoEvaluateGeneric in flags and s.ast[genericParamsPos].len > 0 or
+       (n.kind notin nkCallKinds and s.requiredParams > 0) or
        sfCustomPragma in sym.flags:
       markUsed(n.info, s, c.graph.usageSym)
       styleCheckUse(n.info, s)
-      result = newSymNode(s, n.info)
+      result = symChoice(c, n, s, scClosed)
     else:
       result = semTemplateExpr(c, n, s, flags)
   of skParam:
@@ -1778,6 +1780,7 @@ proc tryExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
   let oldInGenericContext = c.inGenericContext
   let oldInUnrolledContext = c.inUnrolledContext
   let oldInGenericInst = c.inGenericInst
+  let oldInStaticContext = c.inStaticContext
   let oldProcCon = c.p
   c.generics = @[]
   var err: string
@@ -1792,6 +1795,7 @@ proc tryExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
   c.inGenericContext = oldInGenericContext
   c.inUnrolledContext = oldInUnrolledContext
   c.inGenericInst = oldInGenericInst
+  c.inStaticContext = oldInStaticContext
   c.p = oldProcCon
   msgs.setInfoContextLen(oldContextLen)
   setLen(c.graph.owners, oldOwnerLen)
@@ -2156,9 +2160,25 @@ proc semBlock(c: PContext, n: PNode): PNode =
   closeScope(c)
   dec(c.p.nestedBlockCounter)
 
+proc semExportExcept(c: PContext, n: PNode): PNode =
+  let moduleName = semExpr(c, n[0])
+  if moduleName.kind != nkSym or moduleName.sym.kind != skModule:
+    localError(n.info, "The export/except syntax expects a module name")
+    return
+  let exceptSet = readExceptSet(n)
+  let exported = moduleName.sym
+  strTableAdd(c.module.tab, exported)
+  var i: TTabIter
+  var s = initTabIter(i, exported.tab)
+  while s != nil:
+    if s.kind in ExportableSymKinds+{skModule} and
+       s.name.id notin exceptSet:
+      strTableAdd(c.module.tab, s)
+    s = nextIter(i, exported.tab)
+  result = n
+
 proc semExport(c: PContext, n: PNode): PNode =
   var x = newNodeI(n.kind, n.info)
-  #let L = if n.kind == nkExportExceptStmt: L = 1 else: n.len
   for i in 0..<n.len:
     let a = n.sons[i]
     var o: TOverloadIter
@@ -2444,9 +2464,12 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
   of nkIncludeStmt:
     #if not isTopLevel(c): localError(n.info, errXOnlyAtModuleScope, "include")
     result = evalInclude(c, n)
-  of nkExportStmt, nkExportExceptStmt:
+  of nkExportStmt:
     if not isTopLevel(c): localError(n.info, errXOnlyAtModuleScope, "export")
     result = semExport(c, n)
+  of nkExportExceptStmt:
+    if not isTopLevel(c): localError(n.info, errXOnlyAtModuleScope, "export")
+    result = semExportExcept(c, n)
   of nkPragmaBlock:
     result = semPragmaBlock(c, n)
   of nkStaticStmt:
diff --git a/compiler/semmagic.nim b/compiler/semmagic.nim
index 3f0df0065..e6e29b4d3 100644
--- a/compiler/semmagic.nim
+++ b/compiler/semmagic.nim
@@ -199,6 +199,10 @@ proc semBindSym(c: PContext, n: PNode): PNode =
   if s != nil:
     # we need to mark all symbols:
     var sc = symChoice(c, id, s, TSymChoiceRule(isMixin.intVal))
+    if not (c.inStaticContext > 0 or getCurrOwner(c).isCompileTimeProc):
+      # inside regular code, bindSym resolves to the sym-choice
+      # nodes (see tinspectsymbol)
+      return sc
     result.add(sc)
   else:
     errorUndeclaredIdentifier(c, n.sons[1].info, sl.strVal)
diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim
index 8b466f1da..f3cf4196f 100644
--- a/compiler/semstmts.nim
+++ b/compiler/semstmts.nim
@@ -545,7 +545,8 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode =
         b.sons[j] = newSymNode(v)
       checkNilable(v)
       if sfCompileTime in v.flags: hasCompileTime = true
-  if hasCompileTime: vm.setupCompileTimeVar(c.module, c.cache, result)
+  if hasCompileTime:
+    vm.setupCompileTimeVar(c.module, c.cache, c.graph.config, result)
 
 proc semConst(c: PContext, n: PNode): PNode =
   result = copyNode(n)
@@ -846,7 +847,7 @@ proc checkCovariantParamsUsages(genericType: PType) =
         if subType != nil:
           subresult traverseSubTypes(subType)
       if result:
-        error("non-invariant type param used in a proc type: " &  $t)
+        error("non-invariant type param used in a proc type: " & $t)
 
     of tySequence:
       return traverseSubTypes(t[0])
@@ -1753,9 +1754,11 @@ proc semPragmaBlock(c: PContext, n: PNode): PNode =
 proc semStaticStmt(c: PContext, n: PNode): PNode =
   #echo "semStaticStmt"
   #writeStackTrace()
+  inc c.inStaticContext
   let a = semStmt(c, n.sons[0])
+  dec c.inStaticContext
   n.sons[0] = a
-  evalStaticStmt(c.module, c.cache, a, c.p.owner)
+  evalStaticStmt(c.module, c.cache, c.graph.config, a, c.p.owner)
   result = newNodeI(nkDiscardStmt, n.info, 1)
   result.sons[0] = emptyNode
 
diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim
index 4263ef581..55d83d990 100644
--- a/compiler/sigmatch.nim
+++ b/compiler/sigmatch.nim
@@ -1962,7 +1962,8 @@ proc paramTypesMatchAux(m: var TCandidate, f, a: PType,
     inc(m.genericMatches)
     if arg.typ == nil:
       result = arg
-    elif skipTypes(arg.typ, abstractVar-{tyTypeDesc}).kind == tyTuple:
+    elif skipTypes(arg.typ, abstractVar-{tyTypeDesc}).kind == tyTuple or
+         m.inheritancePenalty > 0:
       result = implicitConv(nkHiddenSubConv, f, arg, m, c)
     elif arg.typ.isEmptyContainer:
       result = arg.copyTree
@@ -2032,8 +2033,9 @@ proc paramTypesMatch*(m: var TCandidate, f, a: PType,
     y.calleeSym = m.calleeSym
     z.calleeSym = m.calleeSym
     var best = -1
-    for i in countup(0, sonsLen(arg) - 1):
-      if arg.sons[i].sym.kind in {skProc, skFunc, skMethod, skConverter, skIterator}:
+    for i in 0 ..< arg.len:
+      if arg.sons[i].sym.kind in {skProc, skFunc, skMethod, skConverter,
+                                  skIterator, skMacro, skTemplate}:
         copyCandidate(z, m)
         z.callee = arg.sons[i].typ
         if tfUnresolved in z.callee.flags: continue
@@ -2062,6 +2064,7 @@ proc paramTypesMatch*(m: var TCandidate, f, a: PType,
               x = z
             elif cmp == 0:
               y = z           # z is as good as x
+
     if x.state == csEmpty:
       result = nil
     elif y.state == csMatch and cmpCandidates(x, y) == 0:
@@ -2070,7 +2073,7 @@ proc paramTypesMatch*(m: var TCandidate, f, a: PType,
       # ambiguous: more than one symbol fits!
       # See tsymchoice_for_expr as an example. 'f.kind == tyExpr' should match
       # anyway:
-      if f.kind == tyExpr: result = arg
+      if f.kind in {tyExpr, tyStmt}: result = arg
       else: result = nil
     else:
       # only one valid interpretation found:
@@ -2171,7 +2174,8 @@ proc matchesAux(c: PContext, n, nOrig: PNode,
   var formal: PSym = if formalLen > 1: m.callee.n.sons[1].sym else: nil
 
   while a < n.len:
-    if a >= formalLen-1 and formal != nil and formal.typ.isVarargsUntyped:
+    if a >= formalLen-1 and f < formalLen and m.callee.n[f].typ.isVarargsUntyped:
+      formal = m.callee.n.sons[f].sym
       incl(marker, formal.position)
       if container.isNil:
         container = newNodeIT(nkArgList, n.sons[a].info, arrayConstr(c, n.info))
diff --git a/compiler/syntaxes.nim b/compiler/syntaxes.nim
index 5413565e6..974df50fb 100644
--- a/compiler/syntaxes.nim
+++ b/compiler/syntaxes.nim
@@ -11,17 +11,17 @@
 
 import
   strutils, llstream, ast, astalgo, idents, lexer, options, msgs, parser,
-  pbraces, filters, filter_tmpl, renderer
+  filters, filter_tmpl, renderer
 
 type
   TFilterKind* = enum
     filtNone, filtTemplate, filtReplace, filtStrip
   TParserKind* = enum
-    skinStandard, skinStrongSpaces, skinBraces, skinEndX
+    skinStandard, skinStrongSpaces, skinEndX
 
 const
   parserNames*: array[TParserKind, string] = ["standard", "strongspaces",
-                                              "braces", "endx"]
+                                              "endx"]
   filterNames*: array[TFilterKind, string] = ["none", "stdtmpl", "replace",
                                               "strip"]
 
@@ -34,8 +34,6 @@ proc parseAll*(p: var TParsers): PNode =
   case p.skin
   of skinStandard, skinStrongSpaces:
     result = parser.parseAll(p.parser)
-  of skinBraces:
-    result = pbraces.parseAll(p.parser)
   of skinEndX:
     internalError("parser to implement")
     result = ast.emptyNode
@@ -44,8 +42,6 @@ proc parseTopLevelStmt*(p: var TParsers): PNode =
   case p.skin
   of skinStandard, skinStrongSpaces:
     result = parser.parseTopLevelStmt(p.parser)
-  of skinBraces:
-    result = pbraces.parseTopLevelStmt(p.parser)
   of skinEndX:
     internalError("parser to implement")
     result = ast.emptyNode
@@ -62,7 +58,8 @@ proc containsShebang(s: string, i: int): bool =
     while j < s.len and s[j] in Whitespace: inc(j)
     result = s[j] == '/'
 
-proc parsePipe(filename: string, inputStream: PLLStream; cache: IdentCache): PNode =
+proc parsePipe(filename: string, inputStream: PLLStream; cache: IdentCache;
+               config: ConfigRef): PNode =
   result = ast.emptyNode
   var s = llStreamOpen(filename, fmRead)
   if s != nil:
@@ -78,7 +75,7 @@ proc parsePipe(filename: string, inputStream: PLLStream; cache: IdentCache): PNo
       inc(i, 2)
       while i < line.len and line[i] in Whitespace: inc(i)
       var q: TParser
-      parser.openParser(q, filename, llStreamOpen(substr(line, i)), cache)
+      parser.openParser(q, filename, llStreamOpen(substr(line, i)), cache, config)
       result = parser.parseAll(q)
       parser.closeParser(q)
     llStreamClose(s)
@@ -139,23 +136,23 @@ proc evalPipe(p: var TParsers, n: PNode, filename: string,
     result = applyFilter(p, n, filename, result)
 
 proc openParsers*(p: var TParsers, fileIdx: FileIndex, inputstream: PLLStream;
-                  cache: IdentCache) =
+                  cache: IdentCache; config: ConfigRef) =
   var s: PLLStream
   p.skin = skinStandard
   let filename = fileIdx.toFullPathConsiderDirty
-  var pipe = parsePipe(filename, inputstream, cache)
+  var pipe = parsePipe(filename, inputstream, cache, config)
   if pipe != nil: s = evalPipe(p, pipe, filename, inputstream)
   else: s = inputstream
   case p.skin
-  of skinStandard, skinBraces, skinEndX:
-    parser.openParser(p.parser, fileIdx, s, cache, false)
+  of skinStandard, skinEndX:
+    parser.openParser(p.parser, fileIdx, s, cache, config, false)
   of skinStrongSpaces:
-    parser.openParser(p.parser, fileIdx, s, cache, true)
+    parser.openParser(p.parser, fileIdx, s, cache, config, true)
 
 proc closeParsers*(p: var TParsers) =
   parser.closeParser(p.parser)
 
-proc parseFile*(fileIdx: FileIndex; cache: IdentCache): PNode {.procvar.} =
+proc parseFile*(fileIdx: FileIndex; cache: IdentCache; config: ConfigRef): PNode {.procvar.} =
   var
     p: TParsers
     f: File
@@ -163,6 +160,6 @@ proc parseFile*(fileIdx: FileIndex; cache: IdentCache): PNode {.procvar.} =
   if not open(f, filename):
     rawMessage(errCannotOpenFile, filename)
     return
-  openParsers(p, fileIdx, llStreamOpen(f), cache)
+  openParsers(p, fileIdx, llStreamOpen(f), cache, config)
   result = parseAll(p)
   closeParsers(p)
diff --git a/compiler/types.nim b/compiler/types.nim
index edf4e5b46..b9b6ab33c 100644
--- a/compiler/types.nim
+++ b/compiler/types.nim
@@ -612,7 +612,7 @@ proc firstOrd*(t: PType): BiggestInt =
     else:
       assert(t.n.sons[0].kind == nkSym)
       result = t.n.sons[0].sym.position
-  of tyGenericInst, tyDistinct, tyTypeDesc, tyAlias, tyStatic:
+  of tyGenericInst, tyDistinct, tyTypeDesc, tyAlias, tyStatic, tyInferred:
     result = firstOrd(lastSon(t))
   of tyOrdinal:
     if t.len > 0: result = firstOrd(lastSon(t))
@@ -651,7 +651,7 @@ proc lastOrd*(t: PType; fixedUnsigned = false): BiggestInt =
   of tyEnum:
     assert(t.n.sons[sonsLen(t.n) - 1].kind == nkSym)
     result = t.n.sons[sonsLen(t.n) - 1].sym.position
-  of tyGenericInst, tyDistinct, tyTypeDesc, tyAlias, tyStatic:
+  of tyGenericInst, tyDistinct, tyTypeDesc, tyAlias, tyStatic, tyInferred:
     result = lastOrd(lastSon(t))
   of tyProxy: result = 0
   of tyOrdinal:
diff --git a/compiler/vm.nim b/compiler/vm.nim
index 32db8f378..27135d2e7 100644
--- a/compiler/vm.nim
+++ b/compiler/vm.nim
@@ -210,8 +210,14 @@ proc putIntoNode(n: var PNode; x: TFullReg) =
   of rkInt: n.intVal = x.intVal
   of rkFloat: n.floatVal = x.floatVal
   of rkNode:
-    if nfIsRef in x.node.flags: n = x.node
-    else: n[] = x.node[]
+    if nfIsRef in x.node.flags:
+      n = x.node
+    else:
+      let destIsRef = nfIsRef in n.flags    
+      n[] = x.node[]
+      # Ref-ness must be kept for the destination
+      if destIsRef:
+        n.flags.incl nfIsRef
   of rkRegisterAddr: putIntoNode(n, x.regAddr[])
   of rkNodeAddr: n[] = x.nodeAddr[][]
 
@@ -1341,8 +1347,8 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
       decodeB(rkNode)
       # c.debug[pc].line.int - countLines(regs[rb].strVal) ?
       var error: string
-      let ast = parseString(regs[rb].node.strVal, c.cache, c.debug[pc].toFullPath,
-                            c.debug[pc].line.int,
+      let ast = parseString(regs[rb].node.strVal, c.cache, c.config,
+                            c.debug[pc].toFullPath, c.debug[pc].line.int,
                             proc (info: TLineInfo; msg: TMsgKind; arg: string) =
                               if error.isNil and msg <= msgs.errMax:
                                 error = formatMsg(info, msg, arg))
@@ -1355,8 +1361,8 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
     of opcParseStmtToAst:
       decodeB(rkNode)
       var error: string
-      let ast = parseString(regs[rb].node.strVal, c.cache, c.debug[pc].toFullPath,
-                            c.debug[pc].line.int,
+      let ast = parseString(regs[rb].node.strVal, c.cache, c.config,
+                            c.debug[pc].toFullPath, c.debug[pc].line.int,
                             proc (info: TLineInfo; msg: TMsgKind; arg: string) =
                               if error.isNil and msg <= msgs.errMax:
                                 error = formatMsg(info, msg, arg))
@@ -1643,9 +1649,9 @@ include vmops
 var
   globalCtx*: PCtx
 
-proc setupGlobalCtx(module: PSym; cache: IdentCache) =
+proc setupGlobalCtx(module: PSym; cache: IdentCache; config: ConfigRef) =
   if globalCtx.isNil:
-    globalCtx = newCtx(module, cache)
+    globalCtx = newCtx(module, cache, config)
     registerAdditionalOps(globalCtx)
   else:
     refresh(globalCtx, module)
@@ -1656,7 +1662,7 @@ proc myOpen(graph: ModuleGraph; module: PSym; cache: IdentCache): PPassContext =
   #pushStackFrame(c, newStackFrame())
 
   # XXX produce a new 'globals' environment here:
-  setupGlobalCtx(module, cache)
+  setupGlobalCtx(module, cache, graph.config)
   result = globalCtx
   when hasFFI:
     globalCtx.features = {allowFFI, allowCast}
@@ -1677,10 +1683,11 @@ proc myClose(graph: ModuleGraph; c: PPassContext, n: PNode): PNode =
 
 const evalPass* = makePass(myOpen, nil, myProcess, myClose)
 
-proc evalConstExprAux(module: PSym; cache: IdentCache; prc: PSym, n: PNode,
+proc evalConstExprAux(module: PSym; cache: IdentCache;
+                      config: ConfigRef; prc: PSym, n: PNode,
                       mode: TEvalMode): PNode =
   let n = transformExpr(module, n)
-  setupGlobalCtx(module, cache)
+  setupGlobalCtx(module, cache, config)
   var c = globalCtx
   let oldMode = c.mode
   defer: c.mode = oldMode
@@ -1695,17 +1702,17 @@ proc evalConstExprAux(module: PSym; cache: IdentCache; prc: PSym, n: PNode,
   result = rawExecute(c, start, tos).regToNode
   if result.info.col < 0: result.info = n.info
 
-proc evalConstExpr*(module: PSym; cache: IdentCache, e: PNode): PNode =
-  result = evalConstExprAux(module, cache, nil, e, emConst)
+proc evalConstExpr*(module: PSym; cache: IdentCache, config: ConfigRef; e: PNode): PNode =
+  result = evalConstExprAux(module, cache, config, nil, e, emConst)
 
-proc evalStaticExpr*(module: PSym; cache: IdentCache, e: PNode, prc: PSym): PNode =
-  result = evalConstExprAux(module, cache, prc, e, emStaticExpr)
+proc evalStaticExpr*(module: PSym; cache: IdentCache, config: ConfigRef; e: PNode, prc: PSym): PNode =
+  result = evalConstExprAux(module, cache, config, prc, e, emStaticExpr)
 
-proc evalStaticStmt*(module: PSym; cache: IdentCache, e: PNode, prc: PSym) =
-  discard evalConstExprAux(module, cache, prc, e, emStaticStmt)
+proc evalStaticStmt*(module: PSym; cache: IdentCache, config: ConfigRef; e: PNode, prc: PSym) =
+  discard evalConstExprAux(module, cache, config, prc, e, emStaticStmt)
 
-proc setupCompileTimeVar*(module: PSym; cache: IdentCache, n: PNode) =
-  discard evalConstExprAux(module, cache, nil, n, emStaticStmt)
+proc setupCompileTimeVar*(module: PSym; cache: IdentCache, config: ConfigRef; n: PNode) =
+  discard evalConstExprAux(module, cache, config, nil, n, emStaticStmt)
 
 proc setupMacroParam(x: PNode, typ: PType): TFullReg =
   case typ.kind
@@ -1733,8 +1740,8 @@ iterator genericParamsInMacroCall*(macroSym: PSym, call: PNode): (PSym, PNode) =
 const evalMacroLimit = 1000
 var evalMacroCounter: int
 
-proc evalMacroCall*(module: PSym; cache: IdentCache, n, nOrig: PNode,
-                    sym: PSym): PNode =
+proc evalMacroCall*(module: PSym; cache: IdentCache; config: ConfigRef;
+                    n, nOrig: PNode, sym: PSym): PNode =
   # XXX globalError() is ugly here, but I don't know a better solution for now
   inc(evalMacroCounter)
   if evalMacroCounter > evalMacroLimit:
@@ -1746,7 +1753,7 @@ proc evalMacroCall*(module: PSym; cache: IdentCache, n, nOrig: PNode,
     globalError(n.info, "in call '$#' got $#, but expected $# argument(s)" % [
         n.renderTree, $(n.safeLen-1), $(sym.typ.len-1)])
 
-  setupGlobalCtx(module, cache)
+  setupGlobalCtx(module, cache, config)
   var c = globalCtx
   c.comesFromHeuristic.line = 0'u16
 
diff --git a/compiler/vmdef.nim b/compiler/vmdef.nim
index 66bc8dfd2..b0a559d2c 100644
--- a/compiler/vmdef.nim
+++ b/compiler/vmdef.nim
@@ -10,7 +10,7 @@
 ## This module contains the type definitions for the new evaluation engine.
 ## An instruction is 1-3 int32s in memory, it is a register based VM.
 
-import ast, passes, msgs, idents, intsets
+import ast, passes, msgs, idents, intsets, options
 
 const
   byteExcess* = 128 # we use excess-K for immediates
@@ -206,17 +206,19 @@ type
     callbacks*: seq[tuple[key: string, value: VmCallback]]
     errorFlag*: string
     cache*: IdentCache
+    config*: ConfigRef
 
   TPosition* = distinct int
 
   PEvalContext* = PCtx
 
-proc newCtx*(module: PSym; cache: IdentCache): PCtx =
+proc newCtx*(module: PSym; cache: IdentCache; config: ConfigRef = nil): PCtx =
+  let conf = if config != nil: config else: newConfigRef()
   PCtx(code: @[], debug: @[],
     globals: newNode(nkStmtListExpr), constants: newNode(nkStmtList), types: @[],
     prc: PProc(blocks: @[]), module: module, loopIterations: MaxLoopIterations,
     comesFromHeuristic: unknownLineInfo(), callbacks: @[], errorFlag: "",
-    cache: cache)
+    cache: cache, config: conf)
 
 proc refresh*(c: PCtx, module: PSym) =
   c.module = module
diff --git a/compiler/vmgen.nim b/compiler/vmgen.nim
index 0544dc311..7f91e63db 100644
--- a/compiler/vmgen.nim
+++ b/compiler/vmgen.nim
@@ -790,7 +790,7 @@ proc genIntCast(c: PCtx; n: PNode; dest: var TDest) =
     elif src.kind in signedIntegers and dst.kind in unsignedIntegers:
       # cast signed to unsigned integer of same size
       # unsignedVal = (offset +% signedVal +% 1) and offset
-      let offset = (1 shl (src_size * 8))  - 1
+      let offset = (1 shl (src_size * 8)) - 1
       c.gABx(n, opcLdConst, tmp2, mkIntLit(offset))
       c.gABx(n, opcLdConst, dest, mkIntLit(offset+1))
       c.gABC(n, opcAddu, tmp3, tmp, dest)
@@ -1554,7 +1554,7 @@ proc getNullValue(typ: PType, info: TLineInfo): PNode =
   of tyCString, tyString:
     result = newNodeIT(nkStrLit, info, t)
     result.strVal = ""
-  of tyVar, tyLent, tyPointer, tyPtr, tySequence, tyExpr,
+  of tyVar, tyLent, tyPointer, tyPtr, tyExpr,
      tyStmt, tyTypeDesc, tyStatic, tyRef, tyNil:
     result = newNodeIT(nkNilLit, info, t)
   of tyProc:
@@ -1585,6 +1585,8 @@ proc getNullValue(typ: PType, info: TLineInfo): PNode =
     result = newNodeIT(nkCurly, info, t)
   of tyOpt:
     result = newNodeIT(nkNilLit, info, t)
+  of tySequence:
+    result = newNodeIT(nkBracket, info, t)
   else:
     globalError(info, "cannot create null element for: " & $t.kind)
 
diff --git a/doc/manual.rst b/doc/manual.rst
index fabcf058a..44e2ee5b5 100644
--- a/doc/manual.rst
+++ b/doc/manual.rst
@@ -6298,6 +6298,9 @@ modules don't need to import a module's dependencies:
   var x: MyObject
   echo $x
 
+When the exported symbol is another module, all of its definitions will
+be forwarded. You can use an ``except`` list to exclude some of the symbols.
+
 Note on paths
 -----------
 In module related statements, if any part of the module name /
@@ -7798,8 +7801,9 @@ Future directions:
 Threadvar pragma
 ----------------
 
-A global variable can be marked with the ``threadvar`` pragma; it is
-a `thread-local`:idx: variable then:
+A variable can be marked with the ``threadvar`` pragma, which makes it a
+`thread-local`:idx: variable; Additionally, this implies all the effects
+of the ``global`` pragma.
 
 .. code-block:: nim
   var checkpoints* {.threadvar.}: seq[string]
diff --git a/koch.nim b/koch.nim
index d51b902ee..7a75ebf71 100644
--- a/koch.nim
+++ b/koch.nim
@@ -252,7 +252,7 @@ proc xz(args: string) =
 
 proc buildTool(toolname, args: string) =
   nimexec("cc $# $#" % [args, toolname])
-  copyFile(dest="bin"/ splitFile(toolname).name.exe, source=toolname.exe)
+  copyFile(dest="bin" / splitFile(toolname).name.exe, source=toolname.exe)
 
 proc buildTools(latest: bool) =
   let nimsugExe = "bin/nimsuggest".exe
diff --git a/lib/core/macros.nim b/lib/core/macros.nim
index 1dc067e1a..fa5cd67df 100644
--- a/lib/core/macros.nim
+++ b/lib/core/macros.nim
@@ -385,7 +385,7 @@ type
 
 {.deprecated: [TBindSymRule: BindSymRule].}
 
-proc bindSym*(ident: string, rule: BindSymRule = brClosed): NimNode {.
+proc bindSym*(ident: static[string], rule: BindSymRule = brClosed): NimNode {.
               magic: "NBindSym", noSideEffect.}
   ## creates a node that binds `ident` to a symbol node. The bound symbol
   ## may be an overloaded symbol.
diff --git a/lib/deprecated/pure/ftpclient.nim b/lib/deprecated/pure/ftpclient.nim
index ed2f14450..7645258b6 100644
--- a/lib/deprecated/pure/ftpclient.nim
+++ b/lib/deprecated/pure/ftpclient.nim
@@ -12,7 +12,7 @@ import sockets, strutils, parseutils, times, os, asyncio
 
 from asyncnet import nil
 from nativesockets import nil
-from asyncdispatch import PFuture
+from asyncdispatch import Future
 ## **Note**: This module is deprecated since version 0.11.3.
 ## You should use the async version of this module
 ## `asyncftpclient <asyncftpclient.html>`_.
diff --git a/lib/packages/docutils/rst.nim b/lib/packages/docutils/rst.nim
index 223fc836a..ff2bdb8ce 100644
--- a/lib/packages/docutils/rst.nim
+++ b/lib/packages/docutils/rst.nim
@@ -853,7 +853,6 @@ type
   DirKind = enum             # must be ordered alphabetically!
     dkNone, dkAuthor, dkAuthors, dkCode, dkCodeBlock, dkContainer, dkContents,
     dkFigure, dkImage, dkInclude, dkIndex, dkRaw, dkTitle
-{.deprecated: [TDirKind: DirKind].}
 
 const
   DirIds: array[0..12, string] = ["", "author", "authors", "code",
@@ -1114,7 +1113,6 @@ proc parseHeadline(p: var RstParser): PRstNode =
 
 type
   IntSeq = seq[int]
-{.deprecated: [TIntSeq: IntSeq].}
 
 proc tokEnd(p: RstParser): int =
   result = p.tok[p.idx].col + len(p.tok[p.idx].symbol) - 1
@@ -1408,8 +1406,6 @@ type
     hasArg, hasOptions, argIsFile, argIsWord
   DirFlags = set[DirFlag]
   SectionParser = proc (p: var RstParser): PRstNode {.nimcall.}
-{.deprecated: [TDirFlag: DirFlag, TDirFlags: DirFlags,
-              TSectionParser: SectionParser].}
 
 proc parseDirective(p: var RstParser, flags: DirFlags): PRstNode =
   ## Parses arguments and options for a directive block.
diff --git a/lib/packages/docutils/rstast.nim b/lib/packages/docutils/rstast.nim
index 7be4470c1..f3596b571 100644
--- a/lib/packages/docutils/rstast.nim
+++ b/lib/packages/docutils/rstast.nim
@@ -70,8 +70,6 @@ type
                               ## the document or the section
     level*: int               ## valid for some node kinds
     sons*: RstNodeSeq        ## the node's sons
-{.deprecated: [TRstNodeKind: RstNodeKind, TRstNodeSeq: RstNodeSeq,
-              TRstNode: RstNode].}
 
 proc len*(n: PRstNode): int =
   result = len(n.sons)
@@ -99,7 +97,6 @@ type
   RenderContext {.pure.} = object
     indent: int
     verbatim: int
-{.deprecated: [TRenderContext: RenderContext].}
 
 proc renderRstToRst(d: var RenderContext, n: PRstNode,
                     result: var string) {.gcsafe.}
diff --git a/lib/pure/algorithm.nim b/lib/pure/algorithm.nim
index 45e031574..22793ab1c 100644
--- a/lib/pure/algorithm.nim
+++ b/lib/pure/algorithm.nim
@@ -13,9 +13,6 @@ type
   SortOrder* = enum   ## sort order
     Descending, Ascending
 
-{.deprecated: [TSortOrder: SortOrder].}
-
-
 proc `*`*(x: int, order: SortOrder): int {.inline.} =
   ## flips `x` if ``order == Descending``;
   ## if ``order == Ascending`` then `x` is returned.
@@ -69,21 +66,25 @@ proc reversed*[T](a: openArray[T]): seq[T] =
 
 proc binarySearch*[T](a: openArray[T], key: T): int =
   ## binary search for `key` in `a`. Returns -1 if not found.
-  var b = len(a)
-  while result < b:
-    var mid = (result + b) div 2
-    if a[mid] < key: result = mid + 1
-    else: b = mid
-  if result >= len(a) or a[result] != key: result = -1
-
-proc smartBinarySearch*[T](a: openArray[T], key: T): int =
-  ## ``a.len`` must be a power of 2 for this to work.
-  var step = a.len div 2
-  while step > 0:
-    if a[result or step] <= key:
-      result = result or step
-    step = step shr 1
-  if a[result] != key: result = -1
+  if ((a.len - 1) and a.len) == 0 and a.len > 0:
+    # when `a.len` is a power of 2, a faster div can be used.
+    var step = a.len div 2
+    while step > 0:
+      if a[result or step] <= key:
+        result = result or step
+      step = step shr 1
+    if a[result] != key: result = -1
+  else:
+    var b = len(a)
+    while result < b:
+      var mid = (result + b) div 2
+      if a[mid] < key: result = mid + 1
+      else: b = mid
+    if result >= len(a) or a[result] != key: result = -1
+
+proc smartBinarySearch*[T](a: openArray[T], key: T): int {.deprecated.} =
+  ## **Deprecated since version 0.18.1**; Use ``binarySearch`` instead.
+  binarySearch(a,key)
 
 const
   onlySafeCode = true
@@ -363,10 +364,11 @@ when isMainModule:
   var srt1 = [1,2,3,4,4,4,4,5]
   var srt2 = ["iello","hello"]
   var srt3 = [1.0,1.0,1.0]
-  var srt4: seq[int] = @[]
+  var srt4: seq[int]
   assert srt1.isSorted(cmp) == true
   assert srt2.isSorted(cmp) == false
   assert srt3.isSorted(cmp) == true
+  assert srt4.isSorted(cmp) == true
   var srtseq = newSeq[int]()
   assert srtseq.isSorted(cmp) == true
   # Tests for reversed
@@ -395,7 +397,7 @@ proc rotateInternal[T](arg: var openarray[T]; first, middle, last: int): int =
 
   swap(arg[mFirst], arg[next])
   mFirst += 1
-  next  += 1
+  next += 1
   if mFirst == mMiddle:
     mMiddle = next
 
@@ -514,4 +516,24 @@ when isMainModule:
 
   block fillEmptySeq:
     var s = newSeq[int]()
-    s.fill(0)
\ No newline at end of file
+    s.fill(0)
+
+  block testBinarySearch:
+    var noData: seq[int]
+    doAssert binarySearch(noData, 7)    == -1
+    let oneData = @[1]
+    doAssert binarySearch(oneData, 1)   == 0
+    doAssert binarySearch(onedata, 7)   == -1
+    let someData = @[1,3,4,7]
+    doAssert binarySearch(someData, 1)  == 0
+    doAssert binarySearch(somedata, 7)  == 3
+    doAssert binarySearch(someData, -1) == -1
+    doAssert binarySearch(someData, 5)  == -1
+    doAssert binarySearch(someData, 13) == -1
+    let moreData = @[1,3,5,7,4711]
+    doAssert binarySearch(moreData, -1) == -1
+    doAssert binarySearch(moreData,  1) == 0
+    doAssert binarySearch(moreData,  5) == 2
+    doAssert binarySearch(moreData,  6) == -1
+    doAssert binarySearch(moreData,  4711) == 4
+    doAssert binarySearch(moreData,  4712) == -1
diff --git a/lib/pure/asyncfutures.nim b/lib/pure/asyncfutures.nim
index 8fedb16fe..863a6843b 100644
--- a/lib/pure/asyncfutures.nim
+++ b/lib/pure/asyncfutures.nim
@@ -27,8 +27,6 @@ type
   FutureError* = object of Exception
     cause*: FutureBase
 
-{.deprecated: [PFutureBase: FutureBase, PFuture: Future].}
-
 when not defined(release):
   var currentID = 0
 
diff --git a/lib/pure/asynchttpserver.nim b/lib/pure/asynchttpserver.nim
index ba1615651..fe5a835d7 100644
--- a/lib/pure/asynchttpserver.nim
+++ b/lib/pure/asynchttpserver.nim
@@ -60,9 +60,6 @@ type
     reusePort: bool
     maxBody: int ## The maximum content-length that will be read for the body.
 
-{.deprecated: [TRequest: Request, PAsyncHttpServer: AsyncHttpServer,
-  THttpCode: HttpCode, THttpVersion: HttpVersion].}
-
 proc newAsyncHttpServer*(reuseAddr = true, reusePort = false,
                          maxBody = 8388608): AsyncHttpServer =
   ## Creates a new ``AsyncHttpServer`` instance.
diff --git a/lib/pure/asyncnet.nim b/lib/pure/asyncnet.nim
index 7c354151b..e7552e3e3 100644
--- a/lib/pure/asyncnet.nim
+++ b/lib/pure/asyncnet.nim
@@ -134,8 +134,6 @@ type
     protocol: Protocol
   AsyncSocket* = ref AsyncSocketDesc
 
-{.deprecated: [PAsyncSocket: AsyncSocket].}
-
 proc newAsyncSocket*(fd: AsyncFD, domain: Domain = AF_INET,
     sockType: SockType = SOCK_STREAM,
     protocol: Protocol = IPPROTO_TCP, buffered = true): AsyncSocket =
diff --git a/lib/pure/cgi.nim b/lib/pure/cgi.nim
index a5a404497..e0cdc2ec0 100644
--- a/lib/pure/cgi.nim
+++ b/lib/pure/cgi.nim
@@ -64,8 +64,6 @@ type
     methodPost,          ## query uses the POST method
     methodGet            ## query uses the GET method
 
-{.deprecated: [TRequestMethod: RequestMethod, ECgi: CgiError].}
-
 proc cgiError*(msg: string) {.noreturn.} =
   ## raises an ECgi exception with message `msg`.
   var e: ref CgiError
diff --git a/lib/pure/collections/sets.nim b/lib/pure/collections/sets.nim
index 32b6387ad..59c90bc2b 100644
--- a/lib/pure/collections/sets.nim
+++ b/lib/pure/collections/sets.nim
@@ -120,6 +120,13 @@ iterator items*[A](s: HashSet[A]): A =
   for h in 0..high(s.data):
     if isFilled(s.data[h].hcode): yield s.data[h].key
 
+proc hash*[A](s: HashSet[A]): Hash =
+  ## hashing of HashSet
+  assert s.isValid, "The set needs to be initialized."
+  for h in 0..high(s.data):
+    result = result xor s.data[h].hcode
+  result = !$result
+
 const
   growthFactor = 2
 
@@ -690,6 +697,13 @@ iterator items*[A](s: OrderedSet[A]): A =
   forAllOrderedPairs:
     yield s.data[h].key
 
+proc hash*[A](s: OrderedSet[A]): Hash =
+  ## hashing of OrderedSet
+  assert s.isValid, "The set needs to be initialized."
+  forAllOrderedPairs:
+    result = result !& s.data[h].hcode
+  result = !$result
+
 iterator pairs*[A](s: OrderedSet[A]): tuple[a: int, b: A] =
   assert s.isValid, "The set needs to be initialized"
   forAllOrderedPairs:
diff --git a/lib/pure/colors.nim b/lib/pure/colors.nim
index 4ec76dee0..25a2fb870 100644
--- a/lib/pure/colors.nim
+++ b/lib/pure/colors.nim
@@ -14,8 +14,6 @@ import strutils
 type
   Color* = distinct int ## a color stored as RGB
 
-{.deprecated: [TColor: Color].}
-
 proc `==` *(a, b: Color): bool {.borrow.}
   ## compares two colors.
 
diff --git a/lib/pure/complex.nim b/lib/pure/complex.nim
index ccde5ee0a..98cab1a5a 100644
--- a/lib/pure/complex.nim
+++ b/lib/pure/complex.nim
@@ -25,8 +25,6 @@ type
   Complex* = tuple[re, im: float]
     ## a complex number, consisting of a real and an imaginary part
 
-{.deprecated: [TComplex: Complex].}
-
 proc toComplex*(x: SomeInteger): Complex =
   ## Convert some integer ``x`` to a complex number.
   result.re = x
diff --git a/lib/pure/db_common.nim b/lib/pure/db_common.nim
index 957389605..f8689024b 100644
--- a/lib/pure/db_common.nim
+++ b/lib/pure/db_common.nim
@@ -83,9 +83,6 @@ type
     foreignKey*: bool  ## is this a foreign key?
   DbColumns* = seq[DbColumn]
 
-{.deprecated: [EDb: DbError, TSqlQuery: SqlQuery, FDb: DbEffect,
-              FReadDb: ReadDbEffect, FWriteDb: WriteDbEffect].}
-
 template sql*(query: string): SqlQuery =
   ## constructs a SqlQuery from the string `query`. This is supposed to be
   ## used as a raw-string-literal modifier:
diff --git a/lib/pure/dynlib.nim b/lib/pure/dynlib.nim
index ec6cbb232..5bd06f6fb 100644
--- a/lib/pure/dynlib.nim
+++ b/lib/pure/dynlib.nim
@@ -17,9 +17,9 @@
 ## Loading a simple C function
 ## ^^^^^^^^^^^^^^^^^^^^^^^^^^^
 ##
-## The following example demonstrates loading a function called 'greet' 
+## The following example demonstrates loading a function called 'greet'
 ## from a library that is determined at runtime based upon a language choice.
-## If the library fails to load or the function 'greet' is not found, 
+## If the library fails to load or the function 'greet' is not found,
 ## it quits with a failure error code.
 ##
 ## .. code-block::nim
@@ -59,8 +59,6 @@ import strutils
 type
   LibHandle* = pointer ## a handle to a dynamically loaded library
 
-{.deprecated: [TLibHandle: LibHandle].}
-
 proc loadLib*(path: string, global_symbols=false): LibHandle {.gcsafe.}
   ## loads a library from `path`. Returns nil if the library could not
   ## be loaded.
diff --git a/lib/pure/encodings.nim b/lib/pure/encodings.nim
index 731fbbc29..c67cd7579 100644
--- a/lib/pure/encodings.nim
+++ b/lib/pure/encodings.nim
@@ -27,8 +27,6 @@ type
   EncodingError* = object of ValueError ## exception that is raised
                                         ## for encoding errors
 
-{.deprecated: [EInvalidEncoding: EncodingError, PConverter: EncodingConverter].}
-
 when defined(windows):
   proc eqEncodingNames(a, b: string): bool =
     var i = 0
diff --git a/lib/pure/events.nim b/lib/pure/events.nim
index 23a8a2c58..a39dbe3bf 100644
--- a/lib/pure/events.nim
+++ b/lib/pure/events.nim
@@ -43,9 +43,6 @@ type
     s: seq[EventHandler]
   EventError* = object of ValueError
 
-{.deprecated: [TEventArgs: EventArgs, TEventHandler: EventHandler,
-  TEventEmitter: EventEmitter, EInvalidEvent: EventError].}
-
 proc initEventHandler*(name: string): EventHandler =
   ## Initializes an EventHandler with the specified name and returns it.
   result.handlers = @[]
diff --git a/lib/pure/hashes.nim b/lib/pure/hashes.nim
index b015ed311..6535bb0d3 100644
--- a/lib/pure/hashes.nim
+++ b/lib/pure/hashes.nim
@@ -45,7 +45,6 @@ type
   Hash* = 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.
-{.deprecated: [THash: Hash].}
 
 proc `!&`*(h: Hash, val: int): Hash {.inline.} =
   ## mixes a hash value `h` with `val` to produce a new hash value. This is
diff --git a/lib/pure/htmlparser.nim b/lib/pure/htmlparser.nim
index 2f833804d..9d4b57dc0 100644
--- a/lib/pure/htmlparser.nim
+++ b/lib/pure/htmlparser.nim
@@ -178,7 +178,6 @@ type
     tagVar,        ## the HTML ``var`` element
     tagVideo,      ## the HTML ``video`` element
     tagWbr         ## the HTML ``wbr`` element
-{.deprecated: [THtmlTag: HtmlTag].}
 
 const
   tagToStr* = [
diff --git a/lib/pure/httpclient.nim b/lib/pure/httpclient.nim
index b7617b0b5..3f1a3d067 100644
--- a/lib/pure/httpclient.nim
+++ b/lib/pure/httpclient.nim
@@ -219,10 +219,6 @@ type
                                         ## and ``postContent`` proc,
                                         ## when the server returns an error
 
-{.deprecated: [TResponse: Response, PProxy: Proxy,
-  EInvalidProtocol: ProtocolError, EHttpRequestErr: HttpRequestError
-].}
-
 const defUserAgent* = "Nim httpclient/" & NimVersion
 
 proc httpError(msg: string) =
@@ -362,8 +358,6 @@ proc parseResponse(s: Socket, getBody: bool, timeout: int): Response =
   else:
     result.body = ""
 
-{.deprecated: [THttpMethod: HttpMethod].}
-
 when not defined(ssl):
   type SSLContext = ref object
 var defaultSSLContext {.threadvar.}: SSLContext
@@ -585,7 +579,7 @@ proc request*(url: string, httpMethod: string, extraHeaders = "",
 
   result = parseResponse(s, httpMethod != "HEAD", timeout)
 
-proc request*(url: string, httpMethod = httpGET, extraHeaders = "",
+proc request*(url: string, httpMethod = HttpGET, extraHeaders = "",
               body = "", sslContext = defaultSSLContext, timeout = -1,
               userAgent = defUserAgent, proxy: Proxy = nil): Response
               {.deprecated.} =
@@ -627,13 +621,13 @@ proc get*(url: string, extraHeaders = "", maxRedirects = 5,
   ## server takes longer than specified an ETimeout exception will be raised.
   ##
   ## **Deprecated since version 0.15.0**: use ``HttpClient.get`` instead.
-  result = request(url, httpGET, extraHeaders, "", sslContext, timeout,
+  result = request(url, HttpGET, extraHeaders, "", sslContext, timeout,
                    userAgent, proxy)
   var lastURL = url
   for i in 1..maxRedirects:
     if result.status.redirection():
       let redirectTo = getNewLocation(lastURL, result.headers)
-      result = request(redirectTo, httpGET, extraHeaders, "", sslContext,
+      result = request(redirectTo, HttpGET, extraHeaders, "", sslContext,
                        timeout, userAgent, proxy)
       lastURL = redirectTo
 
@@ -687,13 +681,13 @@ proc post*(url: string, extraHeaders = "", body = "",
   if not multipart.isNil:
     xh.add(withNewLine("Content-Type: " & mpContentType))
 
-  result = request(url, httpPOST, xh, xb, sslContext, timeout, userAgent,
+  result = request(url, HttpPOST, xh, xb, sslContext, timeout, userAgent,
                    proxy)
   var lastURL = url
   for i in 1..maxRedirects:
     if result.status.redirection():
       let redirectTo = getNewLocation(lastURL, result.headers)
-      var meth = if result.status != "307": httpGet else: httpPost
+      var meth = if result.status != "307": HttpGet else: HttpPost
       result = request(redirectTo, meth, xh, xb, sslContext, timeout,
                        userAgent, proxy)
       lastURL = redirectTo
@@ -749,7 +743,7 @@ proc generateHeaders(requestUrl: Uri, httpMethod: string,
 
   if proxy.isNil or requestUrl.scheme == "https":
     # /path?query
-    if requestUrl.path[0] != '/': result.add '/'
+    if not requestUrl.path.startsWith("/"): result.add '/'
     result.add(requestUrl.path)
     if requestUrl.query.len > 0:
       result.add("?" & requestUrl.query)
diff --git a/lib/pure/httpcore.nim b/lib/pure/httpcore.nim
index 5df26fdd5..f85375111 100644
--- a/lib/pure/httpcore.nim
+++ b/lib/pure/httpcore.nim
@@ -45,10 +45,6 @@ type
                       ## TCP/IP tunnel, usually used for proxies.
     HttpPatch         ## Applies partial modifications to a resource.
 
-{.deprecated: [httpGet: HttpGet, httpHead: HttpHead, httpPost: HttpPost,
-               httpPut: HttpPut, httpDelete: HttpDelete, httpTrace: HttpTrace,
-               httpOptions: HttpOptions, httpConnect: HttpConnect].}
-
 
 const
   Http100* = HttpCode(100)
diff --git a/lib/pure/httpserver.nim b/lib/pure/httpserver.nim
index 9f54ed9e8..a81e8c0a8 100644
--- a/lib/pure/httpserver.nim
+++ b/lib/pure/httpserver.nim
@@ -110,7 +110,6 @@ when false:
   # TODO: Fix this, or get rid of it.
   type
     RequestMethod = enum reqGet, reqPost
-  {.deprecated: [TRequestMethod: RequestMethod].}
 
   proc executeCgi(client: Socket, path, query: string, meth: RequestMethod) =
     var env = newStringTable(modeCaseInsensitive)
@@ -225,7 +224,6 @@ type
   PAsyncHTTPServer* = ref AsyncHTTPServer
   AsyncHTTPServer = object of Server
     asyncSocket: AsyncSocket
-{.deprecated: [TAsyncHTTPServer: AsyncHTTPServer, TServer: Server].}
 
 proc open*(s: var Server, port = Port(80), reuseAddr = false) =
   ## creates a new server at port `port`. If ``port == 0`` a free port is
diff --git a/lib/pure/includes/asynccommon.nim b/lib/pure/includes/asynccommon.nim
index 45b10c584..06f4958c6 100644
--- a/lib/pure/includes/asynccommon.nim
+++ b/lib/pure/includes/asynccommon.nim
@@ -18,13 +18,13 @@ proc createAsyncNativeSocket*(domain: Domain = Domain.AF_INET,
   createAsyncNativeSocketImpl(domain, sockType, protocol)
 
 proc newAsyncNativeSocket*(domain: cint, sockType: cint,
-                           protocol: cint): AsyncFD {.deprecated.} =
+                           protocol: cint): AsyncFD {.deprecated: "use createAsyncNativeSocket instead".} =
   createAsyncNativeSocketImpl(domain, sockType, protocol)
 
 proc newAsyncNativeSocket*(domain: Domain = Domain.AF_INET,
                            sockType: SockType = SOCK_STREAM,
                            protocol: Protocol = IPPROTO_TCP): AsyncFD
-                           {.deprecated.} =
+                           {.deprecated: "use createAsyncNativeSocket instead".} =
   createAsyncNativeSocketImpl(domain, sockType, protocol)
 
 when defined(windows) or defined(nimdoc):
diff --git a/lib/pure/includes/oserr.nim b/lib/pure/includes/oserr.nim
index 0889d7383..bfb6118f2 100644
--- a/lib/pure/includes/oserr.nim
+++ b/lib/pure/includes/oserr.nim
@@ -12,50 +12,6 @@ when not defined(nimscript):
   when defined(windows):
     import winlean
 
-proc osErrorMsg*(): string {.rtl, extern: "nos$1", deprecated.} =
-  ## Retrieves the operating system's error flag, ``errno``.
-  ## On Windows ``GetLastError`` is checked before ``errno``.
-  ## Returns "" if no error occurred.
-  ##
-  ## **Deprecated since version 0.9.4**: use the other ``osErrorMsg`` proc.
-
-  result = ""
-  when defined(Windows) and not defined(nimscript):
-    var err = getLastError()
-    if err != 0'i32:
-      when useWinUnicode:
-        var msgbuf: WideCString
-        if formatMessageW(0x00000100 or 0x00001000 or 0x00000200 or 0x000000FF,
-                          nil, err, 0, addr(msgbuf), 0, nil) != 0'i32:
-          result = $msgbuf
-          if msgbuf != nil: localFree(cast[pointer](msgbuf))
-      else:
-        var msgbuf: cstring
-        if formatMessageA(0x00000100 or 0x00001000 or 0x00000200 or 0x000000FF,
-                          nil, err, 0, addr(msgbuf), 0, nil) != 0'i32:
-          result = $msgbuf
-          if msgbuf != nil: localFree(msgbuf)
-  when not defined(nimscript):
-    if errno != 0'i32:
-      result = $c_strerror(errno)
-
-{.push warning[deprecated]: off.}
-proc raiseOSError*(msg: string = "") {.noinline, rtl, extern: "nos$1",
-                                       deprecated.} =
-  ## raises an OSError exception with the given message ``msg``.
-  ## If ``msg == ""``, the operating system's error flag
-  ## (``errno``) is converted to a readable error message. On Windows
-  ## ``GetLastError`` is checked before ``errno``.
-  ## If no error flag is set, the message ``unknown OS error`` is used.
-  ##
-  ## **Deprecated since version 0.9.4**: use the other ``raiseOSError`` proc.
-  if len(msg) == 0:
-    var m = osErrorMsg()
-    raise newException(OSError, if m.len > 0: m else: "unknown OS error")
-  else:
-    raise newException(OSError, msg)
-{.pop.}
-
 proc `==`*(err1, err2: OSErrorCode): bool {.borrow.}
 proc `$`*(err: OSErrorCode): string {.borrow.}
 
diff --git a/lib/pure/json.nim b/lib/pure/json.nim
index 574b13fbf..b16918959 100644
--- a/lib/pure/json.nim
+++ b/lib/pure/json.nim
@@ -158,9 +158,6 @@ type
   JsonKindError* = object of ValueError ## raised by the ``to`` macro if the
                                         ## JSON kind is incorrect.
 
-{.deprecated: [TJsonEventKind: JsonEventKind, TJsonError: JsonError,
-  TJsonParser: JsonParser, TTokKind: TokKind].}
-
 const
   errorMessages: array[JsonError, string] = [
     "no error",
@@ -622,9 +619,6 @@ type
 
   JsonParsingError* = object of ValueError ## is raised for a JSON error
 
-{.deprecated: [EJsonParsingError: JsonParsingError, TJsonNode: JsonNodeObj,
-    PJsonNode: JsonNode, TJsonNodeKind: JsonNodeKind].}
-
 proc raiseParseErr*(p: JsonParser, msg: string) {.noinline, noreturn.} =
   ## raises an `EJsonParsingError` exception.
   raise newException(JsonParsingError, errorMsgExpected(p, msg))
@@ -695,7 +689,7 @@ proc getBiggestInt*(n: JsonNode, default: BiggestInt = 0): BiggestInt =
   if n.isNil or n.kind != JInt: return default
   else: return n.num
 
-proc getNum*(n: JsonNode, default: BiggestInt = 0): BiggestInt {.deprecated.} =
+proc getNum*(n: JsonNode, default: BiggestInt = 0): BiggestInt {.deprecated: "use getInt or getBiggestInt instead".} =
   ## **Deprecated since v0.18.2:** use ``getInt`` or ``getBiggestInt`` instead.
   getBiggestInt(n, default)
 
@@ -709,7 +703,7 @@ proc getFloat*(n: JsonNode, default: float = 0.0): float =
   of JInt: return float(n.num)
   else: return default
 
-proc getFNum*(n: JsonNode, default: float = 0.0): float {.deprecated.} =
+proc getFNum*(n: JsonNode, default: float = 0.0): float {.deprecated: "use getFloat instead".} =
   ## **Deprecated since v0.18.2:** use ``getFloat`` instead.
   getFloat(n, default)
 
@@ -720,7 +714,7 @@ proc getBool*(n: JsonNode, default: bool = false): bool =
   if n.isNil or n.kind != JBool: return default
   else: return n.bval
 
-proc getBVal*(n: JsonNode, default: bool = false): bool {.deprecated.} =
+proc getBVal*(n: JsonNode, default: bool = false): bool {.deprecated: "use getBool instead".} =
   ## **Deprecated since v0.18.2:** use ``getBool`` instead.
   getBool(n, default)
 
@@ -946,7 +940,7 @@ proc contains*(node: JsonNode, val: JsonNode): bool =
   assert(node.kind == JArray)
   find(node.elems, val) >= 0
 
-proc existsKey*(node: JsonNode, key: string): bool {.deprecated.} = node.hasKey(key)
+proc existsKey*(node: JsonNode, key: string): bool {.deprecated: "use hasKey instead".} = node.hasKey(key)
   ## **Deprecated:** use `hasKey` instead.
 
 proc `[]=`*(obj: JsonNode, key: string, val: JsonNode) {.inline.} =
@@ -1277,7 +1271,6 @@ else:
   from math import `mod`
   type
     JSObject = object
-  {.deprecated: [TJSObject: JSObject].}
 
   proc parseNativeJson(x: cstring): JSObject {.importc: "JSON.parse".}
 
diff --git a/lib/pure/lexbase.nim b/lib/pure/lexbase.nim
index 15a390f0b..e38acd5ef 100644
--- a/lib/pure/lexbase.nim
+++ b/lib/pure/lexbase.nim
@@ -40,8 +40,6 @@ type
     offsetBase*: int          # use ``offsetBase + bufpos`` to get the offset
     refillChars: set[char]
 
-{.deprecated: [TBaseLexer: BaseLexer].}
-
 const
   chrSize = sizeof(char)
 
diff --git a/lib/pure/logging.nim b/lib/pure/logging.nim
index 43b5ab3ab..cdff1f548 100644
--- a/lib/pure/logging.nim
+++ b/lib/pure/logging.nim
@@ -96,10 +96,6 @@ when not defined(js):
       logFiles: int # how many log files already created, e.g. basename.1, basename.2...
       bufSize: int # size of output buffer (-1: use system defaults, 0: unbuffered, >0: fixed buffer size)
 
-  {.deprecated: [PFileLogger: FileLogger, PRollingFileLogger: RollingFileLogger].}
-
-{.deprecated: [TLevel: Level, PLogger: Logger, PConsoleLogger: ConsoleLogger].}
-
 var
   level {.threadvar.}: Level   ## global log filter
   handlers {.threadvar.}: seq[Logger] ## handlers with their own log levels
diff --git a/lib/pure/marshal.nim b/lib/pure/marshal.nim
index 6ee830786..b88c9dd85 100644
--- a/lib/pure/marshal.nim
+++ b/lib/pure/marshal.nim
@@ -309,7 +309,6 @@ when not defined(testing) and isMainModule:
     Node = object
       next, prev: PNode
       data: string
-  {.deprecated: [TNode: Node].}
 
   proc buildList(): PNode =
     new(result)
diff --git a/lib/pure/math.nim b/lib/pure/math.nim
index cbd04a145..5f3240e00 100644
--- a/lib/pure/math.nim
+++ b/lib/pure/math.nim
@@ -29,11 +29,21 @@ proc binom*(n, k: int): int {.noSideEffect.} =
   for i in countup(2, k):
     result = (result * (n + 1 - i)) div i
 
-proc fac*(n: int): int {.noSideEffect.} =
+proc createFactTable[N: static[int]]: array[N, int] =
+  result[0] = 1
+  for i in 1 ..< N:
+    result[i] = result[i - 1] * i
+
+proc fac*(n: int): int =
   ## Computes the faculty/factorial function.
-  result = 1
-  for i in countup(2, n):
-    result = result * i
+  const factTable =
+    when sizeof(int) == 4:
+      createFactTable[13]()
+    else:
+      createFactTable[21]()
+  assert(n > 0, $n & " must not be negative.")
+  assert(n < factTable.len, $n & " is too large to look up in the table")
+  factTable[n]
 
 {.push checks:off, line_dir:off, stack_trace:off.}
 
diff --git a/lib/pure/memfiles.nim b/lib/pure/memfiles.nim
index 5c73381ff..bf6795b0c 100644
--- a/lib/pure/memfiles.nim
+++ b/lib/pure/memfiles.nim
@@ -38,8 +38,6 @@ type
     else:
       handle: cint
 
-{.deprecated: [TMemFile: MemFile].}
-
 proc mapMem*(m: var MemFile, mode: FileMode = fmRead,
              mappedSize = -1, offset = 0): pointer =
   ## returns a pointer to a mapped portion of MemFile `m`
diff --git a/lib/pure/mersenne.nim b/lib/pure/mersenne.nim
index 6ac0c4e56..b2227f114 100644
--- a/lib/pure/mersenne.nim
+++ b/lib/pure/mersenne.nim
@@ -12,8 +12,6 @@ type
     mt: array[0..623, uint32]
     index: int
 
-{.deprecated: [TMersenneTwister: MersenneTwister].}
-
 proc newMersenneTwister*(seed: uint32): MersenneTwister =
   result.index = 0
   result.mt[0] = seed
diff --git a/lib/pure/mimetypes.nim b/lib/pure/mimetypes.nim
index b397ef47b..ff69ba61e 100644
--- a/lib/pure/mimetypes.nim
+++ b/lib/pure/mimetypes.nim
@@ -13,8 +13,6 @@ type
   MimeDB* = object
     mimes: StringTableRef
 
-{.deprecated: [TMimeDB: MimeDB].}
-
 const mimes* = {
     "ez": "application/andrew-inset",
     "anx": "application/annodex",
diff --git a/lib/pure/nativesockets.nim b/lib/pure/nativesockets.nim
index 09fa253f1..5545ca2d1 100644
--- a/lib/pure/nativesockets.nim
+++ b/lib/pure/nativesockets.nim
@@ -85,9 +85,6 @@ type
     length*: int
     addrList*: seq[string]
 
-{.deprecated: [TPort: Port, TDomain: Domain, TType: SockType,
-    TProtocol: Protocol, TServent: Servent, THostent: Hostent].}
-
 when useWinVersion:
   let
     osInvalidSocket* = winlean.INVALID_SOCKET
@@ -640,7 +637,7 @@ proc pruneSocketSet(s: var seq[SocketHandle], fd: var TFdSet) =
       inc(i)
   setLen(s, L)
 
-proc select*(readfds: var seq[SocketHandle], timeout = 500): int {.deprecated.} =
+proc select*(readfds: var seq[SocketHandle], timeout = 500): int {.deprecated: "use selectRead instead".} =
   ## When a socket in ``readfds`` is ready to be read from then a non-zero
   ## value will be returned specifying the count of the sockets which can be
   ## read from. The sockets which can be read from will also be removed
diff --git a/lib/pure/net.nim b/lib/pure/net.nim
index e522d86fe..fc04ef1af 100644
--- a/lib/pure/net.nim
+++ b/lib/pure/net.nim
@@ -110,9 +110,6 @@ when defineSsl:
       serverGetPskFunc: SslServerGetPskFunc
       clientGetPskFunc: SslClientGetPskFunc
 
-  {.deprecated: [ESSL: SSLError, TSSLCVerifyMode: SSLCVerifyMode,
-    TSSLProtVersion: SSLProtVersion, PSSLContext: SSLContext,
-    TSSLAcceptResult: SSLAcceptResult].}
 else:
   type
     SslContext* = void # TODO: Workaround #4797.
@@ -159,10 +156,6 @@ type
     Peek,
     SafeDisconn ## Ensures disconnection exceptions (ECONNRESET, EPIPE etc) are not thrown.
 
-{.deprecated: [TSocketFlags: SocketFlag, ETimeout: TimeoutError,
-    TReadLineResult: ReadLineResult, TSOBool: SOBool, PSocket: Socket,
-    TSocketImpl: SocketImpl].}
-
 type
   IpAddressFamily* {.pure.} = enum ## Describes the type of an IP address
     IPv6, ## IPv6 address
@@ -176,8 +169,6 @@ type
     of IpAddressFamily.IPv4:
       address_v4*: array[0..3, uint8] ## Contains the IP address in bytes in
                                       ## case of IPv4
-{.deprecated: [TIpAddress: IpAddress].}
-
 
 proc socketError*(socket: Socket, err: int = -1, async = false,
                   lastError = (-1).OSErrorCode): void {.gcsafe.}
@@ -969,7 +960,7 @@ when defined(posix) and not defined(nimdoc):
       raise newException(ValueError, "socket path too long")
     copyMem(addr result.sun_path, path.cstring, path.len + 1)
 
-when defined(posix):
+when defined(posix) or defined(nimdoc):
   proc connectUnix*(socket: Socket, path: string) =
     ## Connects to Unix socket on `path`.
     ## This only works on Unix-style systems: Mac OS X, BSD and Linux
diff --git a/lib/pure/nimprof.nim b/lib/pure/nimprof.nim
index 4289eb049..506c6bfaa 100644
--- a/lib/pure/nimprof.nim
+++ b/lib/pure/nimprof.nim
@@ -30,7 +30,6 @@ when not declared(system.StackTrace):
   type StackTrace = object
     lines: array[0..20, cstring]
     files: array[0..20, cstring]
-  {.deprecated: [TStackTrace: StackTrace].}
   proc `[]`*(st: StackTrace, i: int): cstring = st.lines[i]
 
 # We use a simple hash table of bounded size to keep track of the stack traces:
@@ -39,7 +38,6 @@ type
     total: int
     st: StackTrace
   ProfileData = array[0..64*1024-1, ptr ProfileEntry]
-{.deprecated: [TProfileEntry: ProfileEntry, TProfileData: ProfileData].}
 
 proc `==`(a, b: StackTrace): bool =
   for i in 0 .. high(a.lines):
diff --git a/lib/pure/oids.nim b/lib/pure/oids.nim
index 26a55de6c..d6369b5f9 100644
--- a/lib/pure/oids.nim
+++ b/lib/pure/oids.nim
@@ -23,11 +23,9 @@ type
     fuzz: int32  ##
     count: int32 ##
 
-{.deprecated: [Toid: Oid].}
-
 proc `==`*(oid1: Oid, oid2: Oid): bool =
-    ## Compare two Mongo Object IDs for equality
-    return (oid1.time == oid2.time) and (oid1.fuzz == oid2.fuzz) and (oid1.count == oid2.count)
+  ## Compare two Mongo Object IDs for equality
+  return (oid1.time == oid2.time) and (oid1.fuzz == oid2.fuzz) and (oid1.count == oid2.count)
 
 proc hexbyte*(hex: char): int =
   case hex
diff --git a/lib/pure/options.nim b/lib/pure/options.nim
index aaffb57ca..bd01b208a 100644
--- a/lib/pure/options.nim
+++ b/lib/pure/options.nim
@@ -134,7 +134,7 @@ proc get*[T](self: Option[T]): T =
 
 proc get*[T](self: Option[T], otherwise: T): T =
   ## Returns the contents of this option or `otherwise` if the option is none.
-  if self.has:
+  if self.isSome:
     self.val
   else:
     otherwise
@@ -154,7 +154,7 @@ proc map*[T, R](self: Option[T], callback: proc (input: T): R): Option[R] =
 
 proc flatten*[A](self: Option[Option[A]]): Option[A] =
   ## Remove one level of structure in a nested Option.
-  if self.has:
+  if self.isSome:
     self.val
   else:
     none(A)
@@ -179,14 +179,14 @@ proc filter*[T](self: Option[T], callback: proc (input: T): bool): Option[T] =
 proc `==`*(a, b: Option): bool =
   ## Returns ``true`` if both ``Option``s are ``none``,
   ## or if they have equal values
-  (a.has and b.has and a.val == b.val) or (not a.has and not b.has)
+  (a.isSome and b.isSome and a.val == b.val) or (not a.isSome and not b.isSome)
 
 proc `$`*[T](self: Option[T]): string =
   ## Get the string representation of this option. If the option has a value,
   ## the result will be `Some(x)` where `x` is the string representation of the contained value.
   ## If the option does not have a value, the result will be `None[T]` where `T` is the name of
   ## the type contained in the option.
-  if self.has:
+  if self.isSome:
     "Some(" & $self.val & ")"
   else:
     "None[" & T.name & "]"
diff --git a/lib/pure/os.nim b/lib/pure/os.nim
index 644afee32..03445a035 100644
--- a/lib/pure/os.nim
+++ b/lib/pure/os.nim
@@ -431,8 +431,6 @@ type
     fpOthersWrite,         ## write access for others
     fpOthersRead           ## read access for others
 
-{.deprecated: [TFilePermission: FilePermission].}
-
 proc getFilePermissions*(filename: string): set[FilePermission] {.
   rtl, extern: "nos$1", tags: [ReadDirEffect].} =
   ## retrieves file permissions for `filename`. `OSError` is raised in case of
@@ -730,8 +728,6 @@ type
     pcDir,                ## path refers to a directory
     pcLinkToDir           ## path refers to a symbolic link to a directory
 
-{.deprecated: [TPathComponent: PathComponent].}
-
 
 when defined(posix):
   proc getSymlinkFileKind(path: string): PathComponent =
@@ -1441,18 +1437,6 @@ proc getAppFilename*(): string {.rtl, extern: "nos$1", tags: [ReadIOEffect].} =
     if result.len == 0:
       result = getApplHeuristic()
 
-proc getApplicationFilename*(): string {.rtl, extern: "nos$1", deprecated.} =
-  ## Returns the filename of the application's executable.
-  ## **Deprecated since version 0.8.12**: use ``getAppFilename``
-  ## instead.
-  result = getAppFilename()
-
-proc getApplicationDir*(): string {.rtl, extern: "nos$1", deprecated.} =
-  ## Returns the directory of the application's executable.
-  ## **Deprecated since version 0.8.12**: use ``getAppDir``
-  ## instead.
-  result = splitFile(getAppFilename()).dir
-
 proc getAppDir*(): string {.rtl, extern: "nos$1", tags: [ReadIOEffect].} =
   ## Returns the directory of the application's executable.
   result = splitFile(getAppFilename()).dir
diff --git a/lib/pure/ospaths.nim b/lib/pure/ospaths.nim
index ee2b715d3..c0d3ef512 100644
--- a/lib/pure/ospaths.nim
+++ b/lib/pure/ospaths.nim
@@ -29,11 +29,6 @@ type
 
   OSErrorCode* = distinct int32 ## Specifies an OS Error Code.
 
-{.deprecated: [FReadEnv: ReadEnvEffect, FWriteEnv: WriteEnvEffect,
-    FReadDir: ReadDirEffect,
-    FWriteDir: WriteDirEffect,
-    TOSErrorCode: OSErrorCode
-].}
 const
   doslikeFileSystem* = defined(windows) or defined(OS2) or defined(DOS)
 
diff --git a/lib/pure/osproc.nim b/lib/pure/osproc.nim
index bcab5ad3a..664446d54 100644
--- a/lib/pure/osproc.nim
+++ b/lib/pure/osproc.nim
@@ -61,9 +61,6 @@ type
   Process* = ref ProcessObj ## represents an operating system process
 
 
-{.deprecated: [TProcess: ProcessObj, PProcess: Process,
-  TProcessOption: ProcessOption].}
-
 const poUseShell* {.deprecated.} = poUsePath
   ## Deprecated alias for poUsePath.
 
@@ -373,17 +370,15 @@ template streamAccess(p) =
 when defined(Windows) and not defined(useNimRtl):
   # We need to implement a handle stream for Windows:
   type
-    PFileHandleStream = ref FileHandleStream
-    FileHandleStream = object of StreamObj
+    FileHandleStream = ref object of StreamObj
       handle: Handle
       atTheEnd: bool
-  {.deprecated: [TFileHandleStream: FileHandleStream].}
 
   proc hsClose(s: Stream) = discard # nothing to do here
-  proc hsAtEnd(s: Stream): bool = return PFileHandleStream(s).atTheEnd
+  proc hsAtEnd(s: Stream): bool = return FileHandleStream(s).atTheEnd
 
   proc hsReadData(s: Stream, buffer: pointer, bufLen: int): int =
-    var s = PFileHandleStream(s)
+    var s = FileHandleStream(s)
     if s.atTheEnd: return 0
     var br: int32
     var a = winlean.readFile(s.handle, buffer, bufLen.cint, addr br, nil)
@@ -395,13 +390,13 @@ when defined(Windows) and not defined(useNimRtl):
     result = br
 
   proc hsWriteData(s: Stream, buffer: pointer, bufLen: int) =
-    var s = PFileHandleStream(s)
+    var s = FileHandleStream(s)
     var bytesWritten: int32
     var a = winlean.writeFile(s.handle, buffer, bufLen.cint,
                               addr bytesWritten, nil)
     if a == 0: raiseOSError(osLastError())
 
-  proc newFileHandleStream(handle: Handle): PFileHandleStream =
+  proc newFileHandleStream(handle: Handle): FileHandleStream =
     new(result)
     result.handle = handle
     result.closeImpl = hsClose
@@ -527,7 +522,7 @@ when defined(Windows) and not defined(useNimRtl):
           if setHandleInformation(he, DWORD(1), DWORD(0)) == 0'i32:
             raiseOsError(osLastError())
         if setHandleInformation(hi, DWORD(1), DWORD(0)) == 0'i32:
-          raiseOsError(osLastError())  
+          raiseOsError(osLastError())
         if setHandleInformation(ho, DWORD(1), DWORD(0)) == 0'i32:
           raiseOsError(osLastError())
       else:
@@ -752,14 +747,14 @@ elif not defined(useNimRtl):
       copyMem(result[i], addr(x[0]), x.len+1)
       inc(i)
 
-  type StartProcessData = object
-    sysCommand: string
-    sysArgs: cstringArray
-    sysEnv: cstringArray
-    workingDir: cstring
-    pStdin, pStdout, pStderr, pErrorPipe: array[0..1, cint]
-    options: set[ProcessOption]
-  {.deprecated: [TStartProcessData: StartProcessData].}
+  type
+    StartProcessData = object
+      sysCommand: string
+      sysArgs: cstringArray
+      sysEnv: cstringArray
+      workingDir: cstring
+      pStdin, pStdout, pStderr, pErrorPipe: array[0..1, cint]
+      options: set[ProcessOption]
 
   const useProcessAuxSpawn = declared(posix_spawn) and not defined(useFork) and
                              not defined(useClone) and not defined(linux)
diff --git a/lib/pure/parsecfg.nim b/lib/pure/parsecfg.nim
index 2a5dbc8f8..5fa2d8dc3 100644
--- a/lib/pure/parsecfg.nim
+++ b/lib/pure/parsecfg.nim
@@ -125,9 +125,6 @@ type
     tok: Token
     filename: string
 
-{.deprecated: [TCfgEventKind: CfgEventKind, TCfgEvent: CfgEvent,
-    TTokKind: TokKind, TToken: Token, TCfgParser: CfgParser].}
-
 # implementation
 
 const
diff --git a/lib/pure/parsecsv.nim b/lib/pure/parsecsv.nim
index 358ce829d..796114d37 100644
--- a/lib/pure/parsecsv.nim
+++ b/lib/pure/parsecsv.nim
@@ -66,8 +66,6 @@ type
   CsvError* = object of IOError ## exception that is raised if
                                 ## a parsing error occurs
 
-{.deprecated: [TCsvRow: CsvRow, TCsvParser: CsvParser, EInvalidCsv: CsvError].}
-
 proc raiseEInvalidCsv(filename: string, line, col: int,
                       msg: string) {.noreturn.} =
   var e: ref CsvError
diff --git a/lib/pure/parseopt.nim b/lib/pure/parseopt.nim
index c1a6161f9..58e1be0e4 100644
--- a/lib/pure/parseopt.nim
+++ b/lib/pure/parseopt.nim
@@ -54,8 +54,6 @@ type
                               ## or the argument, ``value`` is not "" if
                               ## the option was given a value
 
-{.deprecated: [TCmdLineKind: CmdLineKind, TOptParser: OptParser].}
-
 proc parseWord(s: string, i: int, w: var string,
                delim: set[char] = {'\x09', ' '}): int =
   result = i
diff --git a/lib/pure/parseopt2.nim b/lib/pure/parseopt2.nim
index 7254337d0..b54a56c0c 100644
--- a/lib/pure/parseopt2.nim
+++ b/lib/pure/parseopt2.nim
@@ -41,8 +41,6 @@ type
                               ## or the argument, ``value`` is not "" if
                               ## the option was given a value
 
-{.deprecated: [TCmdLineKind: CmdLineKind, TOptParser: OptParser].}
-
 proc initOptParser*(cmdline: seq[string]): OptParser {.rtl.} =
   ## Initalizes option parses with cmdline. cmdline should not contain
   ## argument 0 - program name.
@@ -122,8 +120,6 @@ proc cmdLineRest*(p: OptParser): TaintedString {.rtl, extern: "npo2$1", deprecat
 type
   GetoptResult* = tuple[kind: CmdLineKind, key, val: TaintedString]
 
-{.deprecated: [TGetoptResult: GetoptResult].}
-
 iterator getopt*(p: var OptParser): GetoptResult =
   ## This is an convenience iterator for iterating over the given OptParser object.
   ## Example:
diff --git a/lib/pure/parsesql.nim b/lib/pure/parsesql.nim
index fcc757bea..e3bab9a8d 100644
--- a/lib/pure/parsesql.nim
+++ b/lib/pure/parsesql.nim
@@ -45,8 +45,6 @@ type
   SqlLexer* = object of BaseLexer ## the parser object.
     filename: string
 
-{.deprecated: [TToken: Token, TSqlLexer: SqlLexer].}
-
 const
   tokKindToStr: array[TokKind, string] = [
     "invalid", "[EOF]", "identifier", "quoted identifier", "string constant",
diff --git a/lib/pure/parseutils.nim b/lib/pure/parseutils.nim
index 1d76234ea..d77790fe0 100644
--- a/lib/pure/parseutils.nim
+++ b/lib/pure/parseutils.nim
@@ -365,8 +365,6 @@ type
     ikVar,                   ## ``var`` part of the interpolated string
     ikExpr                   ## ``expr`` part of the interpolated string
 
-{.deprecated: [TInterpolatedKind: InterpolatedKind].}
-
 iterator interpolatedFragments*(s: string): tuple[kind: InterpolatedKind,
   value: string] =
   ## Tokenizes the string `s` into substrings for interpolation purposes.
diff --git a/lib/pure/parsexml.nim b/lib/pure/parsexml.nim
index 978c9c516..e0000aad3 100644
--- a/lib/pure/parsexml.nim
+++ b/lib/pure/parsexml.nim
@@ -98,9 +98,6 @@ type
     filename: string
     options: set[XmlParseOption]
 
-{.deprecated: [TXmlParser: XmlParser, TXmlParseOptions: XmlParseOption,
-    TXmlError: XmlErrorKind, TXmlEventKind: XmlEventKind].}
-
 const
   errorMessages: array[XmlErrorKind, string] = [
     "no error",
diff --git a/lib/pure/pegs.nim b/lib/pure/pegs.nim
index 6d415efd0..830429842 100644
--- a/lib/pure/pegs.nim
+++ b/lib/pure/pegs.nim
@@ -74,8 +74,8 @@ type
     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: Node                   ## the rule that the symbol refers to
-  Node {.shallow.} = object
+    rule: Peg                   ## the rule that the symbol refers to
+  Peg* {.shallow.} = object ## type that represents a PEG
     case kind: PegKind
     of pkEmpty..pkWhitespace: nil
     of pkTerminal, pkTerminalIgnoreCase, pkTerminalIgnoreStyle: term: string
@@ -83,13 +83,9 @@ type
     of pkCharChoice, pkGreedyRepSet: charChoice: ref set[char]
     of pkNonTerminal: nt: NonTerminal
     of pkBackRef..pkBackRefIgnoreStyle: index: range[0..MaxSubpatterns]
-    else: sons: seq[Node]
+    else: sons: seq[Peg]
   NonTerminal* = ref NonTerminalObj
 
-  Peg* = Node ## type that represents a PEG
-
-{.deprecated: [TPeg: Peg, TNode: Node].}
-
 proc term*(t: string): Peg {.nosideEffect, rtl, extern: "npegs$1Str".} =
   ## constructs a PEG from a terminal string
   if t.len != 1:
@@ -621,7 +617,7 @@ proc rawMatch*(s: string, p: Peg, start: int, c: var Captures): int {.
       a, b: Rune
     result = start
     while i < len(p.term):
-      while true:
+      while i < len(p.term):
         fastRuneAt(p.term, i, a)
         if a != Rune('_'): break
       while result < s.len:
diff --git a/lib/pure/ropes.nim b/lib/pure/ropes.nim
index 24ba012e5..9b9cdb52a 100644
--- a/lib/pure/ropes.nim
+++ b/lib/pure/ropes.nim
@@ -37,8 +37,6 @@ type
     length: int
     data: string # != nil if a leaf
 
-{.deprecated: [PRope: Rope].}
-
 proc isConc(r: Rope): bool {.inline.} = return isNil(r.data)
 
 # Note that the left and right pointers are not needed for leafs.
diff --git a/lib/pure/scgi.nim b/lib/pure/scgi.nim
index 1ff26954e..e36803823 100644
--- a/lib/pure/scgi.nim
+++ b/lib/pure/scgi.nim
@@ -94,9 +94,6 @@ type
     disp: Dispatcher
   AsyncScgiState* = ref AsyncScgiStateObj
 
-{.deprecated: [EScgi: ScgiError, TScgiState: ScgiState,
-   PAsyncScgiState: AsyncScgiState].}
-
 proc recvBuffer(s: var ScgiState, L: int) =
   if L > s.bufLen:
     s.bufLen = L
diff --git a/lib/pure/selectors.nim b/lib/pure/selectors.nim
index dda5658a2..640df8282 100644
--- a/lib/pure/selectors.nim
+++ b/lib/pure/selectors.nim
@@ -271,7 +271,7 @@ else:
       msg.add("Internal Error\n")
     var err = newException(IOSelectorsException, msg)
     raise err
-  
+
   proc setNonBlocking(fd: cint) {.inline.} =
     setBlocking(fd.SocketHandle, false)
 
@@ -316,18 +316,18 @@ else:
     include ioselects/ioselectors_poll
 
 proc register*[T](s: Selector[T], fd: int | SocketHandle,
-                  events: set[Event], data: T) {.deprecated.} =
+                  events: set[Event], data: T) {.deprecated: "use registerHandle instead".} =
   ## **Deprecated since v0.18.0:** Use ``registerHandle`` instead.
   s.registerHandle(fd, events, data)
 
-proc setEvent*(ev: SelectEvent) {.deprecated.} =
+proc setEvent*(ev: SelectEvent) {.deprecated: "use trigger instead".} =
   ## Trigger event ``ev``.
   ##
   ## **Deprecated since v0.18.0:** Use ``trigger`` instead.
   ev.trigger()
 
 proc update*[T](s: Selector[T], fd: int | SocketHandle,
-                events: set[Event]) {.deprecated.} =
+                events: set[Event]) {.deprecated: "use updateHandle instead".} =
   ## Update file/socket descriptor ``fd``, registered in selector
   ## ``s`` with new events set ``event``.
   ##
diff --git a/lib/pure/smtp.nim b/lib/pure/smtp.nim
index 08e6c8112..c2c674b84 100644
--- a/lib/pure/smtp.nim
+++ b/lib/pure/smtp.nim
@@ -51,8 +51,6 @@ type
   Smtp* = SmtpBase[Socket]
   AsyncSmtp* = SmtpBase[AsyncSocket]
 
-{.deprecated: [EInvalidReply: ReplyError, TMessage: Message, TSMTP: Smtp].}
-
 proc debugSend(smtp: Smtp | AsyncSmtp, cmd: string) {.multisync.} =
   if smtp.debug:
     echo("C:" & cmd)
diff --git a/lib/pure/stats.nim b/lib/pure/stats.nim
index 964938133..ce32108c2 100644
--- a/lib/pure/stats.nim
+++ b/lib/pure/stats.nim
@@ -65,8 +65,6 @@ type
     y_stats*: RunningStat   ## stats for second set of data
     s_xy: float             ## accumulated data for combined xy
 
-{.deprecated: [TFloatClass: FloatClass, TRunningStat: RunningStat].}
-
 # ----------- RunningStat --------------------------
 proc clear*(s: var RunningStat) =
   ## reset `s`
diff --git a/lib/pure/streams.nim b/lib/pure/streams.nim
index 8fb14b6f6..68922f730 100644
--- a/lib/pure/streams.nim
+++ b/lib/pure/streams.nim
@@ -57,8 +57,6 @@ type
       tags: [WriteIOEffect], gcsafe.}
     flushImpl*: proc (s: Stream) {.nimcall, tags: [WriteIOEffect], gcsafe.}
 
-{.deprecated: [PStream: Stream, TStream: StreamObj].}
-
 proc flush*(s: Stream) =
   ## flushes the buffers that the stream `s` might use.
   if not isNil(s.flushImpl): s.flushImpl(s)
@@ -76,27 +74,14 @@ proc atEnd*(s: Stream): bool =
   ## been read.
   result = s.atEndImpl(s)
 
-proc atEnd*(s, unused: Stream): bool {.deprecated.} =
-  ## checks if more data can be read from `f`. Returns true if all data has
-  ## been read.
-  result = s.atEndImpl(s)
-
 proc setPosition*(s: Stream, pos: int) =
   ## sets the position `pos` of the stream `s`.
   s.setPositionImpl(s, pos)
 
-proc setPosition*(s, unused: Stream, pos: int) {.deprecated.} =
-  ## sets the position `pos` of the stream `s`.
-  s.setPositionImpl(s, pos)
-
 proc getPosition*(s: Stream): int =
   ## retrieves the current position in the stream `s`.
   result = s.getPositionImpl(s)
 
-proc getPosition*(s, unused: Stream): int {.deprecated.} =
-  ## retrieves the current position in the stream `s`.
-  result = s.getPositionImpl(s)
-
 proc readData*(s: Stream, buffer: pointer, bufLen: int): int =
   ## low level proc that reads data into an untyped `buffer` of `bufLen` size.
   result = s.readDataImpl(s, buffer, bufLen)
@@ -114,11 +99,6 @@ proc readAll*(s: Stream): string =
     inc r, bufferSize
     setLen(result, r+bufferSize)
 
-proc readData*(s, unused: Stream, buffer: pointer,
-               bufLen: int): int {.deprecated.} =
-  ## low level proc that reads data into an untyped `buffer` of `bufLen` size.
-  result = s.readDataImpl(s, buffer, bufLen)
-
 proc peekData*(s: Stream, buffer: pointer, bufLen: int): int =
   ## low level proc that reads data into an untyped `buffer` of `bufLen` size
   ## without moving stream position
@@ -153,11 +133,6 @@ proc write*(s: Stream, x: string) =
   else:
     if x.len > 0: writeData(s, unsafeAddr x[0], x.len)
 
-proc writeLn*(s: Stream, args: varargs[string, `$`]) {.deprecated.} =
-  ## **Deprecated since version 0.11.4:** Use **writeLine** instead.
-  for str in args: write(s, str)
-  write(s, "\n")
-
 proc writeLine*(s: Stream, args: varargs[string, `$`]) =
   ## writes one or more strings to the the stream `s` followed
   ## by a new line. No length field or terminating zero is written.
@@ -348,8 +323,6 @@ when not defined(js):
       data*: string
       pos: int
 
-  {.deprecated: [PStringStream: StringStream, TStringStream: StringStreamObj].}
-
   proc ssAtEnd(s: Stream): bool =
     var s = StringStream(s)
     return s.pos >= s.data.len
@@ -409,7 +382,6 @@ when not defined(js):
     FileStream* = ref FileStreamObj ## a stream that encapsulates a `File`
     FileStreamObj* = object of Stream
       f: File
-  {.deprecated: [PFileStream: FileStream, TFileStream: FileStreamObj].}
 
   proc fsClose(s: Stream) =
     if FileStream(s).f != nil:
@@ -472,9 +444,6 @@ else:
       handle*: FileHandle
       pos: int
 
-  {.deprecated: [PFileHandleStream: FileHandleStream,
-     TFileHandleStream: FileHandleStreamObj].}
-
   proc newEOS(msg: string): ref OSError =
     new(result)
     result.msg = msg
diff --git a/lib/pure/strtabs.nim b/lib/pure/strtabs.nim
index 75f9b42cd..d8a23286a 100644
--- a/lib/pure/strtabs.nim
+++ b/lib/pure/strtabs.nim
@@ -17,9 +17,7 @@ import
 
 when defined(js):
   {.pragma: rtlFunc.}
-  {.pragma: deprecatedGetFunc.}
 else:
-  {.pragma: deprecatedGetFunc, deprecatedGet.}
   {.pragma: rtlFunc, rtl.}
   import os
   include "system/inclrtl"
@@ -38,9 +36,6 @@ type
 
   StringTableRef* = ref StringTableObj ## use this type to declare string tables
 
-{.deprecated: [TStringTableMode: StringTableMode,
-  TStringTable: StringTableObj, PStringTable: StringTableRef].}
-
 proc len*(t: StringTableRef): int {.rtlFunc, extern: "nst$1".} =
   ## returns the number of keys in `t`.
   result = t.counter
@@ -73,10 +68,6 @@ type
     useKey                    ## do not replace ``$key`` if it is not found
                               ## in the table (or in the environment)
 
-{.deprecated: [TFormatFlag: FormatFlag].}
-
-# implementation
-
 const
   growthFactor = 2
   startSize = 64
@@ -118,17 +109,12 @@ template get(t: StringTableRef, key: string) =
       raise newException(KeyError, "key not found")
 
 proc `[]`*(t: StringTableRef, key: string): var string {.
-           rtlFunc, extern: "nstTake", deprecatedGetFunc.} =
+           rtlFunc, extern: "nstTake".} =
   ## retrieves the location at ``t[key]``. If `key` is not in `t`, the
   ## ``KeyError`` exception is raised. One can check with ``hasKey`` whether
   ## the key exists.
   get(t, key)
 
-proc mget*(t: StringTableRef, key: string): var string {.deprecated.} =
-  ## retrieves the location at ``t[key]``. If `key` is not in `t`, the
-  ## ``KeyError`` exception is raised. Use ```[]``` instead.
-  get(t, key)
-
 proc getOrDefault*(t: StringTableRef; key: string, default: string = ""): string =
   var index = rawGet(t, key)
   if index >= 0: result = t.data[index].val
@@ -193,7 +179,8 @@ proc newStringTable*(mode: StringTableMode): StringTableRef {.
   result.counter = 0
   newSeq(result.data, startSize)
 
-proc clear*(s: StringTableRef, mode: StringTableMode) =
+proc clear*(s: StringTableRef, mode: StringTableMode) {.
+  rtlFunc, extern: "nst$1".} =
   ## resets a string table to be empty again.
   s.mode = mode
   s.counter = 0
diff --git a/lib/pure/strutils.nim b/lib/pure/strutils.nim
index 3f01f0285..ee3072c85 100644
--- a/lib/pure/strutils.nim
+++ b/lib/pure/strutils.nim
@@ -1262,21 +1262,20 @@ proc initSkipTable*(a: var SkipTable, sub: string)
   {.noSideEffect, rtl, extern: "nsuInitSkipTable".} =
   ## Preprocess table `a` for `sub`.
   let m = len(sub)
-  let m1 = m + 1
   var i = 0
   while i <= 0xff-7:
-    a[chr(i + 0)] = m1
-    a[chr(i + 1)] = m1
-    a[chr(i + 2)] = m1
-    a[chr(i + 3)] = m1
-    a[chr(i + 4)] = m1
-    a[chr(i + 5)] = m1
-    a[chr(i + 6)] = m1
-    a[chr(i + 7)] = m1
+    a[chr(i + 0)] = m
+    a[chr(i + 1)] = m
+    a[chr(i + 2)] = m
+    a[chr(i + 3)] = m
+    a[chr(i + 4)] = m
+    a[chr(i + 5)] = m
+    a[chr(i + 6)] = m
+    a[chr(i + 7)] = m
     i += 8
 
-  for i in 0..m-1:
-    a[sub[i]] = m-i
+  for i in 0 ..< m - 1:
+    a[sub[i]] = m - 1 - i
 
 proc find*(a: SkipTable, s, sub: string, start: Natural = 0, last: Natural = 0): int
   {.noSideEffect, rtl, extern: "nsuFindStrA".} =
@@ -1284,18 +1283,29 @@ proc find*(a: SkipTable, s, sub: string, start: Natural = 0, last: Natural = 0):
   ## If `last` is unspecified, it defaults to `s.high`.
   ##
   ## Searching is case-sensitive. If `sub` is not in `s`, -1 is returned.
+
   let
     last = if last==0: s.high else: last
-    m = len(sub)
-    n = last + 1
-  # search:
-  var j = start
-  while j <= n - m:
-    block match:
-      for k in 0..m-1:
-        if sub[k] != s[k+j]: break match
-      return j
-    inc(j, a[s[j+m]])
+    sLen = last - start + 1
+    subLast = sub.len - 1
+
+  if subLast == -1:
+    # this was an empty needle string,
+    # we count this as match in the first possible position:
+    return start
+
+  # This is an implementation of the Boyer-Moore Horspool algorithms
+  # https://en.wikipedia.org/wiki/Boyer%E2%80%93Moore%E2%80%93Horspool_algorithm
+  var skip = start
+
+  while last - skip >= subLast:
+    var i = subLast
+    while s[skip + i] == sub[i]:
+      if i == 0:
+        return skip
+      dec i
+    inc skip, a[s[skip + subLast]]
+
   return -1
 
 when not (defined(js) or defined(nimdoc) or defined(nimscript)):
@@ -1455,23 +1465,41 @@ proc contains*(s: string, chars: set[char]): bool {.noSideEffect.} =
 proc replace*(s, sub: string, by = ""): string {.noSideEffect,
   rtl, extern: "nsuReplaceStr".} =
   ## Replaces `sub` in `s` by the string `by`.
-  var a {.noinit.}: SkipTable
   result = ""
-  initSkipTable(a, sub)
-  let last = s.high
-  var i = 0
-  while true:
-    let j = find(a, s, sub, i, last)
-    if j < 0: break
-    add result, substr(s, i, j - 1)
+  let subLen = sub.len
+  if subLen == 0:
+    for c in s:
+      add result, by
+      add result, c
     add result, by
-    if sub.len == 0:
-      if i < s.len: add result, s[i]
-      i = j + 1
-    else:
-      i = j + sub.len
-  # copy the rest:
-  add result, substr(s, i)
+    return
+  elif subLen == 1:
+    # when the pattern is a single char, we use a faster
+    # char-based search that doesn't need a skip table:
+    var c = sub[0]
+    let last = s.high
+    var i = 0
+    while true:
+      let j = find(s, c, i, last)
+      if j < 0: break
+      add result, substr(s, i, j - 1)
+      add result, by
+      i = j + subLen
+    # copy the rest:
+    add result, substr(s, i)
+  else:
+    var a {.noinit.}: SkipTable
+    initSkipTable(a, sub)
+    let last = s.high
+    var i = 0
+    while true:
+      let j = find(a, s, sub, i, last)
+      if j < 0: break
+      add result, substr(s, i, j - 1)
+      add result, by
+      i = j + subLen
+    # copy the rest:
+    add result, substr(s, i)
 
 proc replace*(s: string, sub, by: char): string {.noSideEffect,
   rtl, extern: "nsuReplaceChar".} =
@@ -1492,6 +1520,7 @@ proc replaceWord*(s, sub: string, by = ""): string {.noSideEffect,
   ## Each occurrence of `sub` has to be surrounded by word boundaries
   ## (comparable to ``\\w`` in regular expressions), otherwise it is not
   ## replaced.
+  if sub.len == 0: return s
   const wordChars = {'a'..'z', 'A'..'Z', '0'..'9', '_', '\128'..'\255'}
   var a {.noinit.}: SkipTable
   result = ""
@@ -2326,236 +2355,243 @@ proc removePrefix*(s: var string, prefix: string) {.
     s.delete(0, prefix.len - 1)
 
 when isMainModule:
-  doAssert align("abc", 4) == " abc"
-  doAssert align("a", 0) == "a"
-  doAssert align("1232", 6) == "  1232"
-  doAssert align("1232", 6, '#') == "##1232"
-
-  doAssert alignLeft("abc", 4) == "abc "
-  doAssert alignLeft("a", 0) == "a"
-  doAssert alignLeft("1232", 6) == "1232  "
-  doAssert alignLeft("1232", 6, '#') == "1232##"
-
-  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
-
-  let
-    longInp = """ThisIsOneVeryLongStringWhichWeWillSplitIntoEightSeparatePartsNow"""
-    longOutp = "ThisIsOn\neVeryLon\ngStringW\nhichWeWi\nllSplitI\nntoEight\nSeparate\nPartsNow"
-  doAssert wordWrap(longInp, 8, true) == longOutp
-
-  doAssert formatBiggestFloat(1234.567, ffDecimal, -1) == "1234.567000"
-  doAssert formatBiggestFloat(1234.567, ffDecimal, 0) == "1235."
-  doAssert formatBiggestFloat(1234.567, ffDecimal, 1) == "1234.6"
-  doAssert formatBiggestFloat(0.00000000001, ffDecimal, 11) == "0.00000000001"
-  doAssert formatBiggestFloat(0.00000000001, ffScientific, 1, ',') in
-                                                   ["1,0e-11", "1,0e-011"]
-  # bug #6589
-  doAssert formatFloat(123.456, ffScientific, precision = -1) == "1.234560e+02"
-
-  doAssert "$# $3 $# $#" % ["a", "b", "c"] == "a c b c"
-  doAssert "${1}12 ${-1}$2" % ["a", "b"] == "a12 bb"
-
-  block: # formatSize tests
-    doAssert formatSize((1'i64 shl 31) + (300'i64 shl 20)) == "2.293GiB"
-    doAssert formatSize((2.234*1024*1024).int) == "2.234MiB"
-    doAssert formatSize(4096) == "4KiB"
-    doAssert formatSize(4096, prefix=bpColloquial, includeSpace=true) == "4 kB"
-    doAssert formatSize(4096, includeSpace=true) == "4 KiB"
-    doAssert formatSize(5_378_934, prefix=bpColloquial, decimalSep=',') == "5,13MB"
-
-  doAssert "$animal eats $food." % ["animal", "The cat", "food", "fish"] ==
-           "The cat eats fish."
-
-  doAssert "-ld a-ldz -ld".replaceWord("-ld") == " a-ldz "
-  doAssert "-lda-ldz -ld abc".replaceWord("-ld") == "-lda-ldz  abc"
-
-  doAssert "-lda-ldz -ld abc".replaceWord("") == "lda-ldz ld abc"
-  doAssert "oo".replace("", "abc") == "abcoabcoabc"
-
-  type MyEnum = enum enA, enB, enC, enuD, enE
-  doAssert parseEnum[MyEnum]("enu_D") == enuD
-
-  doAssert parseEnum("invalid enum value", enC) == enC
-
-  doAssert center("foo", 13) == "     foo     "
-  doAssert center("foo", 0) == "foo"
-  doAssert center("foo", 3, fillChar = 'a') == "foo"
-  doAssert center("foo", 10, fillChar = '\t') == "\t\t\tfoo\t\t\t\t"
-
-  doAssert count("foofoofoo", "foofoo") == 1
-  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"
-
-  doAssert "  foo\n  bar".indent(4, "Q") == "QQQQ  foo\nQQQQ  bar"
-
-  doAssert "abba".multiReplace(("a", "b"), ("b", "a")) == "baab"
-  doAssert "Hello World.".multiReplace(("ello", "ELLO"), ("World.", "PEOPLE!")) == "HELLO PEOPLE!"
-  doAssert "aaaa".multiReplace(("a", "aa"), ("aa", "bb")) == "aaaaaaaa"
-
-  doAssert isAlphaAscii('r')
-  doAssert isAlphaAscii('A')
-  doAssert(not isAlphaAscii('$'))
-
-  doAssert isAlphaAscii("Rasp")
-  doAssert isAlphaAscii("Args")
-  doAssert(not isAlphaAscii("$Tomato"))
-
-  doAssert isAlphaNumeric('3')
-  doAssert isAlphaNumeric('R')
-  doAssert(not isAlphaNumeric('!'))
-
-  doAssert isAlphaNumeric("34ABc")
-  doAssert isAlphaNumeric("Rad")
-  doAssert isAlphaNumeric("1234")
-  doAssert(not isAlphaNumeric("@nose"))
-
-  doAssert isDigit('3')
-  doAssert(not isDigit('a'))
-  doAssert(not isDigit('%'))
-
-  doAssert isDigit("12533")
-  doAssert(not isDigit("12.33"))
-  doAssert(not isDigit("A45b"))
-
-  doAssert isSpaceAscii('\t')
-  doAssert isSpaceAscii('\l')
-  doAssert(not isSpaceAscii('A'))
-
-  doAssert isSpaceAscii("\t\l \v\r\f")
-  doAssert isSpaceAscii("       ")
-  doAssert(not isSpaceAscii("ABc   \td"))
-
-  doAssert(isNilOrWhitespace(""))
-  doAssert(isNilOrWhitespace("       "))
-  doAssert(isNilOrWhitespace("\t\l \v\r\f"))
-  doAssert(not isNilOrWhitespace("ABc   \td"))
-
-  doAssert isLowerAscii('a')
-  doAssert isLowerAscii('z')
-  doAssert(not isLowerAscii('A'))
-  doAssert(not isLowerAscii('5'))
-  doAssert(not isLowerAscii('&'))
-
-  doAssert isLowerAscii("abcd")
-  doAssert(not isLowerAscii("abCD"))
-  doAssert(not isLowerAscii("33aa"))
-
-  doAssert isUpperAscii('A')
-  doAssert(not isUpperAscii('b'))
-  doAssert(not isUpperAscii('5'))
-  doAssert(not isUpperAscii('%'))
-
-  doAssert isUpperAscii("ABC")
-  doAssert(not isUpperAscii("AAcc"))
-  doAssert(not isUpperAscii("A#$"))
-
-  doAssert rsplit("foo bar", seps=Whitespace) == @["foo", "bar"]
-  doAssert rsplit(" foo bar", seps=Whitespace, maxsplit=1) == @[" foo", "bar"]
-  doAssert rsplit(" foo bar ", seps=Whitespace, maxsplit=1) == @[" foo bar", ""]
-  doAssert rsplit(":foo:bar", sep=':') == @["", "foo", "bar"]
-  doAssert rsplit(":foo:bar", sep=':', maxsplit=2) == @["", "foo", "bar"]
-  doAssert rsplit(":foo:bar", sep=':', maxsplit=3) == @["", "foo", "bar"]
-  doAssert rsplit("foothebar", sep="the") == @["foo", "bar"]
-
-  doAssert(unescape(r"\x013", "", "") == "\x013")
-
-  doAssert join(["foo", "bar", "baz"]) == "foobarbaz"
-  doAssert join(@["foo", "bar", "baz"], ", ") == "foo, bar, baz"
-  doAssert join([1, 2, 3]) == "123"
-  doAssert join(@[1, 2, 3], ", ") == "1, 2, 3"
-
-  doAssert """~~!!foo
+  proc nonStaticTests =
+    doAssert formatBiggestFloat(1234.567, ffDecimal, -1) == "1234.567000"
+    doAssert formatBiggestFloat(1234.567, ffDecimal, 0) == "1235."
+    doAssert formatBiggestFloat(1234.567, ffDecimal, 1) == "1234.6"
+    doAssert formatBiggestFloat(0.00000000001, ffDecimal, 11) == "0.00000000001"
+    doAssert formatBiggestFloat(0.00000000001, ffScientific, 1, ',') in
+                                                     ["1,0e-11", "1,0e-011"]
+    # bug #6589
+    doAssert formatFloat(123.456, ffScientific, precision = -1) == "1.234560e+02"
+
+    doAssert "$# $3 $# $#" % ["a", "b", "c"] == "a c b c"
+    doAssert "${1}12 ${-1}$2" % ["a", "b"] == "a12 bb"
+
+    block: # formatSize tests
+      doAssert formatSize((1'i64 shl 31) + (300'i64 shl 20)) == "2.293GiB"
+      doAssert formatSize((2.234*1024*1024).int) == "2.234MiB"
+      doAssert formatSize(4096) == "4KiB"
+      doAssert formatSize(4096, prefix=bpColloquial, includeSpace=true) == "4 kB"
+      doAssert formatSize(4096, includeSpace=true) == "4 KiB"
+      doAssert formatSize(5_378_934, prefix=bpColloquial, decimalSep=',') == "5,13MB"
+
+    block: # formatEng tests
+      doAssert formatEng(0, 2, trim=false) == "0.00"
+      doAssert formatEng(0, 2) == "0"
+      doAssert formatEng(53, 2, trim=false) == "53.00"
+      doAssert formatEng(0.053, 2, trim=false) == "53.00e-3"
+      doAssert formatEng(0.053, 4, trim=false) == "53.0000e-3"
+      doAssert formatEng(0.053, 4, trim=true) == "53e-3"
+      doAssert formatEng(0.053, 0) == "53e-3"
+      doAssert formatEng(52731234) == "52.731234e6"
+      doAssert formatEng(-52731234) == "-52.731234e6"
+      doAssert formatEng(52731234, 1) == "52.7e6"
+      doAssert formatEng(-52731234, 1) == "-52.7e6"
+      doAssert formatEng(52731234, 1, decimalSep=',') == "52,7e6"
+      doAssert formatEng(-52731234, 1, decimalSep=',') == "-52,7e6"
+
+      doAssert formatEng(4100, siPrefix=true, unit="V") == "4.1 kV"
+      doAssert formatEng(4.1, siPrefix=true, unit="V", useUnitSpace=true) == "4.1 V"
+      doAssert formatEng(4.1, siPrefix=true) == "4.1" # Note lack of space
+      doAssert formatEng(4100, siPrefix=true) == "4.1 k"
+      doAssert formatEng(4.1, siPrefix=true, unit="", useUnitSpace=true) == "4.1 " # Includes space
+      doAssert formatEng(4100, siPrefix=true, unit="") == "4.1 k"
+      doAssert formatEng(4100) == "4.1e3"
+      doAssert formatEng(4100, unit="V", useUnitSpace=true) == "4.1e3 V"
+      doAssert formatEng(4100, unit="", useUnitSpace=true) == "4.1e3 "
+      # Don't use SI prefix as number is too big
+      doAssert formatEng(3.1e22, siPrefix=true, unit="a", useUnitSpace=true) == "31e21 a"
+      # Don't use SI prefix as number is too small
+      doAssert formatEng(3.1e-25, siPrefix=true, unit="A", useUnitSpace=true) == "310e-27 A"
+
+  proc staticTests =
+    doAssert align("abc", 4) == " abc"
+    doAssert align("a", 0) == "a"
+    doAssert align("1232", 6) == "  1232"
+    doAssert align("1232", 6, '#') == "##1232"
+
+    doAssert alignLeft("abc", 4) == "abc "
+    doAssert alignLeft("a", 0) == "a"
+    doAssert alignLeft("1232", 6) == "1232  "
+    doAssert alignLeft("1232", 6, '#') == "1232##"
+
+    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
+
+    let
+      longInp = """ThisIsOneVeryLongStringWhichWeWillSplitIntoEightSeparatePartsNow"""
+      longOutp = "ThisIsOn\neVeryLon\ngStringW\nhichWeWi\nllSplitI\nntoEight\nSeparate\nPartsNow"
+    doAssert wordWrap(longInp, 8, true) == longOutp
+
+    doAssert "$animal eats $food." % ["animal", "The cat", "food", "fish"] ==
+             "The cat eats fish."
+
+    doAssert "-ld a-ldz -ld".replaceWord("-ld") == " a-ldz "
+    doAssert "-lda-ldz -ld abc".replaceWord("-ld") == "-lda-ldz  abc"
+
+    doAssert "-lda-ldz -ld abc".replaceWord("") == "-lda-ldz -ld abc"
+    doAssert "oo".replace("", "abc") == "abcoabcoabc"
+
+    type MyEnum = enum enA, enB, enC, enuD, enE
+    doAssert parseEnum[MyEnum]("enu_D") == enuD
+
+    doAssert parseEnum("invalid enum value", enC) == enC
+
+    doAssert center("foo", 13) == "     foo     "
+    doAssert center("foo", 0) == "foo"
+    doAssert center("foo", 3, fillChar = 'a') == "foo"
+    doAssert center("foo", 10, fillChar = '\t') == "\t\t\tfoo\t\t\t\t"
+
+    doAssert count("foofoofoo", "foofoo") == 1
+    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"
+
+    doAssert "  foo\n  bar".indent(4, "Q") == "QQQQ  foo\nQQQQ  bar"
+
+    doAssert "abba".multiReplace(("a", "b"), ("b", "a")) == "baab"
+    doAssert "Hello World.".multiReplace(("ello", "ELLO"), ("World.", "PEOPLE!")) == "HELLO PEOPLE!"
+    doAssert "aaaa".multiReplace(("a", "aa"), ("aa", "bb")) == "aaaaaaaa"
+
+    doAssert isAlphaAscii('r')
+    doAssert isAlphaAscii('A')
+    doAssert(not isAlphaAscii('$'))
+
+    doAssert isAlphaAscii("Rasp")
+    doAssert isAlphaAscii("Args")
+    doAssert(not isAlphaAscii("$Tomato"))
+
+    doAssert isAlphaNumeric('3')
+    doAssert isAlphaNumeric('R')
+    doAssert(not isAlphaNumeric('!'))
+
+    doAssert isAlphaNumeric("34ABc")
+    doAssert isAlphaNumeric("Rad")
+    doAssert isAlphaNumeric("1234")
+    doAssert(not isAlphaNumeric("@nose"))
+
+    doAssert isDigit('3')
+    doAssert(not isDigit('a'))
+    doAssert(not isDigit('%'))
+
+    doAssert isDigit("12533")
+    doAssert(not isDigit("12.33"))
+    doAssert(not isDigit("A45b"))
+
+    doAssert isSpaceAscii('\t')
+    doAssert isSpaceAscii('\l')
+    doAssert(not isSpaceAscii('A'))
+
+    doAssert isSpaceAscii("\t\l \v\r\f")
+    doAssert isSpaceAscii("       ")
+    doAssert(not isSpaceAscii("ABc   \td"))
+
+    doAssert(isNilOrWhitespace(""))
+    doAssert(isNilOrWhitespace("       "))
+    doAssert(isNilOrWhitespace("\t\l \v\r\f"))
+    doAssert(not isNilOrWhitespace("ABc   \td"))
+
+    doAssert isLowerAscii('a')
+    doAssert isLowerAscii('z')
+    doAssert(not isLowerAscii('A'))
+    doAssert(not isLowerAscii('5'))
+    doAssert(not isLowerAscii('&'))
+
+    doAssert isLowerAscii("abcd")
+    doAssert(not isLowerAscii("abCD"))
+    doAssert(not isLowerAscii("33aa"))
+
+    doAssert isUpperAscii('A')
+    doAssert(not isUpperAscii('b'))
+    doAssert(not isUpperAscii('5'))
+    doAssert(not isUpperAscii('%'))
+
+    doAssert isUpperAscii("ABC")
+    doAssert(not isUpperAscii("AAcc"))
+    doAssert(not isUpperAscii("A#$"))
+
+    doAssert rsplit("foo bar", seps=Whitespace) == @["foo", "bar"]
+    doAssert rsplit(" foo bar", seps=Whitespace, maxsplit=1) == @[" foo", "bar"]
+    doAssert rsplit(" foo bar ", seps=Whitespace, maxsplit=1) == @[" foo bar", ""]
+    doAssert rsplit(":foo:bar", sep=':') == @["", "foo", "bar"]
+    doAssert rsplit(":foo:bar", sep=':', maxsplit=2) == @["", "foo", "bar"]
+    doAssert rsplit(":foo:bar", sep=':', maxsplit=3) == @["", "foo", "bar"]
+    doAssert rsplit("foothebar", sep="the") == @["foo", "bar"]
+
+    doAssert(unescape(r"\x013", "", "") == "\x013")
+
+    doAssert join(["foo", "bar", "baz"]) == "foobarbaz"
+    doAssert join(@["foo", "bar", "baz"], ", ") == "foo, bar, baz"
+    doAssert join([1, 2, 3]) == "123"
+    doAssert join(@[1, 2, 3], ", ") == "1, 2, 3"
+
+    doAssert """~~!!foo
 ~~!!bar
 ~~!!baz""".unindent(2, "~~!!") == "foo\nbar\nbaz"
 
-  doAssert """~~!!foo
+    doAssert """~~!!foo
 ~~!!bar
 ~~!!baz""".unindent(2, "~~!!aa") == "~~!!foo\n~~!!bar\n~~!!baz"
-  doAssert """~~foo
+    doAssert """~~foo
 ~~  bar
 ~~  baz""".unindent(4, "~") == "foo\n  bar\n  baz"
-  doAssert """foo
+    doAssert """foo
 bar
     baz
   """.unindent(4) == "foo\nbar\nbaz\n"
-  doAssert """foo
+    doAssert """foo
     bar
     baz
   """.unindent(2) == "foo\n  bar\n  baz\n"
-  doAssert """foo
+    doAssert """foo
     bar
     baz
   """.unindent(100) == "foo\nbar\nbaz\n"
 
-  doAssert """foo
+    doAssert """foo
     foo
     bar
   """.unindent() == "foo\nfoo\nbar\n"
 
-  let s = " this is an example  "
-  let s2 = ":this;is;an:example;;"
-
-  doAssert s.split() == @["", "this", "is", "an", "example", "", ""]
-  doAssert s2.split(seps={':', ';'}) == @["", "this", "is", "an", "example", "", ""]
-  doAssert s.split(maxsplit=4) == @["", "this", "is", "an", "example  "]
-  doAssert s.split(' ', maxsplit=1) == @["", "this is an example  "]
-  doAssert s.split(" ", maxsplit=4) == @["", "this", "is", "an", "example  "]
-
-  doAssert s.splitWhitespace() == @["this", "is", "an", "example"]
-  doAssert s.splitWhitespace(maxsplit=1) == @["this", "is an example  "]
-  doAssert s.splitWhitespace(maxsplit=2) == @["this", "is", "an example  "]
-  doAssert s.splitWhitespace(maxsplit=3) == @["this", "is", "an", "example  "]
-  doAssert s.splitWhitespace(maxsplit=4) == @["this", "is", "an", "example"]
-
-  block: # formatEng tests
-    doAssert formatEng(0, 2, trim=false) == "0.00"
-    doAssert formatEng(0, 2) == "0"
-    doAssert formatEng(53, 2, trim=false) == "53.00"
-    doAssert formatEng(0.053, 2, trim=false) == "53.00e-3"
-    doAssert formatEng(0.053, 4, trim=false) == "53.0000e-3"
-    doAssert formatEng(0.053, 4, trim=true) == "53e-3"
-    doAssert formatEng(0.053, 0) == "53e-3"
-    doAssert formatEng(52731234) == "52.731234e6"
-    doAssert formatEng(-52731234) == "-52.731234e6"
-    doAssert formatEng(52731234, 1) == "52.7e6"
-    doAssert formatEng(-52731234, 1) == "-52.7e6"
-    doAssert formatEng(52731234, 1, decimalSep=',') == "52,7e6"
-    doAssert formatEng(-52731234, 1, decimalSep=',') == "-52,7e6"
-
-    doAssert formatEng(4100, siPrefix=true, unit="V") == "4.1 kV"
-    doAssert formatEng(4.1, siPrefix=true, unit="V", useUnitSpace=true) == "4.1 V"
-    doAssert formatEng(4.1, siPrefix=true) == "4.1" # Note lack of space
-    doAssert formatEng(4100, siPrefix=true) == "4.1 k"
-    doAssert formatEng(4.1, siPrefix=true, unit="", useUnitSpace=true) == "4.1 " # Includes space
-    doAssert formatEng(4100, siPrefix=true, unit="") == "4.1 k"
-    doAssert formatEng(4100) == "4.1e3"
-    doAssert formatEng(4100, unit="V", useUnitSpace=true) == "4.1e3 V"
-    doAssert formatEng(4100, unit="", useUnitSpace=true) == "4.1e3 "
-    # Don't use SI prefix as number is too big
-    doAssert formatEng(3.1e22, siPrefix=true, unit="a", useUnitSpace=true) == "31e21 a"
-    # Don't use SI prefix as number is too small
-    doAssert formatEng(3.1e-25, siPrefix=true, unit="A", useUnitSpace=true) == "310e-27 A"
-
-  block: # startsWith / endsWith char tests
-    var s = "abcdef"
-    doAssert s.startsWith('a')
-    doAssert s.startsWith('b') == false
-    doAssert s.endsWith('f')
-    doAssert s.endsWith('a') == false
-    doAssert s.endsWith('\0') == false
-
-  #echo("strutils tests passed")
+    let s = " this is an example  "
+    let s2 = ":this;is;an:example;;"
+
+    doAssert s.split() == @["", "this", "is", "an", "example", "", ""]
+    doAssert s2.split(seps={':', ';'}) == @["", "this", "is", "an", "example", "", ""]
+    doAssert s.split(maxsplit=4) == @["", "this", "is", "an", "example  "]
+    doAssert s.split(' ', maxsplit=1) == @["", "this is an example  "]
+    doAssert s.split(" ", maxsplit=4) == @["", "this", "is", "an", "example  "]
+
+    doAssert s.splitWhitespace() == @["this", "is", "an", "example"]
+    doAssert s.splitWhitespace(maxsplit=1) == @["this", "is an example  "]
+    doAssert s.splitWhitespace(maxsplit=2) == @["this", "is", "an example  "]
+    doAssert s.splitWhitespace(maxsplit=3) == @["this", "is", "an", "example  "]
+    doAssert s.splitWhitespace(maxsplit=4) == @["this", "is", "an", "example"]
+
+    block: # startsWith / endsWith char tests
+      var s = "abcdef"
+      doAssert s.startsWith('a')
+      doAssert s.startsWith('b') == false
+      doAssert s.endsWith('f')
+      doAssert s.endsWith('a') == false
+      doAssert s.endsWith('\0') == false
+
+    #echo("strutils tests passed")
+
+  nonStaticTests()
+  staticTests()
+  static: staticTests()
+
diff --git a/lib/pure/subexes.nim b/lib/pure/subexes.nim
index 9d807abd4..8149c72cc 100644
--- a/lib/pure/subexes.nim
+++ b/lib/pure/subexes.nim
@@ -31,8 +31,6 @@ type
   SubexError* = object of ValueError ## exception that is raised for
                                      ## an invalid subex
 
-{.deprecated: [EInvalidSubex: SubexError].}
-
 proc raiseInvalidFormat(msg: string) {.noinline.} =
   raise newException(SubexError, "invalid format string: " & msg)
 
@@ -44,7 +42,6 @@ type
     else:
       f: cstring
     num, i, lineLen: int
-{.deprecated: [TFormatParser: FormatParser].}
 
 template call(x: untyped): untyped =
   p.i = i
diff --git a/lib/pure/terminal.nim b/lib/pure/terminal.nim
index 002181a6f..fcca4d5d7 100644
--- a/lib/pure/terminal.nim
+++ b/lib/pure/terminal.nim
@@ -29,9 +29,7 @@ when not hasThreadSupport:
   var
     colorsFGCache = initTable[Color, string]()
     colorsBGCache = initTable[Color, string]()
-  when not defined(windows):
-    var
-      styleCache = initTable[int, string]()
+    styleCache = initTable[int, string]()
 
 var
   trueColorIsSupported: bool
@@ -41,10 +39,8 @@ var
 const
   fgPrefix = "\x1b[38;2;"
   bgPrefix = "\x1b[48;2;"
-
-when not defined(windows):
-  const
-    stylePrefix = "\e["
+  ansiResetCode* = "\e[0m"
+  stylePrefix = "\e["
 
 when defined(windows):
   import winlean, os
@@ -468,7 +464,7 @@ proc resetAttributes*(f: File) =
     else:
       discard setConsoleTextAttribute(hStdout, oldStdoutAttr)
   else:
-    f.write("\e[0m")
+    f.write(ansiResetCode)
 
 type
   Style* = enum         ## different styles for text output
@@ -487,15 +483,22 @@ when not defined(windows):
     gFG {.threadvar.}: int
     gBG {.threadvar.}: int
 
-  proc getStyleStr(style: int): string =
-    when hasThreadSupport:
-      result = fmt"{stylePrefix}{style}m"
+proc ansiStyleCode*(style: int): string =
+  when hasThreadSupport:
+    result = fmt"{stylePrefix}{style}m"
+  else:
+    if styleCache.hasKey(style):
+      result = styleCache[style]
     else:
-      if styleCache.hasKey(style):
-        result = styleCache[style]
-      else:
-        result = fmt"{stylePrefix}{style}m"
-        styleCache[style] = result
+      result = fmt"{stylePrefix}{style}m"
+      styleCache[style] = result
+
+template ansiStyleCode*(style: Style): string =
+  ansiStyleCode(style.int)
+
+# The styleCache can be skipped when `style` is known at compile-time
+template ansiStyleCode*(style: static[Style]): string =
+  (static(stylePrefix & $style.int & "m"))
 
 proc setStyle*(f: File, style: set[Style]) =
   ## Sets the terminal style.
@@ -510,7 +513,7 @@ proc setStyle*(f: File, style: set[Style]) =
     discard setConsoleTextAttribute(h, old or a)
   else:
     for s in items(style):
-      f.write(getStyleStr(ord(s)))
+      f.write(ansiStyleCode(s))
 
 proc writeStyled*(txt: string, style: set[Style] = {styleBright}) =
   ## Writes the text `txt` in a given `style` to stdout.
@@ -524,9 +527,9 @@ proc writeStyled*(txt: string, style: set[Style] = {styleBright}) =
     stdout.write(txt)
     stdout.resetAttributes()
     if gFG != 0:
-      stdout.write(getStyleStr(gFG))
+      stdout.write(ansiStyleCode(gFG))
     if gBG != 0:
-      stdout.write(getStyleStr(gBG))
+      stdout.write(ansiStyleCode(gBG))
 
 type
   ForegroundColor* = enum  ## terminal's foreground colors
@@ -572,7 +575,7 @@ proc setForegroundColor*(f: File, fg: ForegroundColor, bright=false) =
   else:
     gFG = ord(fg)
     if bright: inc(gFG, 60)
-    f.write(getStyleStr(gFG))
+    f.write(ansiStyleCode(gFG))
 
 proc setBackgroundColor*(f: File, bg: BackgroundColor, bright=false) =
   ## Sets the terminal's background color.
@@ -594,10 +597,18 @@ proc setBackgroundColor*(f: File, bg: BackgroundColor, bright=false) =
   else:
     gBG = ord(bg)
     if bright: inc(gBG, 60)
-    f.write(getStyleStr(gBG))
+    f.write(ansiStyleCode(gBG))
+
+proc ansiForegroundColorCode*(fg: ForegroundColor, bright=false): string =
+  var style = ord(fg)
+  if bright: inc(style, 60)
+  return ansiStyleCode(style)
 
+template ansiForegroundColorCode*(fg: static[ForegroundColor],
+                                  bright: static[bool] = false): string =
+  ansiStyleCode(fg.int + bright.int * 60)
 
-proc getFGColorStr(color: Color): string =
+proc ansiForegroundColorCode*(color: Color): string =
   when hasThreadSupport:
     let rgb = extractRGB(color)
     result = fmt"{fgPrefix}{rgb.r};{rgb.g};{rgb.b}m"
@@ -609,7 +620,11 @@ proc getFGColorStr(color: Color): string =
       result = fmt"{fgPrefix}{rgb.r};{rgb.g};{rgb.b}m"
       colorsFGCache[color] = result
 
-proc getBGColorStr(color: Color): string =
+template ansiForegroundColorCode*(color: static[Color]): string =
+  const rgb = extractRGB(color)
+  (static(fmt"{fgPrefix}{rgb.r};{rgb.g};{rgb.b}m"))
+
+proc ansiBackgroundColorCode*(color: Color): string =
   when hasThreadSupport:
     let rgb = extractRGB(color)
     result = fmt"{bgPrefix}{rgb.r};{rgb.g};{rgb.b}m"
@@ -621,15 +636,19 @@ proc getBGColorStr(color: Color): string =
       result = fmt"{bgPrefix}{rgb.r};{rgb.g};{rgb.b}m"
       colorsFGCache[color] = result
 
+template ansiBackgroundColorCode*(color: static[Color]): string =
+  const rgb = extractRGB(color)
+  (static(fmt"{bgPrefix}{rgb.r};{rgb.g};{rgb.b}m"))
+
 proc setForegroundColor*(f: File, color: Color) =
   ## Sets the terminal's foreground true color.
   if trueColorIsEnabled:
-    f.write(getFGColorStr(color))
+    f.write(ansiForegroundColorCode(color))
 
 proc setBackgroundColor*(f: File, color: Color) =
   ## Sets the terminal's background true color.
   if trueColorIsEnabled:
-    f.write(getBGColorStr(color))
+    f.write(ansiBackgroundColorCode(color))
 
 proc setTrueColor(f: File, color: Color) =
   if fgSetColor:
@@ -759,6 +778,10 @@ when defined(windows):
           x = runeLenAt(password.string, i)
           inc i, x
         password.string.setLen(max(password.len - x, 0))
+      of chr(0x0):
+        # modifier key - ignore - for details see 
+        # https://github.com/nim-lang/Nim/issues/7764
+        continue
       else:
         password.string.add(toUTF8(c.Rune))
     stdout.write "\n"
diff --git a/lib/pure/times.nim b/lib/pure/times.nim
index bc8a50fd7..f6567cf58 100644
--- a/lib/pure/times.nim
+++ b/lib/pure/times.nim
@@ -1173,12 +1173,16 @@ proc formatToken(dt: DateTime, token: string, buf: var string) =
   of "dddd":
     buf.add($dt.weekday)
   of "h":
-    buf.add($(if dt.hour > 12: dt.hour - 12 else: dt.hour))
+    if dt.hour == 0: buf.add("12")
+    else: buf.add($(if dt.hour > 12: dt.hour - 12 else: dt.hour))
   of "hh":
-    let amerHour = if dt.hour > 12: dt.hour - 12 else: dt.hour
-    if amerHour < 10:
-      buf.add('0')
-    buf.add($amerHour)
+    if dt.hour == 0:
+      buf.add("12")
+    else:
+      let amerHour = if dt.hour > 12: dt.hour - 12 else: dt.hour
+      if amerHour < 10:
+        buf.add('0')
+      buf.add($amerHour)
   of "H":
     buf.add($dt.hour)
   of "HH":
@@ -1503,11 +1507,15 @@ proc parseToken(dt: var DateTime; token, value: string; j: var int) =
     dt.second = value[j..j+1].parseInt()
     j += 2
   of "t":
-    if value[j] == 'P' and dt.hour > 0 and dt.hour < 12:
+    if value[j] == 'A' and dt.hour == 12:
+      dt.hour = 0
+    elif value[j] == 'P' and dt.hour > 0 and dt.hour < 12:
       dt.hour += 12
     j += 1
   of "tt":
-    if value[j..j+1] == "PM" and dt.hour > 0 and dt.hour < 12:
+    if value[j..j+1] == "AM" and dt.hour == 12:
+      dt.hour = 0
+    elif value[j..j+1] == "PM" and dt.hour > 0 and dt.hour < 12:
       dt.hour += 12
     j += 2
   of "yy":
diff --git a/lib/pure/uri.nim b/lib/pure/uri.nim
index 9bf25b86b..dd8040928 100644
--- a/lib/pure/uri.nim
+++ b/lib/pure/uri.nim
@@ -18,14 +18,12 @@ type
     hostname*, port*, path*, query*, anchor*: string
     opaque*: bool
 
-{.deprecated: [TUrl: Url, TUri: Uri].}
-
 {.push warning[deprecated]: off.}
-proc `$`*(url: Url): string {.deprecated.} =
+proc `$`*(url: Url): string {.deprecated: "use Uri instead".} =
   ## **Deprecated since 0.9.6**: Use ``Uri`` instead.
   return string(url)
 
-proc `/`*(a, b: Url): Url {.deprecated.} =
+proc `/`*(a, b: Url): Url {.deprecated: "use Uri instead".} =
   ## Joins two URLs together, separating them with / if needed.
   ##
   ## **Deprecated since 0.9.6**: Use ``Uri`` instead.
@@ -40,32 +38,43 @@ proc `/`*(a, b: Url): Url {.deprecated.} =
     urlS.add(bs)
   result = Url(urlS)
 
-proc add*(url: var Url, a: Url) {.deprecated.} =
+proc add*(url: var Url, a: Url) {.deprecated: "use Uri instead".} =
   ## Appends url to url.
   ##
   ## **Deprecated since 0.9.6**: Use ``Uri`` instead.
   url = url / a
 {.pop.}
 
-proc encodeUrl*(s: string): string =
-  ## Encodes a value to be HTTP safe: This means that characters in the set
-  ## ``{'A'..'Z', 'a'..'z', '0'..'9', '_'}`` are carried over to the result,
-  ## a space is converted to ``'+'`` and every other character is encoded as
-  ## ``'%xx'`` where ``xx`` denotes its hexadecimal value.
+proc encodeUrl*(s: string, usePlus=true): string =
+  ## Encodes a URL according to RFC3986.
+  ##
+  ## This means that characters in the set
+  ## ``{'a'..'z', 'A'..'Z', '0'..'9', '-', '.', '_', '~'}`` are
+  ## carried over to the result.
+  ## All other characters are encoded as ``''%xx'`` where ``xx``
+  ## denotes its hexadecimal value.
+  ##
+  ## As a special rule, when the value of ``usePlus`` is true,
+  ## spaces are encoded as ``'+'`` instead of ``'%20'``.
   result = newStringOfCap(s.len + s.len shr 2) # assume 12% non-alnum-chars
-  for i in 0..s.len-1:
-    case s[i]
-    of 'a'..'z', 'A'..'Z', '0'..'9', '_': add(result, s[i])
-    of ' ': add(result, '+')
+  let fromSpace = if usePlus: "+" else: "%20"
+  for c in s:
+    case c
+    of 'a'..'z', 'A'..'Z', '0'..'9', '-', '.', '_', '~': add(result, c)
+    of ' ': add(result, fromSpace)
     else:
       add(result, '%')
-      add(result, toHex(ord(s[i]), 2))
+      add(result, toHex(ord(c), 2))
 
-proc decodeUrl*(s: string): string =
-  ## Decodes a value from its HTTP representation: This means that a ``'+'``
-  ## is converted to a space, ``'%xx'`` (where ``xx`` denotes a hexadecimal
-  ## value) is converted to the character with ordinal number ``xx``, and
+proc decodeUrl*(s: string, decodePlus=true): string =
+  ## Decodes a URL according to RFC3986.
+  ##
+  ## This means that any ``'%xx'`` (where ``xx`` denotes a hexadecimal
+  ## value) are converted to the character with ordinal number ``xx``,
   ## and every other character is carried over.
+  ##
+  ## As a special rule, when the value of ``decodePlus`` is true, ``'+'``
+  ## characters are converted to a space.
   proc handleHexChar(c: char, x: var int) {.inline.} =
     case c
     of '0'..'9': x = (x shl 4) or (ord(c) - ord('0'))
@@ -84,7 +93,11 @@ proc decodeUrl*(s: string): string =
       handleHexChar(s[i+2], x)
       inc(i, 2)
       result[j] = chr(x)
-    of '+': result[j] = ' '
+    of '+':
+      if decodePlus:
+        result[j] = ' '
+      else:
+        result[j] = s[i]
     else: result[j] = s[i]
     inc(i)
     inc(j)
@@ -370,6 +383,9 @@ when isMainModule:
     const test1 = "abc\L+def xyz"
     doAssert encodeUrl(test1) == "abc%0A%2Bdef+xyz"
     doAssert decodeUrl(encodeUrl(test1)) == test1
+    doAssert encodeUrl(test1, false) == "abc%0A%2Bdef%20xyz"
+    doAssert decodeUrl(encodeUrl(test1, false), false) == test1
+    doAssert decodeUrl(encodeUrl(test1)) == test1
 
   block:
     let str = "http://localhost"
diff --git a/lib/pure/xmldom.nim b/lib/pure/xmldom.nim
index c38d36026..8cd47aa39 100644
--- a/lib/pure/xmldom.nim
+++ b/lib/pure/xmldom.nim
@@ -1069,17 +1069,15 @@ proc splitData*(textNode: PText, offset: int): PText =
     var newNode: PText = textNode.fOwnerDocument.createTextNode(right)
     return newNode
 
-
 # ProcessingInstruction
 proc target*(pi: PProcessingInstruction): string =
   ## Returns the Processing Instructions target
 
   return pi.fTarget
 
-
-# --Other stuff--
-# Writer
-proc addEscaped(s: string): string =
+proc escapeXml*(s: string; result: var string) =
+  ## Prepares a string for insertion into a XML document
+  ## by escaping the XML special characters.
   result = ""
   for c in items(s):
     case c
@@ -1089,11 +1087,20 @@ proc addEscaped(s: string): string =
     of '"': result.add("&quot;")
     else: result.add(c)
 
+proc escapeXml*(s: string): string =
+  ## Prepares a string for insertion into a XML document
+  ## by escaping the XML special characters.
+  result = newStringOfCap(s.len + s.len shr 4)
+  escapeXml(s, result)
+
+# --Other stuff--
+# Writer
+
 proc nodeToXml(n: PNode, indent: int = 0): string =
   result = spaces(indent) & "<" & n.nodeName
   if not isNil(n.attributes):
     for i in items(n.attributes):
-      result.add(" " & i.name & "=\"" & addEscaped(i.value) & "\"")
+      result.add(" " & i.name & "=\"" & escapeXml(i.value) & "\"")
 
   if isNil(n.childNodes) or n.childNodes.len() == 0:
     result.add("/>") # No idea why this doesn't need a \n :O
@@ -1106,7 +1113,7 @@ proc nodeToXml(n: PNode, indent: int = 0): string =
         result.add(nodeToXml(i, indent + 2))
       of TextNode:
         result.add(spaces(indent * 2))
-        result.add(addEscaped(i.nodeValue))
+        result.add(escapeXml(i.nodeValue))
       of CDataSectionNode:
         result.add(spaces(indent * 2))
         result.add("<![CDATA[" & i.nodeValue & "]]>")
diff --git a/lib/pure/xmlparser.nim b/lib/pure/xmlparser.nim
index 9159b4bfc..597b80eb5 100644
--- a/lib/pure/xmlparser.nim
+++ b/lib/pure/xmlparser.nim
@@ -16,8 +16,6 @@ type
                                    ## for invalid XML.
     errors*: seq[string]           ## All detected parsing errors.
 
-{.deprecated: [EInvalidXml: XmlError].}
-
 proc raiseInvalidXml(errors: seq[string]) =
   var e: ref XmlError
   new(e)
diff --git a/lib/pure/xmltree.nim b/lib/pure/xmltree.nim
index a6f62abce..8f85cb5c9 100644
--- a/lib/pure/xmltree.nim
+++ b/lib/pure/xmltree.nim
@@ -33,9 +33,6 @@ type
       fAttr: XmlAttributes
     fClientData: int              ## for other clients
 
-{.deprecated: [PXmlNode: XmlNode, TXmlNodeKind: XmlNodeKind, PXmlAttributes:
-    XmlAttributes, TXmlNode: XmlNodeObj].}
-
 proc newXmlNode(kind: XmlNodeKind): XmlNode =
   ## creates a new ``XmlNode``.
   new(result)
@@ -155,11 +152,6 @@ proc `[]`* (n: var XmlNode, i: int): var XmlNode {.inline.} =
   assert n.k == xnElement
   result = n.s[i]
 
-proc mget*(n: var XmlNode, i: int): var XmlNode {.inline, deprecated.} =
-  ## returns the `i`'th child of `n` so that it can be modified. Use ```[]```
-  ## instead.
-  n[i]
-
 iterator items*(n: XmlNode): XmlNode {.inline.} =
   ## iterates over any child of `n`.
   assert n.k == xnElement
@@ -319,8 +311,8 @@ proc xmlConstructor(a: NimNode): NimNode {.compileTime.} =
   if a.kind == nnkCall:
     result = newCall("newXmlTree", toStrLit(a[0]))
     var attrs = newNimNode(nnkBracket, a)
-    var newStringTabCall = newCall("newStringTable", attrs,
-                                   newIdentNode("modeCaseSensitive"))
+    var newStringTabCall = newCall(bindSym"newStringTable", attrs,
+                                    bindSym"modeCaseSensitive")
     var elements = newNimNode(nnkBracket, a)
     for i in 1..a.len-1:
       if a[i].kind == nnkExprEqExpr:
diff --git a/lib/system.nim b/lib/system.nim
index 0c8659fda..5781aff27 100644
--- a/lib/system.nim
+++ b/lib/system.nim
@@ -4172,8 +4172,9 @@ template doAssertRaises*(exception, code: untyped): typed =
   if wrong:
     raiseAssert(astToStr(exception) & " wasn't raised by:\n" & astToStr(code))
 
-when defined(cpp) and appType != "lib" and not defined(js) and
-    not defined(nimscript) and hostOS != "standalone":
+when defined(cpp) and appType != "lib" and
+    not defined(js) and not defined(nimscript) and
+    hostOS != "standalone" and not defined(noCppExceptions):
   proc setTerminate(handler: proc() {.noconv.})
     {.importc: "std::set_terminate", header: "<exception>".}
   setTerminate proc() {.noconv.} =
diff --git a/lib/system/assign.nim b/lib/system/assign.nim
index ff1ef31d2..16b56aba7 100644
--- a/lib/system/assign.nim
+++ b/lib/system/assign.nim
@@ -74,7 +74,7 @@ proc genericAssignAux(dest, src: pointer, mt: PNimType, shallow: bool) =
       var dst = cast[ByteAddress](cast[PPointer](dest)[])
       for i in 0..seq.len-1:
         genericAssignAux(
-          cast[pointer](dst +% i*% mt.base.size +% GenericSeqSize),
+          cast[pointer](dst +% i *% mt.base.size +% GenericSeqSize),
           cast[pointer](cast[ByteAddress](s2) +% i *% mt.base.size +%
                       GenericSeqSize),
           mt.base, shallow)
@@ -100,8 +100,8 @@ proc genericAssignAux(dest, src: pointer, mt: PNimType, shallow: bool) =
     genericAssignAux(dest, src, mt.node, shallow)
   of tyArray, tyArrayConstr:
     for i in 0..(mt.size div mt.base.size)-1:
-      genericAssignAux(cast[pointer](d +% i*% mt.base.size),
-                       cast[pointer](s +% i*% mt.base.size), mt.base, shallow)
+      genericAssignAux(cast[pointer](d +% i *% mt.base.size),
+                       cast[pointer](s +% i *% mt.base.size), mt.base, shallow)
   of tyRef:
     unsureAsgnRef(cast[PPointer](dest), cast[PPointer](s)[])
   of tyOptAsRef:
@@ -166,8 +166,8 @@ proc genericAssignOpenArray(dest, src: pointer, len: int,
     d = cast[ByteAddress](dest)
     s = cast[ByteAddress](src)
   for i in 0..len-1:
-    genericAssign(cast[pointer](d +% i*% mt.base.size),
-                  cast[pointer](s +% i*% mt.base.size), mt.base)
+    genericAssign(cast[pointer](d +% i *% mt.base.size),
+                  cast[pointer](s +% i *% mt.base.size), mt.base)
 
 proc objectInit(dest: pointer, typ: PNimType) {.compilerProc, benign.}
 proc objectInitAux(dest: pointer, n: ptr TNimNode) {.benign.} =
@@ -235,7 +235,7 @@ proc genericReset(dest: pointer, mt: PNimType) =
     pint[] = nil
   of tyArray, tyArrayConstr:
     for i in 0..(mt.size div mt.base.size)-1:
-      genericReset(cast[pointer](d +% i*% mt.base.size), mt.base)
+      genericReset(cast[pointer](d +% i *% mt.base.size), mt.base)
   else:
     zeroMem(dest, mt.size) # set raw bits to zero
 
diff --git a/lib/system/deepcopy.nim b/lib/system/deepcopy.nim
index 51e138e5e..750da00cf 100644
--- a/lib/system/deepcopy.nim
+++ b/lib/system/deepcopy.nim
@@ -105,7 +105,7 @@ proc genericDeepCopyAux(dest, src: pointer, mt: PNimType; tab: var PtrTable) =
     var dst = cast[ByteAddress](cast[PPointer](dest)[])
     for i in 0..seq.len-1:
       genericDeepCopyAux(
-        cast[pointer](dst +% i*% mt.base.size +% GenericSeqSize),
+        cast[pointer](dst +% i *% mt.base.size +% GenericSeqSize),
         cast[pointer](cast[ByteAddress](s2) +% i *% mt.base.size +%
                      GenericSeqSize),
         mt.base, tab)
@@ -122,8 +122,8 @@ proc genericDeepCopyAux(dest, src: pointer, mt: PNimType; tab: var PtrTable) =
     genericDeepCopyAux(dest, src, mt.node, tab)
   of tyArray, tyArrayConstr:
     for i in 0..(mt.size div mt.base.size)-1:
-      genericDeepCopyAux(cast[pointer](d +% i*% mt.base.size),
-                         cast[pointer](s +% i*% mt.base.size), mt.base, tab)
+      genericDeepCopyAux(cast[pointer](d +% i *% mt.base.size),
+                         cast[pointer](s +% i *% mt.base.size), mt.base, tab)
   of tyRef, tyOptAsRef:
     let s2 = cast[PPointer](src)[]
     if s2 == nil:
@@ -183,5 +183,5 @@ proc genericDeepCopyOpenArray(dest, src: pointer, len: int,
     d = cast[ByteAddress](dest)
     s = cast[ByteAddress](src)
   for i in 0..len-1:
-    genericDeepCopy(cast[pointer](d +% i*% mt.base.size),
-                    cast[pointer](s +% i*% mt.base.size), mt.base)
+    genericDeepCopy(cast[pointer](d +% i *% mt.base.size),
+                    cast[pointer](s +% i *% mt.base.size), mt.base)
diff --git a/lib/system/gc.nim b/lib/system/gc.nim
index 66d49ce1b..425963f3f 100644
--- a/lib/system/gc.nim
+++ b/lib/system/gc.nim
@@ -535,7 +535,7 @@ proc growObj(old: pointer, newsize: int, gch: var GcHeap): pointer =
 
   var oldsize = cast[PGenericSeq](old).len*elemSize + GenericSeqSize
   copyMem(res, ol, oldsize + sizeof(Cell))
-  zeroMem(cast[pointer](cast[ByteAddress](res)+% oldsize +% sizeof(Cell)),
+  zeroMem(cast[pointer](cast[ByteAddress](res) +% oldsize +% sizeof(Cell)),
           newsize-oldsize)
   sysAssert((cast[ByteAddress](res) and (MemAlign-1)) == 0, "growObj: 3")
   # This can be wrong for intermediate temps that are nevertheless on the
diff --git a/lib/system/osalloc.nim b/lib/system/osalloc.nim
index 1ad4cf695..9609b6d39 100644
--- a/lib/system/osalloc.nim
+++ b/lib/system/osalloc.nim
@@ -58,7 +58,7 @@ when defined(emscripten):
 
     # Convert pointer to PageSize correct one.
     var new_pos = cast[ByteAddress](pos) +% (PageSize - (pos %% PageSize))
-    if (new_pos-pos)< sizeof(EmscriptenMMapBlock):
+    if (new_pos-pos) < sizeof(EmscriptenMMapBlock):
       new_pos = new_pos +% PageSize
     result = cast[pointer](new_pos)
 
diff --git a/lib/system/sysstr.nim b/lib/system/sysstr.nim
index bba59e930..c5c8a9cac 100644
--- a/lib/system/sysstr.nim
+++ b/lib/system/sysstr.nim
@@ -76,6 +76,7 @@ proc rawNewStringNoInit(space: int): NimString {.compilerProc.} =
   if s < 7: s = 7
   result = allocStrNoInit(sizeof(TGenericSeq) + s + 1)
   result.reserved = s
+  result.len = 0
   when defined(gogc):
     result.elemSize = 1
 
@@ -84,6 +85,7 @@ proc rawNewString(space: int): NimString {.compilerProc.} =
   if s < 7: s = 7
   result = allocStr(sizeof(TGenericSeq) + s + 1)
   result.reserved = s
+  result.len = 0
   when defined(gogc):
     result.elemSize = 1
 
diff --git a/lib/wrappers/openssl.nim b/lib/wrappers/openssl.nim
index 86ae85369..6609dc245 100644
--- a/lib/wrappers/openssl.nim
+++ b/lib/wrappers/openssl.nim
@@ -38,7 +38,7 @@ when useWinVersion:
 
   from winlean import SocketHandle
 else:
-  const versions = "(.1.1|.38|.39|.41|.43|.44|.10|.1.0.2|.1.0.1|.1.0.0|.0.9.9|.0.9.8|)"
+  const versions = "(.1.1|.38|.39|.41|.43|.44|.45|.10|.1.0.2|.1.0.1|.1.0.0|.0.9.9|.0.9.8|)"
 
   when defined(macosx):
     const
diff --git a/tests/async/tasyncawait.nim b/tests/async/tasyncawait.nim
index 9fe9507ad..74933f063 100644
--- a/tests/async/tasyncawait.nim
+++ b/tests/async/tasyncawait.nim
@@ -12,11 +12,11 @@ const
 
 var clientCount = 0
 
-proc sendMessages(client: TAsyncFD) {.async.} =
+proc sendMessages(client: AsyncFD) {.async.} =
   for i in 0 .. <messagesToSend:
     await send(client, "Message " & $i & "\c\L")
 
-proc launchSwarm(port: TPort) {.async.} =
+proc launchSwarm(port: Port) {.async.} =
   for i in 0 .. <swarmSize:
     var sock = newAsyncNativeSocket()
 
@@ -24,7 +24,7 @@ proc launchSwarm(port: TPort) {.async.} =
     await sendMessages(sock)
     closeSocket(sock)
 
-proc readMessages(client: TAsyncFD) {.async.} =
+proc readMessages(client: AsyncFD) {.async.} =
   while true:
     var line = await recvLine(client)
     if line == "":
@@ -37,7 +37,7 @@ proc readMessages(client: TAsyncFD) {.async.} =
       else:
         doAssert false
 
-proc createServer(port: TPort) {.async.} =
+proc createServer(port: Port) {.async.} =
   var server = newAsyncNativeSocket()
   block:
     var name: Sockaddr_in
@@ -55,8 +55,8 @@ proc createServer(port: TPort) {.async.} =
   while true:
     asyncCheck readMessages(await accept(server))
 
-asyncCheck createServer(TPort(10335))
-asyncCheck launchSwarm(TPort(10335))
+asyncCheck createServer(Port(10335))
+asyncCheck launchSwarm(Port(10335))
 while true:
   poll()
   if clientCount == swarmSize: break
diff --git a/tests/collections/thashes.nim b/tests/collections/thashes.nim
index 76b99313c..5cc3cc8bb 100644
--- a/tests/collections/thashes.nim
+++ b/tests/collections/thashes.nim
@@ -3,7 +3,7 @@ discard """
 """
 
 import tables
-from hashes import THash
+from hashes import Hash
 
 # Test with int
 block:
@@ -66,7 +66,7 @@ block:
 # The same test with a custom hash(s: string) does
 # work though.
 block:
-  proc hash(x: int): THash {.inline.} =
+  proc hash(x: int): Hash {.inline.} =
     echo "overloaded hash"
     result = x
   var t = initTable[int, int]()
diff --git a/tests/collections/tsets.nim b/tests/collections/tsets.nim
index 6139560bd..61e14260a 100644
--- a/tests/collections/tsets.nim
+++ b/tests/collections/tsets.nim
@@ -1,4 +1,6 @@
 import sets
+import hashes
+import algorithm
 
 block setEquality:
   var
@@ -35,7 +37,7 @@ block setWithSequences:
   doAssert( not s.contains(@[4, 5, 6]) )
 
 block setClearWorked:
-  var s = initSet[char]() 
+  var s = initSet[char]()
 
   for c in "this is a test":
     s.incl(c)
@@ -68,12 +70,54 @@ block orderedSetClearWorked:
   for c in "eat at joes":
     s.incl(c)
 
-  r = "" 
+  r = ""
   for c in items(s):
     add(r, c)
 
   doAssert r == "zeat jos"
 
+block hashForHashedSet:
+  let
+    seq1 = "This is the test."
+    seq2 = "the test is This."
+    s1 = seq1.toSet()
+    s2 = seq2.toSet()
+  var hashSeq: seq[Hash] = @[]
+  doAssert s1 == s2
+  doAssert hash(s1) == hash(s2)
+
+block hashForOrderdSet:
+  let
+    str = "This is the test."
+    rstr = str.reversed
 
-
-
+  var
+    s1 = initOrderedSet[char]()
+    s2 = initOrderedSet[char]()
+    r = initOrderedSet[char]()
+    expected: Hash
+    added: seq[char] = @[]
+    reversed: Hash
+    radded: seq[char] = @[]
+
+  expected = 0
+  for c in str:
+    if (not (c in added)):
+      expected = expected !& hash(c)
+      added.add(c)
+    s1.incl(c)
+    s2.incl(c)
+  expected = !$expected
+  doAssert hash(s1) == expected
+  doAssert hash(s1) == hash(s2)
+  doAssert hash(s1) != hash(r)
+
+  reversed = 0
+  for c in rstr:
+    if (not (c in radded)):
+      reversed = reversed !& hash(c)
+      radded.add(c)
+    r.incl(c)
+  reversed = !$reversed
+  doAssert hash(r) == reversed
+  doAssert hash(s1) != reversed
diff --git a/tests/exprs/tstmtexprs.nim b/tests/exprs/tstmtexprs.nim
index 2a0ec2821..577f314ec 100644
--- a/tests/exprs/tstmtexprs.nim
+++ b/tests/exprs/tstmtexprs.nim
@@ -81,7 +81,7 @@ semiProblem()
 # bug #844
 
 import json
-proc parseResponse(): PJsonNode =
+proc parseResponse(): JsonNode =
   result = % { "key1": % { "key2": % "value" } }
   for key, val in result["key1"]:
     var excMsg = key & "("
diff --git a/tests/generics/module_with_generics.nim b/tests/generics/module_with_generics.nim
new file mode 100644
index 000000000..e801a4790
--- /dev/null
+++ b/tests/generics/module_with_generics.nim
@@ -0,0 +1,14 @@
+type
+  Base[T] = ref object {.inheritable.}
+    value*: T
+
+  Derived[T] = ref object of Base[T]
+    derivedValue*: T
+
+proc makeDerived*[T](v: T): Derived[T] =
+  new result
+  result.value = v
+
+proc setBaseValue*[T](a: Base[T], value: T) =
+  a.value = value
+
diff --git a/tests/generics/t5602_inheritence.nim b/tests/generics/t5602_inheritence.nim
index 6d48c796e..ee5ba89d5 100644
--- a/tests/generics/t5602_inheritence.nim
+++ b/tests/generics/t5602_inheritence.nim
@@ -1,10 +1,11 @@
 discard """
   output: "seq[float]\n0"
+  targets: "c cpp"
 """
 
 # https://github.com/nim-lang/Nim/issues/5602
 
-import typetraits
+import typetraits, module_with_generics
 
 type
   Foo[T] = object of RootObj
@@ -16,3 +17,8 @@ proc p[T](f: Foo[T]): T =
 var s: Bar[float]
 echo p(s).len # the bug was: p(s) should return seq[float], but returns float instead
 
+# Test overloading and code generation when
+# downcasting is required for generic types:
+var d = makeDerived(10)
+setBaseValue(d, 20)
+
diff --git a/tests/macros/tstructuredlogging.nim b/tests/macros/tstructuredlogging.nim
new file mode 100644
index 000000000..05bb52a40
--- /dev/null
+++ b/tests/macros/tstructuredlogging.nim
@@ -0,0 +1,154 @@
+discard """
+output: '''
+main started: a=10, b=inner-b, c=10, d=some-d, x=16, z=20
+exiting: a=12, b=overriden-b, c=100, msg=bye bye, x=16
+'''
+"""
+
+import macros, tables
+
+template scopeHolder =
+  0 # scope revision number
+
+type
+  BindingsSet = Table[string, NimNode]
+
+proc actualBody(n: NimNode): NimNode =
+  # skip over the double StmtList node introduced in `mergeScopes`
+  result = n.body
+  if result.kind == nnkStmtList and result[0].kind == nnkStmtList:
+    result = result[0]
+
+iterator bindings(n: NimNode, skip = 0): (string, NimNode) =
+  for i in skip ..< n.len:
+    let child = n[i]
+    if child.kind in {nnkAsgn, nnkExprEqExpr}:
+      let name = $child[0]
+      let value = child[1]
+      yield (name, value)
+
+proc scopeRevision(scopeHolder: NimNode): int =
+  # get the revision number from a scopeHolder sym
+  assert scopeHolder.kind == nnkSym
+  var revisionNode = scopeHolder.getImpl.actualBody[0]
+  result = int(revisionNode.intVal)
+
+proc lastScopeHolder(scopeHolders: NimNode): NimNode =
+  # get the most recent scopeHolder from a symChoice node
+  if scopeHolders.kind in {nnkClosedSymChoice, nnkOpenSymChoice}:
+    var bestScopeRev = 0
+    assert scopeHolders.len > 0
+    for scope in scopeHolders:
+      let rev = scope.scopeRevision
+      if result == nil or rev > bestScopeRev:
+        result = scope
+        bestScopeRev = rev
+  else:
+    result = scopeHolders
+
+  assert result.kind == nnkSym
+
+macro mergeScopes(scopeHolders: typed, newBindings: untyped): untyped =
+  var
+    bestScope = scopeHolders.lastScopeHolder
+    bestScopeRev = bestScope.scopeRevision
+
+  var finalBindings = initTable[string, NimNode]()
+  for k, v in bindings(bestScope.getImpl.actualBody, skip = 1):
+    finalBindings[k] = v
+
+  for k, v in bindings(newBindings):
+    finalBindings[k] = v
+
+  var newScopeDefinition = newStmtList(newLit(bestScopeRev + 1))
+
+  for k, v in finalBindings:
+    newScopeDefinition.add newAssignment(newIdentNode(k), v)
+
+  result = quote:
+    template scopeHolder = `newScopeDefinition`
+
+template scope(newBindings: untyped) {.dirty.} =
+  mergeScopes(bindSym"scopeHolder", newBindings)
+
+type
+  TextLogRecord = object
+    line: string
+
+  StdoutLogRecord = object
+
+template setProperty(r: var TextLogRecord, key: string, val: string, isFirst: bool) =
+  if not first: r.line.add ", "
+  r.line.add key
+  r.line.add "="
+  r.line.add val
+
+template setEventName(r: var StdoutLogRecord, name: string) =
+  stdout.write(name & ": ")
+
+template setProperty(r: var StdoutLogRecord, key: string, val: auto, isFirst: bool) =
+  when not isFirst: stdout.write ", "
+  stdout.write key
+  stdout.write "="
+  stdout.write $val
+
+template flushRecord(r: var StdoutLogRecord) =
+  stdout.write "\n"
+  stdout.flushFile
+
+macro logImpl(scopeHolders: typed,
+              logStmtProps: varargs[untyped]): untyped =
+  let lexicalScope = scopeHolders.lastScopeHolder.getImpl.actualBody
+  var finalBindings = initOrderedTable[string, NimNode]()
+
+  for k, v in bindings(lexicalScope, skip = 1):
+    finalBindings[k] = v
+
+  for k, v in bindings(logStmtProps, skip = 1):
+    finalBindings[k] = v
+
+  finalBindings.sort(system.cmp)
+
+  let eventName = logStmtProps[0]
+  assert eventName.kind in {nnkStrLit}
+  let record = genSym(nskVar, "record")
+
+  result = quote:
+    var `record`: StdoutLogRecord
+    setEventName(`record`, `eventName`)
+
+  var isFirst = true
+  for k, v in finalBindings:
+    result.add newCall(newIdentNode"setProperty",
+                       record, newLit(k), v, newLit(isFirst))
+    isFirst = false
+
+  result.add newCall(newIdentNode"flushRecord", record)
+
+template log(props: varargs[untyped]) {.dirty.} =
+  logImpl(bindSym"scopeHolder", props)
+
+scope:
+  a = 12
+  b = "original-b"
+
+scope:
+  x = 16
+  b = "overriden-b"
+
+scope:
+  c = 100
+
+proc main =
+  scope:
+    c = 10
+
+  scope:
+    z = 20
+
+  log("main started", a = 10, b = "inner-b", d = "some-d")
+
+main()
+
+log("exiting", msg = "bye bye")
+
diff --git a/tests/macros/ttemplatesymbols.nim b/tests/macros/ttemplatesymbols.nim
new file mode 100644
index 000000000..8d9c9ec02
--- /dev/null
+++ b/tests/macros/ttemplatesymbols.nim
@@ -0,0 +1,173 @@
+import
+  macros, algorithm, strutils
+
+proc normalProc(x: int) =
+  echo x
+
+template templateWithtouParams =
+  echo 10
+
+proc overloadedProc(x: int) =
+  echo x
+
+proc overloadedProc(x: string) =
+  echo x
+
+proc overloadedProc[T](x: T) =
+  echo x
+
+template normalTemplate(x: int) =
+  echo x
+
+template overloadedTemplate(x: int) =
+  echo x
+
+template overloadedTemplate(x: string) =
+  echo x
+
+macro normalMacro(x: int): untyped =
+  discard
+
+macro macroWithoutParams: untyped =
+  discard
+
+macro inspectSymbol(sym: typed, expected: static[string]): untyped =
+  if sym.kind == nnkSym:
+    echo "Symbol node:"
+    let res = sym.getImpl.repr & "\n"
+    echo res
+    # echo "|", res, "|"
+    # echo "|", expected, "|"
+    if expected.len > 0: assert res == expected
+  elif sym.kind in {nnkClosedSymChoice, nnkOpenSymChoice}:
+    echo "Begin sym choice:"
+    var results = newSeq[string](0)
+    for innerSym in sym:
+      results.add innerSym.getImpl.repr
+    sort(results, cmp[string])
+    let res = results.join("\n") & "\n"
+    echo res
+    if expected.len > 0: assert res == expected
+    echo "End symchoice."
+  else:
+    echo "Non-symbol node: ", sym.kind
+    if expected.len > 0: assert $sym.kind == expected
+
+macro inspectUntyped(sym: untyped, expected: static[string]): untyped =
+  let res = sym.repr
+  echo "Untyped node: ", res
+  assert res == expected
+
+inspectSymbol templateWithtouParams, "nnkCommand"
+  # this template is expanded, because bindSym was not used
+  # the end result is the template body (nnkCommand)
+
+inspectSymbol bindSym("templateWithtouParams"), """
+template templateWithtouParams() =
+  echo 10
+
+"""
+
+inspectSymbol macroWithoutParams, "nnkEmpty"
+  # Just like the template above, the macro was expanded
+
+inspectSymbol bindSym("macroWithoutParams"), """
+macro macroWithoutParams(): untyped =
+  discard
+
+"""
+
+inspectSymbol normalMacro, """
+macro normalMacro(x: int): untyped =
+  discard
+
+"""
+  # Since the normalMacro has params, it's automatically
+  # treated as a symbol here (no need for `bindSym`)
+
+inspectSymbol bindSym("normalMacro"), """
+macro normalMacro(x: int): untyped =
+  discard
+
+"""
+
+inspectSymbol normalTemplate, """
+template normalTemplate(x: int) =
+  echo x
+
+"""
+
+inspectSymbol bindSym("normalTemplate"), """
+template normalTemplate(x: int) =
+  echo x
+
+"""
+
+inspectSymbol overloadedTemplate, """
+template overloadedTemplate(x: int) =
+  echo x
+
+template overloadedTemplate(x: string) =
+  echo x
+
+"""
+
+inspectSymbol bindSym("overloadedTemplate"), """
+template overloadedTemplate(x: int) =
+  echo x
+
+template overloadedTemplate(x: string) =
+  echo x
+
+"""
+
+inspectUntyped bindSym("overloadedTemplate"), """bindSym("overloadedTemplate")"""
+  # binSym is active only in the presense of `typed` params.
+  # `untyped` params still get the raw AST
+
+inspectSymbol normalProc, """
+proc normalProc(x: int) =
+  echo [x]
+
+"""
+
+inspectSymbol bindSym("normalProc"), """
+proc normalProc(x: int) =
+  echo [x]
+
+"""
+
+inspectSymbol overloadedProc, """
+proc overloadedProc(x: int) =
+  echo [x]
+
+proc overloadedProc(x: string) =
+  echo [x]
+
+proc overloadedProc[T](x: T) =
+  echo x
+
+"""
+  # XXX: There seems to be a repr rendering problem above.
+  # Notice that `echo [x]`
+
+inspectSymbol overloadedProc[float], """
+proc overloadedProc(x: T) =
+  echo [x]
+
+"""
+  # As expected, when we select a specific generic, the
+  # AST is no longer a symChoice
+
+inspectSymbol bindSym("overloadedProc"), """
+proc overloadedProc(x: int) =
+  echo [x]
+
+proc overloadedProc(x: string) =
+  echo [x]
+
+proc overloadedProc[T](x: T) =
+  echo x
+
+"""
+
diff --git a/tests/misc/tsimplesort.nim b/tests/misc/tsimplesort.nim
index 3115863d5..e4a8e0b37 100644
--- a/tests/misc/tsimplesort.nim
+++ b/tests/misc/tsimplesort.nim
@@ -40,11 +40,11 @@ proc mustRehash(length, counter: int): bool {.inline.} =
   assert(length > counter)
   result = (length * 2 < counter * 3) or (length - counter < 4)
 
-proc nextTry(h, maxHash: THash): THash {.inline.} =
+proc nextTry(h, maxHash: Hash): Hash {.inline.} =
   result = ((5 * h) + 1) and maxHash
 
 template rawGetImpl() =
-  var h: THash = hash(key) and high(t.data) # start with real hash value
+  var h: Hash = hash(key) and high(t.data) # start with real hash value
   while t.data[h].slot != seEmpty:
     if t.data[h].key == key and t.data[h].slot == seFilled:
       return h
@@ -52,7 +52,7 @@ template rawGetImpl() =
   result = -1
 
 template rawInsertImpl() =
-  var h: THash = hash(key) and high(data)
+  var h: Hash = hash(key) and high(data)
   while data[h].slot == seFilled:
     h = nextTry(h, high(data))
   data[h].key = key
@@ -162,7 +162,7 @@ iterator values*[A](t: TCountTable[A]): int =
     if t.data[h].val != 0: yield t.data[h].val
 
 proc RawGet[A](t: TCountTable[A], key: A): int =
-  var h: THash = hash(key) and high(t.data) # start with real hash value
+  var h: Hash = hash(key) and high(t.data) # start with real hash value
   while t.data[h].val != 0:
     if t.data[h].key == key: return h
     h = nextTry(h, high(t.data))
@@ -181,7 +181,7 @@ proc hasKey*[A](t: TCountTable[A], key: A): bool =
 
 proc rawInsert[A](t: TCountTable[A], data: var seq[tuple[key: A, val: int]],
                   key: A, val: int) =
-  var h: THash = hash(key) and high(data)
+  var h: Hash = hash(key) and high(data)
   while data[h].val != 0: h = nextTry(h, high(data))
   data[h].key = key
   data[h].val = val
diff --git a/tests/modules/definitions.nim b/tests/modules/definitions.nim
new file mode 100644
index 000000000..edc6eaa6d
--- /dev/null
+++ b/tests/modules/definitions.nim
@@ -0,0 +1,4 @@
+var v*: int
+proc p* = echo "proc p called"
+template t* = echo "template t expanded"
+
diff --git a/tests/modules/proxy_module.nim b/tests/modules/proxy_module.nim
new file mode 100644
index 000000000..c244688cd
--- /dev/null
+++ b/tests/modules/proxy_module.nim
@@ -0,0 +1,3 @@
+import definitions
+export definitions except p
+
diff --git a/tests/overload/tparam_forwarding.nim b/tests/overload/tparam_forwarding.nim
index c1b276bfc..b0eea42c7 100644
--- a/tests/overload/tparam_forwarding.nim
+++ b/tests/overload/tparam_forwarding.nim
@@ -6,6 +6,10 @@ output: '''baz
 a
 b
 c
+x: 1, y: test 1
+x: 2, y: test 2
+x: 10, y: test 3
+x: 4, y: test 4
 '''
 """
 
@@ -35,3 +39,15 @@ templateForwarding fooVarargs, "test".len > 3, Foo(x: 10), Foo(x: 100), Foo(x: 1
 
 procForwarding "a", "b", "c"
 
+proc hasKeywordArgs(x = 10, y = "y") =
+  echo "x: ", x, ", y: ", y
+
+proc hasRegularArgs(x: int, y: string) =
+  echo "x: ", x, ", y: ", y
+
+templateForwarding(hasRegularArgs, true, 1, "test 1")
+templateForwarding hasKeywordArgs, true, 2, "test 2"
+
+templateForwarding(hasKeywordArgs, true, y = "test 3")
+templateForwarding hasKeywordArgs, true, y = "test 4", x = 4
+
diff --git a/tests/parser/tbraces.nim b/tests/parser/tbraces.nim
deleted file mode 100644
index 86c854546..000000000
--- a/tests/parser/tbraces.nim
+++ /dev/null
@@ -1,432 +0,0 @@
-#? braces
-
-#
-#
-#            Nim's Runtime Library
-#        (c) Copyright 2015 Andreas Rumpf
-#
-#    See the file "copying.txt", included in this
-#    distribution, for details about the copyright.
-#
-
-## This module implements some common generic algorithms.
-
-type
-  SortOrder* = enum {  ## sort order
-    Descending, Ascending
-  }
-
-
-type(
-  DummyAlias = int
-  OtherAlias = distinct char
-
-  SomeObject = object of RootObj { ## declaration here
-    fieldA, fieldB: int
-    case order: SortOrder {
-      of Descending {a: string}
-      of Ascending {b: seq[char]}
-    }
-  }
-
-  MyConcept = concept x {
-     x is int
-  }
-)
-
-{.deprecated: [TSortOrder: SortOrder].}
-
-
-proc `*`*(x: int, order: SortOrder): int @inline {
-  ## flips `x` if ``order == Descending``;
-  ## if ``order == Ascending`` then `x` is returned.
-  ## `x` is supposed to be the result of a comparator, ie ``< 0`` for
-  ## *less than*, ``== 0`` for *equal*, ``> 0`` for *greater than*.
-  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
-  var y = last
-  while x < y {
-    swap(a[x], a[y])
-    dec(y)
-    inc(x)
-  }
-}
-
-proc reverse*[T](a: var openArray[T]) {
-  ## reverses the array `a`.
-  reverse(a, 0, a.high)
-}
-
-proc reversed*[T](a: openArray[T], first: Natural, last: int): seq[T] {
-  ## returns the reverse of the array `a[first..last]`.
-  assert last >= first-1
-  var i = last - first
-  var x = first.int
-  result = newSeq[T](i + 1)
-  while i >= 0 {
-    result[i] = a[x]
-    dec(i)
-    inc(x)
-  }
-}
-
-proc reversed*[T](a: openArray[T]): seq[T] {
-  ## returns the reverse of the array `a`.
-  reversed(a, 0, a.high)
-}
-
-proc binarySearch*[T](a: openArray[T], key: T): int {
-  ## binary search for `key` in `a`. Returns -1 if not found.
-  var b = len(a)
-  while result < b {
-    var mid = (result + b) div 2
-    if a[mid] < key { result = mid + 1 } else { b = mid }
-  }
-  if result >= len(a) or a[result] != key { result = -1 }
-}
-
-proc smartBinarySearch*[T](a: openArray[T], key: T): int {
-  ## ``a.len`` must be a power of 2 for this to work.
-  var step = a.len div 2
-  while step > 0 {
-    if a[result or step] <= key { result = result or step }
-    step = step shr 1
-  }
-  if a[result] != key { result = -1 }
-}
-
-const (
-  onlySafeCode = true
-)
-
-proc lowerBound*[T](a: openArray[T], key: T, cmp: proc(x,y: T): int @closure): int {
-  ## same as binarySearch except that if key is not in `a` then this
-  ## returns the location where `key` would be if it were. In other
-  ## words if you have a sorted sequence and you call
-  ## insert(thing, elm, lowerBound(thing, elm))
-  ## the sequence will still be sorted.
-  ##
-  ## `cmp` is the comparator function to use, the expected return values are
-  ## the same as that of system.cmp.
-  ##
-  ## example::
-  ##
-  ##   var arr = @[1,2,3,5,6,7,8,9]
-  ##   arr.insert(4, arr.lowerBound(4))
-  ##   # after running the above arr is `[1,2,3,4,5,6,7,8,9]`
-  result = a.low
-  var count = a.high - a.low + 1
-  var step, pos: int
-  while count != 0 {
-    step = count div 2
-    pos = result + step
-    if cmp(a[pos], key) < 0 {
-      result = pos + 1
-      count -= step + 1
-    } else {
-      count = step
-    }
-  }
-}
-
-proc lowerBound*[T](a: openArray[T], key: T): int { lowerBound(a, key, cmp[T]) }
-proc merge[T](a, b: var openArray[T], lo, m, hi: int,
-              cmp: proc (x, y: T): int @closure, order: SortOrder) {
-  template `<-` (a, b) {
-    when false {
-      a = b
-    } elif onlySafeCode {
-      shallowCopy(a, b)
-    } else {
-      copyMem(addr(a), addr(b), sizeof(T))
-    }
-  }
-  # optimization: If max(left) <= min(right) there is nothing to do!
-  # 1 2 3 4  ## 5 6 7 8
-  # -> O(n) for sorted arrays.
-  # On random data this safes up to 40% of merge calls
-  if cmp(a[m], a[m+1]) * order <= 0 { return }
-  var j = lo
-  # copy a[j..m] into b:
-  assert j <= m
-  when onlySafeCode {
-    var bb = 0
-    while j <= m {
-      b[bb] <- a[j]
-      inc(bb)
-      inc(j)
-    }
-  } else {
-    copyMem(addr(b[0]), addr(a[j]), sizeof(T)*(m-j+1))
-    j = m+1
-  }
-  var i = 0
-  var k = lo
-  # copy proper element back:
-  while k < j and j <= hi {
-    if cmp(b[i], a[j]) * order <= 0 {
-      a[k] <- b[i]
-      inc(i)
-    } else {
-      a[k] <- a[j]
-      inc(j)
-    }
-    inc(k)
-  }
-  # copy rest of b:
-  when onlySafeCode {
-    while k < j {
-      a[k] <- b[i]
-      inc(k)
-      inc(i)
-    }
-  } else {
-    if k < j { copyMem(addr(a[k]), addr(b[i]), sizeof(T)*(j-k)) }
-  }
-}
-
-proc sort*[T](a: var openArray[T],
-              cmp: proc (x, y: T): int @closure,
-              order = SortOrder.Ascending) {
-  ## Default Nim sort (an implementation of merge sort). The sorting
-  ## is guaranteed to be stable and the worst case is guaranteed to
-  ## be O(n log n).
-  ## The current implementation uses an iterative
-  ## mergesort to achieve this. It uses a temporary sequence of
-  ## length ``a.len div 2``. Currently Nim does not support a
-  ## sensible default argument for ``cmp``, so you have to provide one
-  ## of your own. However, the ``system.cmp`` procs can be used:
-  ##
-  ## .. code-block:: nim
-  ##
-  ##    sort(myIntArray, system.cmp[int])
-  ##
-  ##    # do not use cmp[string] here as we want to use the specialized
-  ##    # overload:
-  ##    sort(myStrArray, system.cmp)
-  ##
-  ## You can inline adhoc comparison procs with the `do notation
-  ## <manual.html#procedures-do-notation>`_. Example:
-  ##
-  ## .. code-block:: nim
-  ##
-  ##   people.sort do (x, y: Person) -> int:
-  ##     result = cmp(x.surname, y.surname)
-  ##     if result == 0:
-  ##       result = cmp(x.name, y.name)
-  var n = a.len
-  var b: seq[T]
-  newSeq(b, n div 2)
-  var s = 1
-  while s < n {
-    var m = n-1-s
-    while m >= 0 {
-      merge(a, b, max(m-s+1, 0), m, m+s, cmp, order)
-      dec(m, s*2)
-    }
-    s = s*2
-  }
-}
-
-proc sorted*[T](a: openArray[T], cmp: proc(x, y: T): int {.closure.},
-                order = SortOrder.Ascending): seq[T] {
-  ## returns `a` sorted by `cmp` in the specified `order`.
-  result = newSeq[T](a.len)
-  for i in 0 .. a.high { result[i] = a[i] }
-  sort(result, cmp, order)
-}
-
-template sortedByIt*(seq1, op: untyped): untyped {
-  ## Convenience template around the ``sorted`` proc to reduce typing.
-  ##
-  ## The template injects the ``it`` variable which you can use directly in an
-  ## expression. Example:
-  ##
-  ## .. code-block:: nim
-  ##
-  ##   type Person = tuple[name: string, age: int]
-  ##   var
-  ##     p1: Person = (name: "p1", age: 60)
-  ##     p2: Person = (name: "p2", age: 20)
-  ##     p3: Person = (name: "p3", age: 30)
-  ##     p4: Person = (name: "p4", age: 30)
-  ##     people = @[p1,p2,p4,p3]
-  ##
-  ##   echo people.sortedByIt(it.name)
-  ##
-  ## Because the underlying ``cmp()`` is defined for tuples you can do
-  ## a nested sort like in the following example:
-  ##
-  ## .. code-block:: nim
-  ##
-  ##   echo people.sortedByIt((it.age, it.name))
-  ##
-  var result = sorted(seq1, proc(x, y: type[seq1[0]]): int {
-    var it {.inject.} = x
-    let a = op
-    it = y
-    let b = op
-    result = cmp(a, b)
-  })
-  result
-}
-
-proc isSorted*[T](a: openarray[T],
-                 cmp: proc(x, y: T): int {.closure.},
-                 order = SortOrder.Ascending): bool {
-  ## Checks to see whether `a` is already sorted in `order`
-  ## using `cmp` for the comparison. Parameters identical
-  ## to `sort`
-  result = true
-  for i in 0..<len(a)-1 {
-    case cmp(a[i],a[i+1]) * order > 0 {
-      of true { return false }
-      of false {}
-    }
-  }
-}
-
-proc product*[T](x: openArray[seq[T]]): seq[seq[T]] {
-  ## produces the Cartesian product of the array. Warning: complexity
-  ## may explode.
-  result = newSeq[seq[T]]()
-  if x.len == 0 { return }
-  if x.len == 1 {
-    result = @x
-    return
-  }
-  var (
-    indexes = newSeq[int](x.len)
-    initial = newSeq[int](x.len)
-    index = 0
-  )
-  var next = newSeq[T]()
-  next.setLen(x.len)
-  for i in 0..(x.len-1) {
-    if len(x[i]) == 0 { return }
-    initial[i] = len(x[i])-1
-  }
-  indexes = initial
-  while true {
-    while indexes[index] == -1 {
-      indexes[index] = initial[index]
-      index += 1
-      if index == x.len { return }
-      indexes[index] -= 1
-    }
-    for ni, i in indexes {
-      next[ni] = x[ni][i]
-    }
-    var res: seq[T]
-    shallowCopy(res, next)
-    result.add(res)
-    index = 0
-    indexes[index] -= 1
-  }
-}
-
-proc nextPermutation*[T](x: var openarray[T]): bool {.discardable.} {
-  ## Calculates the next lexicographic permutation, directly modifying ``x``.
-  ## The result is whether a permutation happened, otherwise we have reached
-  ## the last-ordered permutation.
-  ##
-  ## .. code-block:: nim
-  ##
-  ##     var v = @[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
-  ##     v.nextPermutation()
-  ##     echo v # @[0, 1, 2, 3, 4, 5, 6, 7, 9, 8]
-  if x.len < 2 {
-    return false }
-
-  var i = x.high
-  while i > 0 and x[i-1] >= x[i] { dec i }
-  if i == 0 { return false }
-
-  var j = x.high
-  while j >= i and x[j] <= x[i-1] { dec j }
-
-  swap x[j], x[i-1]
-  x.reverse(i, x.high)
-
-  result = true
-}
-
-proc prevPermutation*[T](x: var openarray[T]): bool @discardable {
-  ## Calculates the previous lexicographic permutation, directly modifying
-  ## ``x``.  The result is whether a permutation happened, otherwise we have
-  ## reached the first-ordered permutation.
-  ##
-  ## .. code-block:: nim
-  ##
-  ##     var v = @[0, 1, 2, 3, 4, 5, 6, 7, 9, 8]
-  ##     v.prevPermutation()
-  ##     echo v # @[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
-  if x.len < 2 { return false }
-
-  var i = x.high
-  while i > 0 and x[i-1] <= x[i] {
-    dec i
-  }
-  if i == 0 { return false }
-
-  x.reverse(i, x.high)
-
-  var j = x.high
-  while j >= i and x[j-1] < x[i-1] {
-    dec j
-  }
-  swap x[i-1], x[j]
-
-  result = true
-}
-
-when isMainModule {
-  # Tests for lowerBound
-  var arr = @[1,2,3,5,6,7,8,9]
-  assert arr.lowerBound(0) == 0
-  assert arr.lowerBound(4) == 3
-  assert arr.lowerBound(5) == 3
-  assert arr.lowerBound(10) == 8
-  arr = @[1,5,10]
-  try {
-    assert arr.lowerBound(4) == 1
-    assert arr.lowerBound(5) == 1
-    assert arr.lowerBound(6) == 2
-  } except ValueError {}
-  # Tests for isSorted
-  var srt1 = [1,2,3,4,4,4,4,5]
-  var srt2 = ["iello","hello"]
-  var srt3 = [1.0,1.0,1.0]
-  var srt4: seq[int] = @[]
-  assert srt1.isSorted(cmp) == true
-  assert srt2.isSorted(cmp) == false
-  assert srt3.isSorted(cmp) == true
-  var srtseq = newSeq[int]()
-  assert srtseq.isSorted(cmp) == true
-  # Tests for reversed
-  var arr1 = @[0,1,2,3,4]
-  assert arr1.reversed() == @[4,3,2,1,0]
-  for i in 0 .. high(arr1) {
-    assert arr1.reversed(0, i) == arr1.reversed()[high(arr1) - i .. high(arr1)]
-    assert arr1.reversed(i, high(arr1)) == arr1.reversed()[0 .. high(arr1) - i]
-  }
-}
diff --git a/tests/parser/tcommand_as_expr.nim b/tests/parser/tcommand_as_expr.nim
index a244c8767..b25ec4bd8 100644
--- a/tests/parser/tcommand_as_expr.nim
+++ b/tests/parser/tcommand_as_expr.nim
@@ -2,7 +2,10 @@ discard """
   output: '''140
 5-120-120
 359
-77'''
+77
+-4
+-1
+-1'''
 """
 #import math
 import sequtils
@@ -25,3 +28,11 @@ let a = [2,4,8].map do (d:int) -> int: d + 1
 echo a[0], a[1], a[2]
 
 echo(foo 8, foo 8)
+
+# bug #7582
+proc f(x: int): int = x
+
+echo f -4
+
+echo int -1 # doesn't compile
+echo int `-` 1 # compiles
diff --git a/tests/parser/twrongcmdsyntax.nim b/tests/parser/twrongcmdsyntax.nim
index affe72c34..c2962bed4 100644
--- a/tests/parser/twrongcmdsyntax.nim
+++ b/tests/parser/twrongcmdsyntax.nim
@@ -1,5 +1,5 @@
 discard """
-  errormsg: '''identifier expected, but found 'echo 4'''
+  errormsg: '''in expression '4 2': identifier expected, but found '4'''
   line: 6
 """
 
diff --git a/tests/stdlib/ttimes.nim b/tests/stdlib/ttimes.nim
index 37e14c1e2..4ab3ba581 100644
--- a/tests/stdlib/ttimes.nim
+++ b/tests/stdlib/ttimes.nim
@@ -28,6 +28,12 @@ t.checkFormat("d dd ddd dddd h hh H HH m mm M MM MMM MMMM s" &
 
 t.checkFormat("yyyyMMddhhmmss", "20380119031407")
 
+# issue 7620
+let t7620_am = parse("4/15/2017 12:01:02 AM +0", "M/d/yyyy' 'h:mm:ss' 'tt' 'z", utc())
+t7620_am.checkFormat("M/d/yyyy' 'h:mm:ss' 'tt' 'z", "4/15/2017 12:01:02 AM +0")
+let t7620_pm = parse("4/15/2017 12:01:02 PM +0", "M/d/yyyy' 'h:mm:ss' 'tt' 'z", utc())
+t7620_pm.checkFormat("M/d/yyyy' 'h:mm:ss' 'tt' 'z", "4/15/2017 12:01:02 PM +0")
+
 let t2 = fromUnix(160070789).utc # Mon 27 Jan 16:06:29 GMT 1975
 t2.checkFormat("d dd ddd dddd h hh H HH m mm M MM MMM MMMM s" &
   " ss t tt y yy yyy yyyy yyyyy z zz zzz",
diff --git a/tests/testament/tester.nim b/tests/testament/tester.nim
index f08c83079..0c6f376d3 100644
--- a/tests/testament/tester.nim
+++ b/tests/testament/tester.nim
@@ -212,18 +212,18 @@ proc cmpMsgs(r: var TResults, expected, given: TSpec, test: TTest, target: TTarg
   elif expected.tfile == "" and extractFilename(expected.file) != extractFilename(given.file) and
       "internal error:" notin expected.msg:
     r.addResult(test, target, expected.file, given.file, reFilesDiffer)
-  elif expected.line   != given.line   and expected.line   != 0 or
+  elif expected.line != given.line and expected.line != 0 or
        expected.column != given.column and expected.column != 0:
     r.addResult(test, target, $expected.line & ':' & $expected.column,
-                      $given.line    & ':' & $given.column,
+                      $given.line & ':' & $given.column,
                       reLinesDiffer)
   elif expected.tfile != "" and extractFilename(expected.tfile) != extractFilename(given.tfile) and
       "internal error:" notin expected.msg:
     r.addResult(test, target, expected.tfile, given.tfile, reFilesDiffer)
-  elif expected.tline   != given.tline   and expected.tline   != 0 or
+  elif expected.tline != given.tline and expected.tline != 0 or
        expected.tcolumn != given.tcolumn and expected.tcolumn != 0:
     r.addResult(test, target, $expected.tline & ':' & $expected.tcolumn,
-                      $given.tline    & ':' & $given.tcolumn,
+                      $given.tline & ':' & $given.tcolumn,
                       reLinesDiffer)
   else:
     r.addResult(test, target, expected.msg, given.msg, reSuccess)
diff --git a/tests/threads/tthreadvars.nim b/tests/threads/tthreadvars.nim
new file mode 100644
index 000000000..81aa2e5ec
--- /dev/null
+++ b/tests/threads/tthreadvars.nim
@@ -0,0 +1,78 @@
+discard """
+output: '''
+10
+1111
+1222
+3030303
+3060606
+6060606
+6121212
+3030903
+3061206
+3031503
+3061806
+5050505
+5101010
+'''
+"""
+
+import typetraits
+
+var tls1 {.threadvar.}: int
+var g0: int
+var g1 {.global.}: int
+
+proc customInc(x: var int, delta: int) =
+  x += delta
+
+customInc(tls1, 10)
+echo tls1
+
+proc nonGenericProc: int =
+  var local: int
+  var nonGenericTls {.threadvar.}: int
+  var nonGenericGlobal {.global.}: int
+  var nonGenericMixedPragmas {.global, threadvar.}: int
+
+  customInc local, 1000
+  customInc nonGenericTls, 1
+  customInc nonGenericGlobal, 10
+  customInc nonGenericMixedPragmas, 100
+
+  return local + nonGenericTls + nonGenericGlobal + nonGenericMixedPragmas
+
+proc genericProc(T: typedesc): int =
+  var local: int
+  var genericTls {.threadvar.}: int
+  var genericGlobal {.global.}: int
+  var genericMixedPragmas {.global, threadvar.}: int
+
+  customInc local, T.name.len * 1000000
+  customInc genericTls, T.name.len * 1
+  customInc genericGlobal, T.name.len * 100
+  customInc genericMixedPragmas, T.name.len * 10000
+
+  return local + genericTls + genericGlobal + genericMixedPragmas
+
+echo nonGenericProc()
+echo nonGenericProc()
+
+echo genericProc(int)
+echo genericProc(int)
+
+echo genericProc(string)
+echo genericProc(string)
+
+proc echoInThread[T]() {.thread.} =
+  echo genericProc(T)
+  echo genericProc(T)
+
+proc newEchoThread(T: typedesc) =
+  var t: Thread[void]
+  createThread(t, echoInThread[T])
+  joinThreads(t)
+
+newEchoThread int
+newEchoThread int
+newEchoThread float
+
diff --git a/tests/trmacros/thoist.nim b/tests/trmacros/thoist.nim
index 7d14c0abf..657f210a1 100644
--- a/tests/trmacros/thoist.nim
+++ b/tests/trmacros/thoist.nim
@@ -5,7 +5,7 @@ true'''
 
 import pegs
 
-template optPeg{peg(pattern)}(pattern: string{lit}): TPeg =
+template optPeg{peg(pattern)}(pattern: string{lit}): Peg =
   var gl {.global, gensym.} = peg(pattern)
   gl
 
diff --git a/tests/typerel/texplicitcmp.nim b/tests/typerel/texplicitcmp.nim
index 8aec9885a..e91ac2ffe 100644
--- a/tests/typerel/texplicitcmp.nim
+++ b/tests/typerel/texplicitcmp.nim
@@ -18,7 +18,7 @@ proc works() =
   sort(f, system.cmp[int])
   outp(f)
 
-proc weird(json_params: TTable) =
+proc weird(json_params: Table) =
   var f = @[3, 2, 1]
   # The following line doesn't compile: type mismatch. Why?
   sort(f, system.cmp[int])
@@ -29,4 +29,4 @@ when isMainModule:
   sort(t, system.cmp[int])
   outp(t)
   works()
-  weird(initTable[string, TJsonNode]())
+  weird(initTable[string, JsonNode]())
diff --git a/tests/vm/tref.nim b/tests/vm/tref.nim
new file mode 100644
index 000000000..517a67fb0
--- /dev/null
+++ b/tests/vm/tref.nim
@@ -0,0 +1,12 @@
+static:
+  var
+    a: ref string
+    b: ref string
+  new a
+
+  a[] = "Hello world"
+  b = a
+
+  b[5] = 'c'
+  doAssert a[] == "Hellocworld"
+  doAssert b[] == "Hellocworld"
\ No newline at end of file
diff --git a/tools/finish.nim b/tools/finish.nim
index b5ef78b65..4f2c72595 100644
--- a/tools/finish.nim
+++ b/tools/finish.nim
@@ -187,12 +187,14 @@ when defined(windows):
 
 proc main() =
   when defined(windows):
-    let desiredPath = expandFilename(getCurrentDir() / "bin")
+    let nimDesiredPath = expandFilename(getCurrentDir() / "bin")
+    let nimbleDesiredPath = expandFilename(getEnv("USERPROFILE") / ".nimble" / "bin")
     let p = tryGetUnicodeValue(r"Environment", "Path",
       HKEY_CURRENT_USER) & ";" & tryGetUnicodeValue(
         r"System\CurrentControlSet\Control\Session Manager\Environment", "Path",
         HKEY_LOCAL_MACHINE)
-    var alreadyInPath = false
+    var nimAlreadyInPath = false
+    var nimbleAlreadyInPath = false
     var mingWchoices: seq[string] = @[]
     var incompat: seq[string] = @[]
     for x in p.split(';'):
@@ -200,18 +202,29 @@ proc main() =
       let y = try: expandFilename(if x[0] == '"' and x[^1] == '"':
                                     substr(x, 1, x.len-2) else: x)
               except: ""
-      if y.cmpIgnoreCase(desiredPath) == 0: alreadyInPath = true
-      if y.toLowerAscii.contains("mingw"):
+      if y.cmpIgnoreCase(nimDesiredPath) == 0:
+        nimAlreadyInPath = true
+      elif y.cmpIgnoreCase(nimbleDesiredPath) == 0:
+        nimbleAlreadyInPath = true
+      elif y.toLowerAscii.contains("mingw"):
         if dirExists(y):
           if checkGccArch(y): mingWchoices.add y
           else: incompat.add y
 
-    if alreadyInPath:
-      echo "bin/nim.exe is already in your PATH [Skipping]"
+    if nimAlreadyInPath:
+      echo "bin\\nim.exe is already in your PATH [Skipping]"
     else:
       if askBool("nim.exe is not in your PATH environment variable.\n" &
           "Should it be added permanently? (y/n) "):
-        addToPathEnv(desiredPath)
+        addToPathEnv(nimDesiredPath)
+
+    if nimbleAlreadyInPath:
+      echo nimbleDesiredPath & " is already in your PATH [Skipping]"
+    else:
+      if askBool(nimbleDesiredPath & " is not in your PATH environment variable.\n" &
+          "Should it be added permanently? (y/n) "):
+        addToPathEnv(nimbleDesiredPath)
+
     if mingWchoices.len == 0:
       # No mingw in path, so try a few locations:
       let alternative = tryDirs(incompat, defaultMingwLocations())
diff --git a/tools/niminst/buildsh.tmpl b/tools/niminst/buildsh.tmpl
index 3e7d8ae6e..be6d43754 100644
--- a/tools/niminst/buildsh.tmpl
+++ b/tools/niminst/buildsh.tmpl
@@ -39,8 +39,8 @@ do
   esac
 done
 
-CC="gcc"
-LINKER="gcc"
+CC="${CC:-gcc}"
+LINKER="${LD:-gcc}"
 COMP_FLAGS="${CPPFLAGS:-} ${CFLAGS:-} ?{c.ccompiler.flags}$extraBuildArgs"
 LINK_FLAGS="${LDFLAGS:-} ?{c.linker.flags}"
 PS4=""