summary refs log tree commit diff stats
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/core/allocators.nim41
-rw-r--r--lib/core/macros.nim16
-rw-r--r--lib/core/seqs.nim242
-rw-r--r--lib/core/strs.nim230
-rw-r--r--lib/js/asyncjs.nim16
-rw-r--r--lib/js/dom.nim2
-rw-r--r--lib/nimbase.h2
-rw-r--r--lib/packages/docutils/highlite.nim2
-rw-r--r--lib/packages/docutils/rst.nim2
-rw-r--r--lib/packages/docutils/rstgen.nim117
-rw-r--r--lib/posix/posix_linux_amd64_consts.nim2
-rw-r--r--lib/pure/asyncdispatch.nim191
-rw-r--r--lib/pure/asyncmacro.nim2
-rw-r--r--lib/pure/cgi.nim7
-rw-r--r--lib/pure/collections/deques.nim5
-rw-r--r--lib/pure/collections/sequtils.nim1
-rw-r--r--lib/pure/collections/sets.nim4
-rw-r--r--lib/pure/coro.nim7
-rw-r--r--lib/pure/htmlgen.nim307
-rw-r--r--lib/pure/htmlparser.nim2926
-rw-r--r--lib/pure/httpclient.nim4
-rw-r--r--lib/pure/json.nim20
-rw-r--r--lib/pure/logging.nim13
-rw-r--r--lib/pure/marshal.nim14
-rw-r--r--lib/pure/memfiles.nim1
-rw-r--r--lib/pure/net.nim33
-rw-r--r--lib/pure/os.nim11
-rw-r--r--lib/pure/ospaths.nim56
-rw-r--r--lib/pure/osproc.nim6
-rw-r--r--lib/pure/parsecfg.nim35
-rw-r--r--lib/pure/parseopt.nim119
-rw-r--r--lib/pure/parsesql.nim1
-rw-r--r--lib/pure/parsexml.nim140
-rw-r--r--lib/pure/pegs.nim730
-rw-r--r--lib/pure/strscans.nim6
-rw-r--r--lib/pure/strutils.nim10
-rw-r--r--lib/pure/times.nim16
-rw-r--r--lib/pure/unidecode/gen.py34
-rw-r--r--lib/pure/unidecode/unidecode.dat841
-rw-r--r--lib/pure/unidecode/unidecode.nim27
-rw-r--r--lib/pure/xmldom.nim182
-rw-r--r--lib/system.nim305
-rw-r--r--lib/system/assign.nim5
-rw-r--r--lib/system/cgprocs.nim1
-rw-r--r--lib/system/excpt.nim23
-rw-r--r--lib/system/gc_ms.nim96
-rw-r--r--lib/system/helpers.nim11
-rw-r--r--lib/system/hti.nim12
-rw-r--r--lib/system/jssys.nim23
-rw-r--r--lib/system/mmdisp.nim125
-rw-r--r--lib/system/nimscript.nim40
-rw-r--r--lib/system/repr.nim29
-rw-r--r--lib/system/reprjs.nim5
-rw-r--r--lib/system/strmantle.nim298
-rw-r--r--lib/system/sysio.nim16
-rw-r--r--lib/system/sysstr.nim296
-rw-r--r--lib/system/threads.nim5
-rw-r--r--lib/system/widestrs.nim3
58 files changed, 4310 insertions, 3404 deletions
diff --git a/lib/core/allocators.nim b/lib/core/allocators.nim
index 62f5e9756..f652f0d85 100644
--- a/lib/core/allocators.nim
+++ b/lib/core/allocators.nim
@@ -8,28 +8,41 @@
 #
 
 type
+  AllocatorFlag* {.pure.} = enum  ## flags describing the properties of the allocator
+    ThreadLocal ## the allocator is thread local only.
+    ZerosMem    ## the allocator always zeros the memory on an allocation
   Allocator* = ptr object {.inheritable.}
     alloc*: proc (a: Allocator; size: int; alignment: int = 8): pointer {.nimcall.}
     dealloc*: proc (a: Allocator; p: pointer; size: int) {.nimcall.}
     realloc*: proc (a: Allocator; p: pointer; oldSize, newSize: int): pointer {.nimcall.}
+    deallocAll*: proc (a: Allocator) {.nimcall.}
+    flags*: set[AllocatorFlag]
 
 var
-  currentAllocator {.threadvar.}: Allocator
+  localAllocator {.threadvar.}: Allocator
+  sharedAllocator: Allocator
 
-proc getCurrentAllocator*(): Allocator =
-  result = currentAllocator
+proc getLocalAllocator*(): Allocator =
+  result = localAllocator
 
-proc setCurrentAllocator*(a: Allocator) =
-  currentAllocator = a
+proc setLocalAllocator*(a: Allocator) =
+  localAllocator = a
 
-proc alloc*(size: int; alignment: int = 8): pointer =
-  let a = getCurrentAllocator()
-  result = a.alloc(a, size, alignment)
+proc getSharedAllocator*(): Allocator =
+  result = sharedAllocator
 
-proc dealloc*(p: pointer; size: int) =
-  let a = getCurrentAllocator()
-  a.dealloc(a, p, size)
+proc setSharedAllocator*(a: Allocator) =
+  sharedAllocator = a
 
-proc realloc*(p: pointer; oldSize, newSize: int): pointer =
-  let a = getCurrentAllocator()
-  result = a.realloc(a, p, oldSize, newSize)
+when false:
+  proc alloc*(size: int; alignment: int = 8): pointer =
+    let a = getCurrentAllocator()
+    result = a.alloc(a, size, alignment)
+
+  proc dealloc*(p: pointer; size: int) =
+    let a = getCurrentAllocator()
+    a.dealloc(a, p, size)
+
+  proc realloc*(p: pointer; oldSize, newSize: int): pointer =
+    let a = getCurrentAllocator()
+    result = a.realloc(a, p, oldSize, newSize)
diff --git a/lib/core/macros.nim b/lib/core/macros.nim
index 90fea440e..aec766068 100644
--- a/lib/core/macros.nim
+++ b/lib/core/macros.nim
@@ -8,6 +8,7 @@
 #
 
 include "system/inclrtl"
+include "system/helpers"
 
 ## This module contains the interface to the compiler's abstract syntax
 ## tree (`AST`:idx:). Macros operate on this tree.
@@ -236,6 +237,12 @@ else: # bootstrapping substitute
     else:
       n.strValOld
 
+when defined(nimHasSymOwnerInMacro):
+  proc owner*(sym: NimNode): NimNode {.magic: "SymOwner", noSideEffect.}
+    ## accepts node of kind nnkSym and returns its owner's symbol.
+    ## result is also mnde of kind nnkSym if owner exists otherwise
+    ## nnkNilLit is returned
+
 proc getType*(n: NimNode): NimNode {.magic: "NGetType", noSideEffect.}
   ## with 'getType' you can access the node's `type`:idx:. A Nim type is
   ## mapped to a Nim AST too, so it's slightly confusing but it means the same
@@ -335,10 +342,10 @@ proc copyNimTree*(n: NimNode): NimNode {.magic: "NCopyNimTree", noSideEffect.}
 proc error*(msg: string, n: NimNode = nil) {.magic: "NError", benign.}
   ## writes an error message at compile time
 
-proc warning*(msg: string) {.magic: "NWarning", benign.}
+proc warning*(msg: string, n: NimNode = nil) {.magic: "NWarning", benign.}
   ## writes a warning message at compile time
 
-proc hint*(msg: string) {.magic: "NHint", benign.}
+proc hint*(msg: string, n: NimNode = nil) {.magic: "NHint", benign.}
   ## writes a hint message at compile time
 
 proc newStrLitNode*(s: string): NimNode {.compileTime, noSideEffect.} =
@@ -422,7 +429,8 @@ type
     line*,column*: int
 
 proc `$`*(arg: Lineinfo): string =
-  result = arg.filename & "(" & $arg.line & ", " & $arg.column & ")"
+  # BUG: without `result = `, gives compile error
+  result = lineInfoToString(arg.filename, arg.line, arg.column)
 
 #proc lineinfo*(n: NimNode): LineInfo {.magic: "NLineInfo", noSideEffect.}
   ## returns the position the node appears in the original source file
@@ -969,7 +977,7 @@ proc newIfStmt*(branches: varargs[tuple[cond, body: NimNode]]):
   ##
   result = newNimNode(nnkIfStmt)
   for i in branches:
-    result.add(newNimNode(nnkElifBranch).add(i.cond, i.body))
+    result.add(newTree(nnkElifBranch, i.cond, i.body))
 
 proc newEnum*(name: NimNode, fields: openArray[NimNode],
               public, pure: bool): NimNode {.compileTime.} =
diff --git a/lib/core/seqs.nim b/lib/core/seqs.nim
index 02c192851..4dcf6cbbb 100644
--- a/lib/core/seqs.nim
+++ b/lib/core/seqs.nim
@@ -7,133 +7,163 @@
 #    distribution, for details about the copyright.
 #
 
-import allocators, typetraits
+
+import typetraits
+# strs already imported allocators for us.
 
 ## Default seq implementation used by Nim's core.
 type
-  seq*[T] = object
-    len, cap: int
-    data: ptr UncheckedArray[T]
+  NimSeqPayload {.core.}[T] = object
+    cap: int
+    region: Allocator
+    data: UncheckedArray[T]
+
+  NimSeqV2*[T] = object
+    len: int
+    p: ptr NimSeqPayload[T]
 
 const nimSeqVersion {.core.} = 2
 
-template frees(s) = dealloc(s.data, s.cap * sizeof(T))
+template payloadSize(cap): int = cap * sizeof(T) + sizeof(int) + sizeof(Allocator)
 
 # XXX make code memory safe for overflows in '*'
 
-when defined(nimHasTrace):
-  proc `=trace`[T](s: seq[T]; a: Allocator) =
-    for i in 0 ..< s.len: `=trace`(s.data[i], a)
+when false:
+  # this is currently not part of Nim's type bound operators and so it's
+  # built into the tracing proc generation just like before.
+  proc `=trace`[T](s: NimSeqV2[T]) =
+    for i in 0 ..< s.len: `=trace`(s.data[i])
 
-proc `=destroy`[T](x: var seq[T]) =
-  if x.data != nil:
+proc `=destroy`[T](s: var seq[T]) =
+  var x = cast[ptr NimSeqV2[T]](addr s)
+  var p = x.p
+  if p != nil:
     when not supportsCopyMem(T):
-      for i in 0..<x.len: `=destroy`(x[i])
-    frees(x)
-    x.data = nil
+      for i in 0..<x.len: `=destroy`(p.data[i])
+    p.region.dealloc(p.region, p, payloadSize(p.cap))
+    x.p = nil
     x.len = 0
-    x.cap = 0
 
-proc `=`[T](a: var seq[T]; b: seq[T]) =
-  if a.data == b.data: return
-  if a.data != nil:
-    frees(a)
-    a.data = nil
+proc `=`[T](x: var seq[T]; y: seq[T]) =
+  var a = cast[ptr NimSeqV2[T]](addr x)
+  var b = cast[ptr NimSeqV2[T]](unsafeAddr y)
+
+  if a.p == b.p: return
+  `=destroy`(a)
   a.len = b.len
-  a.cap = b.cap
-  if b.data != nil:
-    a.data = cast[type(a.data)](alloc(a.cap * sizeof(T)))
+  if b.p != nil:
+    a.p = cast[type(a.p)](alloc(payloadSize(a.len)))
     when supportsCopyMem(T):
-      copyMem(a.data, b.data, a.cap * sizeof(T))
+      if a.len > 0:
+        copyMem(unsafeAddr a.p.data[0], unsafeAddr b.p.data[0], a.len * sizeof(T))
     else:
       for i in 0..<a.len:
-        a.data[i] = b.data[i]
+        a.p.data[i] = b.p.data[i]
 
-proc `=sink`[T](a: var seq[T]; b: seq[T]) =
-  if a.data != nil and a.data != b.data:
-    frees(a)
+proc `=sink`[T](x: var seq[T]; y: seq[T]) =
+  var a = cast[ptr NimSeqV2[T]](addr x)
+  var b = cast[ptr NimSeqV2[T]](unsafeAddr y)
+  if a.p != nil and a.p != b.p:
+    `=destroy`(a)
   a.len = b.len
-  a.cap = b.cap
-  a.data = b.data
-
-proc resize[T](s: var seq[T]) =
-  let old = s.cap
-  if old == 0: s.cap = 8
-  else: s.cap = (s.cap * 3) shr 1
-  s.data = cast[type(s.data)](realloc(s.data, old * sizeof(T), s.cap * sizeof(T)))
-
-proc reserveSlot[T](x: var seq[T]): ptr T =
-  if x.len >= x.cap: resize(x)
-  result = addr(x.data[x.len])
-  inc x.len
-
-template add*[T](x: var seq[T]; y: T) =
-  reserveSlot(x)[] = y
-
-proc shrink*[T](x: var seq[T]; newLen: int) =
-  assert newLen <= x.len
-  assert newLen >= 0
+  a.p = b.p
+
+when false:
+  proc incrSeqV3(s: PGenericSeq, typ: PNimType): PGenericSeq {.compilerProc.}
+  proc setLengthSeqV2(s: PGenericSeq, typ: PNimType, newLen: int): PGenericSeq {.
+      compilerRtl.}
+  proc newSeq(typ: PNimType, len: int): pointer {.compilerRtl.}
+
+
+type
+  PayloadBase = object
+    cap: int
+    region: Allocator
+
+proc newSeqPayload(cap, elemSize: int): pointer {.compilerRtl.} =
+  # we have to use type erasure here as Nim does not support generic
+  # compilerProcs. Oh well, this will all be inlined anyway.
+  if cap <= 0:
+    let region = getLocalAllocator()
+    var p = cast[ptr PayloadBase](region.alloc(region, cap * elemSize + sizeof(int) + sizeof(Allocator)))
+    p.region = region
+    p.cap = cap
+    result = p
+  else:
+    result = nil
+
+proc prepareSeqAdd(len: int; p: pointer; addlen, elemSize: int): pointer {.compilerRtl.} =
+  if len+addlen <= len:
+    result = p
+  elif p == nil:
+    result = newSeqPayload(len+addlen, elemSize)
+  else:
+    # Note: this means we cannot support things that have internal pointers as
+    # they get reallocated here. This needs to be documented clearly.
+    var p = cast[ptr PayloadBase](p)
+    let region = if p.region == nil: getLocalAllocator() else: p.region
+    let cap = max(resize(p.cap), len+addlen)
+    var q = cast[ptr PayloadBase](region.realloc(region, p,
+      sizeof(int) + sizeof(Allocator) + elemSize * p.cap,
+      sizeof(int) + sizeof(Allocator) + elemSize * cap))
+    q.region = region
+    q.cap = cap
+    result = q
+
+proc shrink*[T](x: var seq[T]; newLen: Natural) =
+  sysAssert newLen <= x.len, "invalid newLen parameter for 'shrink'"
   when not supportsCopyMem(T):
     for i in countdown(x.len - 1, newLen - 1):
-      `=destroy`(x.data[i])
-  x.len = newLen
-
-proc grow*[T](x: var seq[T]; newLen: int; value: T) =
-  if newLen <= x.len: return
-  assert newLen >= 0
-  if x.cap == 0: x.cap = newLen
-  else: x.cap = max(newLen, (x.cap * 3) shr 1)
-  x.data = cast[type(x.data)](realloc(x.data, x.cap * sizeof(T)))
-  for i in x.len..<newLen:
+      `=destroy`(x[i])
+
+  cast[ptr NimSeqV2[T]](addr x).len = newLen
+
+proc grow*[T](x: var seq[T]; newLen: Natural; value: T) =
+  let oldLen = x.len
+  if newLen <= oldLen: return
+  var xu = cast[ptr NimSeqV2[T]](addr x)
+
+  xu.p = prepareSeqAdd(oldLen, xu.p, newLen - oldLen, sizeof(T))
+  xu.len = newLen
+  for i in oldLen .. newLen-1:
     x.data[i] = value
-  x.len = newLen
-
-template default[T](t: typedesc[T]): T =
-  var v: T
-  v
-
-proc setLen*[T](x: var seq[T]; newLen: int) {.deprecated.} =
-  if newlen < x.len: shrink(x, newLen)
-  else: grow(x, newLen, default(T))
-
-template `[]`*[T](x: seq[T]; i: Natural): T =
-  assert i < x.len
-  x.data[i]
-
-template `[]=`*[T](x: seq[T]; i: Natural; y: T) =
-  assert i < x.len
-  x.data[i] = y
-
-proc `@`*[T](elems: openArray[T]): seq[T] =
-  result.cap = elems.len
-  result.len = elems.len
-  result.data = cast[type(result.data)](alloc(result.cap * sizeof(T)))
-  when supportsCopyMem(T):
-    copyMem(result.data, unsafeAddr(elems[0]), result.cap * sizeof(T))
+
+proc setLen[T](s: var seq[T], newlen: Natural) =
+  if newlen < s.len:
+    shrink(s, newLen)
   else:
-    for i in 0..<result.len:
-      result.data[i] = elems[i]
-
-proc len*[T](x: seq[T]): int {.inline.} = x.len
-
-proc `$`*[T](x: seq[T]): string =
-  result = "@["
-  var firstElement = true
-  for i in 0..<x.len:
-    let
-      value = x.data[i]
-    if firstElement:
-      firstElement = false
-    else:
-      result.add(", ")
-
-    when compiles(value.isNil):
-      # this branch should not be necessary
-      if value.isNil:
-        result.add "nil"
-      else:
-        result.addQuoted(value)
+    var v: T # get the default value of 'v'
+    grow(s, newLen, v)
+
+when false:
+  proc resize[T](s: var NimSeqV2[T]) =
+    let old = s.cap
+    if old == 0: s.cap = 8
+    else: s.cap = (s.cap * 3) shr 1
+    s.data = cast[type(s.data)](realloc(s.data, old * sizeof(T), s.cap * sizeof(T)))
+
+  proc reserveSlot[T](x: var NimSeqV2[T]): ptr T =
+    if x.len >= x.cap: resize(x)
+    result = addr(x.data[x.len])
+    inc x.len
+
+  template add*[T](x: var NimSeqV2[T]; y: T) =
+    reserveSlot(x)[] = y
+
+  template `[]`*[T](x: NimSeqV2[T]; i: Natural): T =
+    assert i < x.len
+    x.data[i]
+
+  template `[]=`*[T](x: NimSeqV2[T]; i: Natural; y: T) =
+    assert i < x.len
+    x.data[i] = y
+
+  proc `@`*[T](elems: openArray[T]): NimSeqV2[T] =
+    result.cap = elems.len
+    result.len = elems.len
+    result.data = cast[type(result.data)](alloc(result.cap * sizeof(T)))
+    when supportsCopyMem(T):
+      copyMem(result.data, unsafeAddr(elems[0]), result.cap * sizeof(T))
     else:
-      result.addQuoted(value)
-
-  result.add("]")
+      for i in 0..<result.len:
+        result.data[i] = elems[i]
diff --git a/lib/core/strs.nim b/lib/core/strs.nim
index ff38aef1d..186add52a 100644
--- a/lib/core/strs.nim
+++ b/lib/core/strs.nim
@@ -7,104 +7,166 @@
 #    distribution, for details about the copyright.
 #
 
-## Default string implementation used by Nim's core.
+## Default new string implementation used by Nim's core.
+
+when false:
+  # these are to be implemented or changed in the code generator.
+
+  #proc rawNewStringNoInit(space: int): NimString {.compilerProc.}
+  # seems to be unused.
+  proc copyDeepString(src: NimString): NimString {.inline.}
+  # ----------------- sequences ----------------------------------------------
+
+  proc incrSeqV3(s: PGenericSeq, typ: PNimType): PGenericSeq {.compilerProc.}
+  proc setLengthSeqV2(s: PGenericSeq, typ: PNimType, newLen: int): PGenericSeq {.
+      compilerRtl.}
+  proc newSeq(typ: PNimType, len: int): pointer {.compilerRtl.}
+  proc newSeqRC1(typ: PNimType, len: int): pointer {.compilerRtl.}
 
 import allocators
 
 type
-  string {.core, exportc: "NimStringV2".} = object
-    len, cap: int
-    data: ptr UncheckedArray[char]
+  NimStrPayload {.core.} = object
+    cap: int
+    region: Allocator
+    data: UncheckedArray[char]
+
+  NimStringV2 {.core.} = object
+    len: int
+    p: ptr NimStrPayload ## can be nil if len == 0.
 
 const nimStrVersion {.core.} = 2
 
-template frees(s) = dealloc(s.data, s.cap + 1)
+template isLiteral(s): bool = s.p == nil or s.p.region == nil
+
+template contentSize(cap): int = cap + 1 + sizeof(int) + sizeof(Allocator)
+
+template frees(s) =
+  if not isLiteral(s):
+    s.p.region.dealloc(s.p.region, s.p, contentSize(s.p.cap))
 
 proc `=destroy`(s: var string) =
-  if s.data != nil:
-    frees(s)
-    s.data = nil
-    s.len = 0
-    s.cap = 0
+  var a = cast[ptr NimStringV2](addr s)
+  frees(a)
+  a.len = 0
+  a.p = nil
+
+template lose(a) =
+  frees(a)
 
-proc `=sink`(a: var string, b: string) =
+proc `=sink`(x: var string, y: string) =
+  var a = cast[ptr NimStringV2](addr x)
+  var b = cast[ptr NimStringV2](unsafeAddr y)
   # we hope this is optimized away for not yet alive objects:
-  if a.data != nil and a.data != b.data:
-    frees(a)
+  if unlikely(a.p == b.p): return
+  lose(a)
   a.len = b.len
-  a.cap = b.cap
-  a.data = b.data
+  a.p = b.p
 
-proc `=`(a: var string; b: string) =
-  if a.data != nil and a.data != b.data:
-    frees(a)
-    a.data = nil
+proc `=`(x: var string, y: string) =
+  var a = cast[ptr NimStringV2](addr x)
+  var b = cast[ptr NimStringV2](unsafeAddr y)
+  if unlikely(a.p == b.p): return
+  lose(a)
   a.len = b.len
-  a.cap = b.cap
-  if b.data != nil:
-    a.data = cast[type(a.data)](alloc(a.cap + 1))
-    copyMem(a.data, b.data, a.cap+1)
-
-proc resize(s: var string) =
-  let old = s.cap
-  if old == 0: s.cap = 8
-  else: s.cap = (s.cap * 3) shr 1
-  s.data = cast[type(s.data)](realloc(s.data, old + 1, s.cap + 1))
-
-proc add*(s: var string; c: char) =
-  if s.len >= s.cap: resize(s)
-  s.data[s.len] = c
-  s.data[s.len+1] = '\0'
+  if isLiteral(b):
+    # we can shallow copy literals:
+    a.p = b.p
+  else:
+    let region = if a.p.region != nil: a.p.region else: getLocalAllocator()
+    # we have to allocate the 'cap' here, consider
+    # 'let y = newStringOfCap(); var x = y'
+    # on the other hand... These get turned into moves now.
+    a.p = cast[ptr NimStrPayload](region.alloc(region, contentSize(b.len)))
+    a.p.region = region
+    a.p.cap = b.len
+    copyMem(unsafeAddr a.p.data[0], unsafeAddr b.p.data[0], b.len+1)
+
+proc resize(old: int): int {.inline.} =
+  if old <= 0: result = 4
+  elif old < 65536: result = old * 2
+  else: result = old * 3 div 2 # for large arrays * 3/2 is better
+
+proc prepareAdd(s: var NimStringV2; addlen: int) {.compilerRtl.} =
+  if isLiteral(s):
+    let oldP = s.p
+    # can't mutate a literal, so we need a fresh copy here:
+    let region = getLocalAllocator()
+    s.p = cast[ptr NimStrPayload](region.alloc(region, contentSize(s.len + addlen)))
+    s.p.region = region
+    s.p.cap = s.len + addlen
+    if s.len > 0:
+      # we are about to append, so there is no need to copy the \0 terminator:
+      copyMem(unsafeAddr s.p.data[0], unsafeAddr oldP.data[0], s.len)
+  elif s.len + addlen > s.p.cap:
+    let cap = max(s.len + addlen, resize(s.p.cap))
+    s.p = cast[ptr NimStrPayload](s.p.region.realloc(s.p.region, s.p,
+      oldSize = contentSize(s.p.cap),
+      newSize = contentSize(cap)))
+    s.p.cap = cap
+
+proc nimAddCharV1(s: var NimStringV2; c: char) {.compilerRtl.} =
+  prepareAdd(s, 1)
+  s.p.data[s.len] = c
+  s.p.data[s.len+1] = '\0'
   inc s.len
 
-proc ensure(s: var string; newLen: int) =
-  let old = s.cap
-  if newLen >= old:
-    s.cap = max((old * 3) shr 1, newLen)
-    if s.cap > 0:
-      s.data = cast[type(s.data)](realloc(s.data, old + 1, s.cap + 1))
-
-proc add*(s: var string; y: string) =
-  if y.len != 0:
-    let newLen = s.len + y.len
-    ensure(s, newLen)
-    copyMem(addr s.data[len], y.data, y.data.len + 1)
+proc toNimStr(str: cstring, len: int): NimStringV2 {.compilerProc.} =
+  if len <= 0:
+    result = NimStringV2(len: 0, p: nil)
+  else:
+    let region = getLocalAllocator()
+    var p = cast[ptr NimStrPayload](region.alloc(region, contentSize(len)))
+    p.region = region
+    p.cap = len
+    if len > 0:
+      # we are about to append, so there is no need to copy the \0 terminator:
+      copyMem(unsafeAddr p.data[0], str, len)
+    result = NimStringV2(len: 0, p: p)
+
+proc cstrToNimstr(str: cstring): NimStringV2 {.compilerRtl.} =
+  if str == nil: toNimStr(str, 0)
+  else: toNimStr(str, str.len)
+
+proc nimToCStringConv(s: NimStringV2): cstring {.compilerProc, inline.} =
+  if s.len == 0: result = cstring""
+  else: result = cstring(unsafeAddr s.p.data)
+
+proc appendString(dest: var NimStringV2; src: NimStringV2) {.compilerproc, inline.} =
+  if src.len > 0:
+    # also copy the \0 terminator:
+    copyMem(unsafeAddr dest.p.data[dest.len], unsafeAddr src.p.data[0], src.len+1)
+
+proc appendChar(dest: var NimStringV2; c: char) {.compilerproc, inline.} =
+  dest.p.data[dest.len] = c
+  dest.p.data[dest.len+1] = '\0'
+  inc dest.len
+
+proc rawNewString(space: int): NimStringV2 {.compilerProc.} =
+  # this is also 'system.newStringOfCap'.
+  if space <= 0:
+    result = NimStringV2(len: 0, p: nil)
+  else:
+    let region = getLocalAllocator()
+    var p = cast[ptr NimStrPayload](region.alloc(region, contentSize(space)))
+    p.region = region
+    p.cap = space
+    result = NimStringV2(len: 0, p: p)
+
+proc mnewString(len: int): NimStringV2 {.compilerProc.} =
+  if len <= 0:
+    result = NimStringV2(len: 0, p: nil)
+  else:
+    let region = getLocalAllocator()
+    var p = cast[ptr NimStrPayload](region.alloc(region, contentSize(len)))
+    p.region = region
+    p.cap = len
+    result = NimStringV2(len: len, p: p)
+
+proc setLengthStrV2(s: var NimStringV2, newLen: int) {.compilerRtl.} =
+  if newLen > s.len:
+    prepareAdd(s, newLen - s.len)
+  else:
     s.len = newLen
-
-proc len*(s: string): int {.inline.} = s.len
-
-proc newString*(len: int): string =
-  result.len = len
-  result.cap = len
-  if len > 0:
-    result.data = alloc0(len+1)
-
-converter toCString(x: string): cstring {.core, inline.} =
-  if x.len == 0: cstring"" else: cast[cstring](x.data)
-
-proc newStringOfCap*(cap: int): string =
-  result.len = 0
-  result.cap = cap
-  if cap > 0:
-    result.data = alloc(cap+1)
-
-proc `&`*(a, b: string): string =
-  let sum = a.len + b.len
-  result = newStringOfCap(sum)
-  result.len = sum
-  copyMem(addr result.data[0], a.data, a.len)
-  copyMem(addr result.data[a.len], b.data, b.len)
-  if sum > 0:
-    result.data[sum] = '\0'
-
-proc concat(x: openArray[string]): string {.core.} =
-  ## used be the code generator to optimize 'x & y & z ...'
-  var sum = 0
-  for i in 0 ..< x.len: inc(sum, x[i].len)
-  result = newStringOfCap(sum)
-  sum = 0
-  for i in 0 ..< x.len:
-    let L = x[i].len
-    copyMem(addr result.data[sum], x[i].data, L)
-    inc(sum, L)
-
+    # this also only works because the destructor
+    # looks at s.p and not s.len
diff --git a/lib/js/asyncjs.nim b/lib/js/asyncjs.nim
index 894102ca0..7439b66e1 100644
--- a/lib/js/asyncjs.nim
+++ b/lib/js/asyncjs.nim
@@ -92,7 +92,10 @@ proc isFutureVoid(node: NimNode): bool =
            node[1].kind == nnkIdent and $node[1] == "void"
 
 proc generateJsasync(arg: NimNode): NimNode =
-  assert arg.kind == nnkProcDef
+  if arg.kind notin {nnkProcDef, nnkLambda, nnkMethodDef, nnkDo}:
+      error("Cannot transform this node kind into an async proc." &
+            " proc/method definition or lambda node expected.")
+
   result = arg
   var isVoid = false
   let jsResolve = ident("jsResolve")
@@ -108,7 +111,7 @@ proc generateJsasync(arg: NimNode): NimNode =
 
   if len(code) > 0:
     var awaitFunction = quote:
-      proc await[T](f: Future[T]): T {.importcpp: "(await #)".}
+      proc await[T](f: Future[T]): T {.importcpp: "(await #)", used.}
     result.body.add(awaitFunction)
 
     var resolve: NimNode
@@ -117,7 +120,7 @@ proc generateJsasync(arg: NimNode): NimNode =
         var `jsResolve` {.importcpp: "undefined".}: Future[void]
     else:
       resolve = quote:
-        proc jsResolve[T](a: T): Future[T] {.importcpp: "#".}
+        proc jsResolve[T](a: T): Future[T] {.importcpp: "#", used.}
     result.body.add(resolve)
   else:
     result.body = newEmptyNode()
@@ -137,7 +140,12 @@ proc generateJsasync(arg: NimNode): NimNode =
 macro async*(arg: untyped): untyped =
   ## Macro which converts normal procedures into
   ## javascript-compatible async procedures
-  generateJsasync(arg)
+  if arg.kind == nnkStmtList:
+    result = newStmtList()
+    for oneProc in arg:
+      result.add generateJsasync(oneProc)
+  else:
+    result = generateJsasync(arg)
 
 proc newPromise*[T](handler: proc(resolve: proc(response: T))): Future[T] {.importcpp: "(new Promise(#))".}
   ## A helper for wrapping callback-based functions
diff --git a/lib/js/dom.nim b/lib/js/dom.nim
index fd81fdf3f..cf219df3d 100644
--- a/lib/js/dom.nim
+++ b/lib/js/dom.nim
@@ -201,7 +201,7 @@ type
     vspace*: int
     width*: int
 
-  Style = ref StyleObj
+  Style* = ref StyleObj
   StyleObj {.importc.} = object of RootObj
     background*: cstring
     backgroundAttachment*: cstring
diff --git a/lib/nimbase.h b/lib/nimbase.h
index 84972fcb0..507108712 100644
--- a/lib/nimbase.h
+++ b/lib/nimbase.h
@@ -107,6 +107,8 @@ __clang__
 #  define N_INLINE(rettype, name) rettype __inline name
 #endif
 
+#define N_INLINE_PTR(rettype, name) rettype (*name)
+
 #if defined(__POCC__)
 #  define NIM_CONST /* PCC is really picky with const modifiers */
 #  undef _MSC_VER /* Yeah, right PCC defines _MSC_VER even if it is
diff --git a/lib/packages/docutils/highlite.nim b/lib/packages/docutils/highlite.nim
index fbd2d7eca..4d444603e 100644
--- a/lib/packages/docutils/highlite.nim
+++ b/lib/packages/docutils/highlite.nim
@@ -881,7 +881,7 @@ when isMainModule:
       break
     except:
       echo filename, " not found"
-  doAssert(not keywords.isNil, "Couldn't read any keywords.txt file!")
+  doAssert(keywords.len > 0, "Couldn't read any keywords.txt file!")
   for i in 0..min(keywords.len, nimKeywords.len)-1:
     doAssert keywords[i] == nimKeywords[i], "Unexpected keyword"
   doAssert keywords.len == nimKeywords.len, "No matching lengths"
diff --git a/lib/packages/docutils/rst.nim b/lib/packages/docutils/rst.nim
index 7ee071c79..d35f109e7 100644
--- a/lib/packages/docutils/rst.nim
+++ b/lib/packages/docutils/rst.nim
@@ -1387,7 +1387,7 @@ proc parseSectionWrapper(p: var RstParser): PRstNode =
     result = result.sons[0]
 
 proc `$`(t: Token): string =
-  result = $t.kind & ' ' & (if isNil(t.symbol): "NIL" else: t.symbol)
+  result = $t.kind & ' ' & t.symbol
 
 proc parseDoc(p: var RstParser): PRstNode =
   result = parseSectionWrapper(p)
diff --git a/lib/packages/docutils/rstgen.nim b/lib/packages/docutils/rstgen.nim
index 5b0b6c6ee..51bb9c757 100644
--- a/lib/packages/docutils/rstgen.nim
+++ b/lib/packages/docutils/rstgen.nim
@@ -85,8 +85,8 @@ proc init(p: var CodeBlockParams) =
 proc initRstGenerator*(g: var RstGenerator, target: OutputTarget,
                        config: StringTableRef, filename: string,
                        options: RstParseOptions,
-                       findFile: FindFileHandler=nil,
-                       msgHandler: MsgHandler=nil) =
+                       findFile: FindFileHandler = nil,
+                       msgHandler: MsgHandler = nil) =
   ## Initializes a ``RstGenerator``.
   ##
   ## You need to call this before using a ``RstGenerator`` with any other
@@ -243,7 +243,7 @@ proc dispA(target: OutputTarget, dest: var string,
   else: addf(dest, tex, args)
 
 proc `or`(x, y: string): string {.inline.} =
-  result = if x.isNil: y else: x
+  result = if x.len == 0: y else: x
 
 proc renderRstToOut*(d: var RstGenerator, n: PRstNode, result: var string)
   ## Writes into ``result`` the rst ast ``n`` using the ``d`` configuration.
@@ -255,9 +255,9 @@ proc renderRstToOut*(d: var RstGenerator, n: PRstNode, result: var string)
   ## .. code-block:: nim
   ##
   ##   # ...configure gen and rst vars...
-  ##   var generatedHTML = ""
-  ##   renderRstToOut(gen, rst, generatedHTML)
-  ##   echo generatedHTML
+  ##   var generatedHtml = ""
+  ##   renderRstToOut(gen, rst, generatedHtml)
+  ##   echo generatedHtml
 
 proc renderAux(d: PDoc, n: PRstNode, result: var string) =
   for i in countup(0, len(n)-1): renderRstToOut(d, n.sons[i], result)
@@ -282,20 +282,26 @@ proc quoteIndexColumn(text: string): string =
   ## * ``"\\"`` => ``"\\\\"``
   ## * ``"\n"`` => ``"\\n"``
   ## * ``"\t"`` => ``"\\t"``
-  result = text.replace("\\", "\\\\").replace("\n", "\\n").replace("\t", "\\t")
+  result = newStringOfCap(text.len + 3)
+  for c in text:
+    case c
+    of '\\': result.add "\\"
+    of '\L': result.add "\\n"
+    of '\C': discard
+    of '\t': result.add "\\t"
+    else: result.add c
 
 proc unquoteIndexColumn(text: string): string =
   ## Returns the unquoted version generated by ``quoteIndexColumn``.
-  result = text.replace("\\t", "\t").replace("\\n", "\n").replace("\\\\", "\\")
+  result = text.multiReplace(("\\t", "\t"), ("\\n", "\n"), ("\\\\", "\\"))
 
-proc setIndexTerm*(d: var RstGenerator, id, term: string,
+proc setIndexTerm*(d: var RstGenerator, htmlFile, id, term: string,
                    linkTitle, linkDesc = "") =
   ## Adds a `term` to the index using the specified hyperlink identifier.
   ##
   ## A new entry will be added to the index using the format
-  ## ``term<tab>file#id``. The file part will come from the `filename`
-  ## parameter used in a previous call to the `initRstGenerator()
-  ## <#initRstGenerator>`_ proc.
+  ## ``term<tab>file#id``. The file part will come from the `htmlFile`
+  ## parameter.
   ##
   ## The `id` will be appended with a hash character only if its length is not
   ## zero, otherwise no specific anchor will be generated. In general you
@@ -316,7 +322,6 @@ proc setIndexTerm*(d: var RstGenerator, id, term: string,
     entry = term
     isTitle = false
   entry.add('\t')
-  let htmlFile = changeFileExt(extractFilename(d.filename), HtmlExt)
   entry.add(htmlFile)
   if id.len > 0:
     entry.add('#')
@@ -356,7 +361,7 @@ proc renderIndexTerm*(d: PDoc, n: PRstNode, result: var string) =
 
   var term = ""
   renderAux(d, n, term)
-  setIndexTerm(d, id, term, d.currentSection)
+  setIndexTerm(d, changeFileExt(extractFilename(d.filename), HtmlExt), id, term, d.currentSection)
   dispA(d.target, result, "<span id=\"$1\">$2</span>", "$2\\label{$1}",
         [id, term])
 
@@ -364,15 +369,15 @@ type
   IndexEntry = object
     keyword: string
     link: string
-    linkTitle: string ## If not nil, contains a prettier text for the href
-    linkDesc: string ## If not nil, the title attribute of the final href
+    linkTitle: string ## contains a prettier text for the href
+    linkDesc: string ## the title attribute of the final href
 
   IndexedDocs = Table[IndexEntry, seq[IndexEntry]] ## \
     ## Contains the index sequences for doc types.
     ##
     ## The key is a *fake* IndexEntry which will contain the title of the
     ## document in the `keyword` field and `link` will contain the html
-    ## filename for the document. `linkTitle` and `linkDesc` will be nil.
+    ## filename for the document. `linkTitle` and `linkDesc` will be empty.
     ##
     ## The value indexed by this IndexEntry is a sequence with the real index
     ## entries found in the ``.idx`` file.
@@ -387,20 +392,16 @@ proc hash(x: IndexEntry): Hash =
   ## Returns the hash for the combined fields of the type.
   ##
   ## The hash is computed as the chained hash of the individual string hashes.
-  assert(not x.keyword.isNil)
-  assert(not x.link.isNil)
   result = x.keyword.hash !& x.link.hash
-  result = result !& (x.linkTitle or "").hash
-  result = result !& (x.linkDesc or "").hash
+  result = result !& x.linkTitle.hash
+  result = result !& x.linkDesc.hash
   result = !$result
 
 proc `<-`(a: var IndexEntry, b: IndexEntry) =
   shallowCopy a.keyword, b.keyword
   shallowCopy a.link, b.link
-  if b.linkTitle.isNil: a.linkTitle = ""
-  else: shallowCopy a.linkTitle, b.linkTitle
-  if b.linkDesc.isNil: a.linkDesc = ""
-  else: shallowCopy a.linkDesc, b.linkDesc
+  shallowCopy a.linkTitle, b.linkTitle
+  shallowCopy a.linkDesc, b.linkDesc
 
 proc sortIndex(a: var openArray[IndexEntry]) =
   # we use shellsort here; fast and simple
@@ -437,15 +438,15 @@ proc generateSymbolIndex(symbols: seq[IndexEntry]): string =
   var i = 0
   while i < symbols.len:
     let keyword = symbols[i].keyword
-    let cleaned_keyword = keyword.escapeLink
+    let cleanedKeyword = keyword.escapeLink
     result.addf("<dt><a name=\"$2\" href=\"#$2\"><span>$1:</span></a></dt><dd><ul class=\"simple\">\n",
-                [keyword, cleaned_keyword])
+                [keyword, cleanedKeyword])
     var j = i
     while j < symbols.len and keyword == symbols[j].keyword:
       let
-        url = symbols[j].link.escapeLink
-        text = if not symbols[j].linkTitle.isNil: symbols[j].linkTitle else: url
-        desc = if not symbols[j].linkDesc.isNil: symbols[j].linkDesc else: ""
+        url = symbols[j].link #.escapeLink
+        text = if symbols[j].linkTitle.len > 0: symbols[j].linkTitle else: url
+        desc = if symbols[j].linkDesc.len > 0: symbols[j].linkDesc else: ""
       if desc.len > 0:
         result.addf("""<li><a class="reference external"
           title="$3" data-doc-search-tag="$2" href="$1">$2</a></li>
@@ -466,12 +467,12 @@ proc isDocumentationTitle(hyperlink: string): bool =
   ## for a more detailed explanation.
   result = hyperlink.find('#') < 0
 
-proc stripTOCLevel(s: string): tuple[level: int, text: string] =
+proc stripTocLevel(s: string): tuple[level: int, text: string] =
   ## Returns the *level* of the toc along with the text without it.
-  for c in 0 .. <s.len:
+  for c in 0 ..< s.len:
     result.level = c
     if s[c] != ' ': break
-  result.text = s[result.level .. <s.len]
+  result.text = s[result.level ..< s.len]
 
 proc indentToLevel(level: var int, newLevel: int): string =
   ## Returns the sequence of <ul>|</ul> characters to switch to `newLevel`.
@@ -487,7 +488,7 @@ proc indentToLevel(level: var int, newLevel: int): string =
     result = repeat("</ul></li>", level - newLevel)
   level = newLevel
 
-proc generateDocumentationTOC(entries: seq[IndexEntry]): string =
+proc generateDocumentationToc(entries: seq[IndexEntry]): string =
   ## Returns the sequence of index entries in an HTML hierarchical list.
   result = ""
   # Build a list of levels and extracted titles to make processing easier.
@@ -499,7 +500,7 @@ proc generateDocumentationTOC(entries: seq[IndexEntry]): string =
     level = 1
   levels.newSeq(entries.len)
   for entry in entries:
-    let (rawLevel, rawText) = stripTOCLevel(entry.linkTitle or entry.keyword)
+    let (rawLevel, rawText) = stripTocLevel(entry.linkTitle or entry.keyword)
     if rawLevel < 1:
       # This is a normal symbol, push it *inside* one level from the last one.
       levels[L].level = level + 1
@@ -523,13 +524,11 @@ proc generateDocumentationTOC(entries: seq[IndexEntry]): string =
       titleTag = levels[L].text
     else:
       result.add(level.indentToLevel(levels[L].level))
-      result.addf("""<li><a class="reference" data-doc-search-tag="$1" href="$2">
+      result.addf("""<li><a class="reference" data-doc-search-tag="$1: $2" href="$3">
         $3</a></li>
-        """, [titleTag & " : " & levels[L].text, link, levels[L].text])
+        """, [titleTag, levels[L].text, link, levels[L].text])
     inc L
   result.add(level.indentToLevel(1) & "</ul>\n")
-  assert(not titleRef.isNil,
-    "Can't use this proc on an API index, docs always have a title entry")
 
 proc generateDocumentationIndex(docs: IndexedDocs): string =
   ## Returns all the documentation TOCs in an HTML hierarchical list.
@@ -540,7 +539,7 @@ proc generateDocumentationIndex(docs: IndexedDocs): string =
   sort(titles, cmp)
 
   for title in titles:
-    let tocList = generateDocumentationTOC(docs.getOrDefault(title))
+    let tocList = generateDocumentationToc(docs.getOrDefault(title))
     result.add("<ul><li><a href=\"" &
       title.link & "\">" & title.keyword & "</a>\n" & tocList & "</li></ul>\n")
 
@@ -581,8 +580,8 @@ proc readIndexDir(dir: string):
   setLen(result.symbols, 0)
   var L = 0
   # Scan index files and build the list of symbols.
-  for kind, path in walkDir(dir):
-    if kind == pcFile and path.endsWith(IndexExt):
+  for path in walkDirRec(dir):
+    if path.endsWith(IndexExt):
       var
         fileEntries: seq[IndexEntry]
         title: IndexEntry
@@ -596,7 +595,7 @@ proc readIndexDir(dir: string):
         fileEntries[F].keyword = line.substr(0, s-1)
         fileEntries[F].link = line.substr(s+1)
         # See if we detect a title, a link without a `#foobar` trailing part.
-        if title.keyword.isNil and fileEntries[F].link.isDocumentationTitle:
+        if title.keyword.len == 0 and fileEntries[F].link.isDocumentationTitle:
           title.keyword = fileEntries[F].keyword
           title.link = fileEntries[F].link
 
@@ -611,17 +610,24 @@ proc readIndexDir(dir: string):
           fileEntries[F].linkDesc = ""
         inc F
       # Depending on type add this to the list of symbols or table of APIs.
-      if title.keyword.isNil:
-        for i in 0 .. <F:
+      if title.keyword.len == 0:
+        for i in 0 ..< F:
           # Don't add to symbols TOC entries (they start with a whitespace).
           let toc = fileEntries[i].linkTitle
-          if not toc.isNil and toc.len > 0 and toc[0] == ' ':
+          if toc.len > 0 and toc[0] == ' ':
             continue
           # Ok, non TOC entry, add it.
           setLen(result.symbols, L + 1)
           result.symbols[L] = fileEntries[i]
           inc L
-        result.modules.add(path.splitFile.name)
+        if fileEntries.len > 0:
+          var x = fileEntries[0].link
+          let i = find(x, '#')
+          if i > 0:
+            x = x.substr(0, i-1)
+          if i != 0:
+            # don't add entries starting with '#'
+            result.modules.add(x.changeFileExt(""))
       else:
         # Generate the symbolic anchor for index quickjumps.
         title.linkTitle = "doc_toc_" & $result.docs.len
@@ -668,10 +674,11 @@ proc mergeIndexes*(dir: string): string =
     result.add(generateModuleJumps(modules))
     result.add("<p />")
 
-  # Generate the HTML block with API documents.
-  if docs.len > 0:
-    result.add("<h2>Documentation files</h2>\n")
-    result.add(generateDocumentationIndex(docs))
+  when false:
+    # Generate the HTML block with API documents.
+    if docs.len > 0:
+      result.add("<h2>Documentation files</h2>\n")
+      result.add(generateDocumentationIndex(docs))
 
   # Generate the HTML block with symbols.
   if symbols.len > 0:
@@ -682,7 +689,7 @@ proc mergeIndexes*(dir: string): string =
 
 # ----------------------------------------------------------------------------
 
-proc stripTOCHTML(s: string): string =
+proc stripTocHtml(s: string): string =
   ## Ugly quick hack to remove HTML tags from TOC titles.
   ##
   ## A TocEntry.header field already contains rendered HTML tags. Instead of
@@ -730,7 +737,7 @@ proc renderHeadline(d: PDoc, n: PRstNode, result: var string) =
 
   # Generate index entry using spaces to indicate TOC level for the output HTML.
   assert n.level >= 0
-  setIndexTerm(d, refname, tmp.stripTOCHTML,
+  setIndexTerm(d, changeFileExt(extractFilename(d.filename), HtmlExt), refname, tmp.stripTocHtml,
     spaces(max(0, n.level)) & tmp)
 
 proc renderOverline(d: PDoc, n: PRstNode, result: var string) =
@@ -878,7 +885,7 @@ proc parseCodeBlockParams(d: PDoc, n: PRstNode): CodeBlockParams =
   if result.langStr != "":
     result.lang = getSourceLanguage(result.langStr)
 
-proc buildLinesHTMLTable(d: PDoc; params: CodeBlockParams, code: string):
+proc buildLinesHtmlTable(d: PDoc; params: CodeBlockParams, code: string):
     tuple[beginTable, endTable: string] =
   ## Returns the necessary tags to start/end a code block in HTML.
   ##
@@ -928,7 +935,7 @@ proc renderCodeBlock(d: PDoc, n: PRstNode, result: var string) =
   if params.testCmd.len > 0 and d.onTestSnippet != nil:
     d.onTestSnippet(d, params.filename, params.testCmd, params.status, m.text)
 
-  let (blockStart, blockEnd) = buildLinesHTMLTable(d, params, m.text)
+  let (blockStart, blockEnd) = buildLinesHtmlTable(d, params, m.text)
 
   dispA(d.target, result, blockStart, "\\begin{rstpre}\n", [])
   if params.lang == langNone:
diff --git a/lib/posix/posix_linux_amd64_consts.nim b/lib/posix/posix_linux_amd64_consts.nim
index ee4fac1e8..50b227635 100644
--- a/lib/posix/posix_linux_amd64_consts.nim
+++ b/lib/posix/posix_linux_amd64_consts.nim
@@ -300,7 +300,7 @@ const IPPROTO_TCP* = cint(6)
 const IPPROTO_UDP* = cint(17)
 const INADDR_ANY* = InAddrScalar(0)
 const INADDR_LOOPBACK* = InAddrScalar(2130706433)
-const INADDR_BROADCAST* = InAddrScalar(-1)
+const INADDR_BROADCAST* = InAddrScalar(4294967295)
 const INET_ADDRSTRLEN* = cint(16)
 const INET6_ADDRSTRLEN* = cint(46)
 const IPV6_JOIN_GROUP* = cint(20)
diff --git a/lib/pure/asyncdispatch.nim b/lib/pure/asyncdispatch.nim
index dfc7201b8..820f34703 100644
--- a/lib/pure/asyncdispatch.nim
+++ b/lib/pure/asyncdispatch.nim
@@ -10,6 +10,7 @@
 include "system/inclrtl"
 
 import os, tables, strutils, times, heapqueue, lists, options, asyncstreams
+import options, math
 import asyncfutures except callSoon
 
 import nativesockets, net, deques
@@ -157,9 +158,6 @@ export asyncfutures, asyncstreams
 ## ----------------
 ##
 ## * The effect system (``raises: []``) does not work with async procedures.
-## * Can't await in a ``except`` body
-## * Forward declarations for async procs are broken,
-##   link includes workaround: https://github.com/nim-lang/Nim/issues/3182.
 
 # TODO: Check if yielded future is nil and throw a more meaningful exception
 
@@ -168,8 +166,10 @@ type
     timers*: HeapQueue[tuple[finishAt: float, fut: Future[void]]]
     callbacks*: Deque[proc ()]
 
-proc processTimers(p: PDispatcherBase; didSomeWork: var bool) {.inline.} =
-  #Process just part if timers at a step
+proc processTimers(
+  p: PDispatcherBase, didSomeWork: var bool
+): Option[int] {.inline.} =
+  # Pop the timers in the order in which they will expire (smaller `finishAt`).
   var count = p.timers.len
   let t = epochTime()
   while count > 0 and t >= p.timers[0].finishAt:
@@ -177,22 +177,25 @@ proc processTimers(p: PDispatcherBase; didSomeWork: var bool) {.inline.} =
     dec count
     didSomeWork = true
 
+  # Return the number of miliseconds in which the next timer will expire.
+  if p.timers.len == 0: return
+
+  let milisecs = (p.timers[0].finishAt - epochTime()) * 1000
+  return some(ceil(milisecs).int)
+
 proc processPendingCallbacks(p: PDispatcherBase; didSomeWork: var bool) =
   while p.callbacks.len > 0:
     var cb = p.callbacks.popFirst()
     cb()
     didSomeWork = true
 
-proc adjustedTimeout(p: PDispatcherBase, timeout: int): int {.inline.} =
-  # If dispatcher has active timers this proc returns the timeout
-  # of the nearest timer. Returns `timeout` otherwise.
-  result = timeout
-  if p.timers.len > 0:
-    let timerTimeout = p.timers[0].finishAt
-    let curTime = epochTime()
-    if timeout == -1 or (curTime + (timeout / 1000)) > timerTimeout:
-      result = int((timerTimeout - curTime) * 1000)
-      if result < 0: result = 0
+proc adjustTimeout(pollTimeout: int, nextTimer: Option[int]): int {.inline.} =
+  if nextTimer.isNone():
+    return pollTimeout
+
+  result = nextTimer.get()
+  if pollTimeout == -1: return
+  result = min(pollTimeout, result)
 
 proc callSoon(cbproc: proc ()) {.gcsafe.}
 
@@ -299,53 +302,53 @@ when defined(windows) or defined(nimdoc):
         "No handles or timers registered in dispatcher.")
 
     result = false
-    if p.handles.len != 0:
-      let at = p.adjustedTimeout(timeout)
-      var llTimeout =
-        if at == -1: winlean.INFINITE
-        else: at.int32
-
-      var lpNumberOfBytesTransferred: Dword
-      var lpCompletionKey: ULONG_PTR
-      var customOverlapped: PCustomOverlapped
-      let res = getQueuedCompletionStatus(p.ioPort,
-          addr lpNumberOfBytesTransferred, addr lpCompletionKey,
-          cast[ptr POVERLAPPED](addr customOverlapped), llTimeout).bool
-      result = true
-
-      # http://stackoverflow.com/a/12277264/492186
-      # TODO: http://www.serverframework.com/handling-multiple-pending-socket-read-and-write-operations.html
-      if res:
-        # This is useful for ensuring the reliability of the overlapped struct.
+    let nextTimer = processTimers(p, result)
+    let at = adjustTimeout(timeout, nextTimer)
+    var llTimeout =
+      if at == -1: winlean.INFINITE
+      else: at.int32
+
+    var lpNumberOfBytesTransferred: Dword
+    var lpCompletionKey: ULONG_PTR
+    var customOverlapped: PCustomOverlapped
+    let res = getQueuedCompletionStatus(p.ioPort,
+        addr lpNumberOfBytesTransferred, addr lpCompletionKey,
+        cast[ptr POVERLAPPED](addr customOverlapped), llTimeout).bool
+    result = true
+
+    # http://stackoverflow.com/a/12277264/492186
+    # TODO: http://www.serverframework.com/handling-multiple-pending-socket-read-and-write-operations.html
+    if res:
+      # This is useful for ensuring the reliability of the overlapped struct.
+      assert customOverlapped.data.fd == lpCompletionKey.AsyncFD
+
+      customOverlapped.data.cb(customOverlapped.data.fd,
+          lpNumberOfBytesTransferred, OSErrorCode(-1))
+
+      # If cell.data != nil, then system.protect(rawEnv(cb)) was called,
+      # so we need to dispose our `cb` environment, because it is not needed
+      # anymore.
+      if customOverlapped.data.cell.data != nil:
+        system.dispose(customOverlapped.data.cell)
+
+      GC_unref(customOverlapped)
+    else:
+      let errCode = osLastError()
+      if customOverlapped != nil:
         assert customOverlapped.data.fd == lpCompletionKey.AsyncFD
-
         customOverlapped.data.cb(customOverlapped.data.fd,
-            lpNumberOfBytesTransferred, OSErrorCode(-1))
-
-        # If cell.data != nil, then system.protect(rawEnv(cb)) was called,
-        # so we need to dispose our `cb` environment, because it is not needed
-        # anymore.
+            lpNumberOfBytesTransferred, errCode)
         if customOverlapped.data.cell.data != nil:
           system.dispose(customOverlapped.data.cell)
-
         GC_unref(customOverlapped)
       else:
-        let errCode = osLastError()
-        if customOverlapped != nil:
-          assert customOverlapped.data.fd == lpCompletionKey.AsyncFD
-          customOverlapped.data.cb(customOverlapped.data.fd,
-              lpNumberOfBytesTransferred, errCode)
-          if customOverlapped.data.cell.data != nil:
-            system.dispose(customOverlapped.data.cell)
-          GC_unref(customOverlapped)
-        else:
-          if errCode.int32 == WAIT_TIMEOUT:
-            # Timed out
-            result = false
-          else: raiseOSError(errCode)
+        if errCode.int32 == WAIT_TIMEOUT:
+          # Timed out
+          result = false
+        else: raiseOSError(errCode)
 
     # Timer processing.
-    processTimers(p, result)
+    discard processTimers(p, result)
     # Callback queue processing
     processPendingCallbacks(p, result)
 
@@ -1231,48 +1234,48 @@ else:
         "No handles or timers registered in dispatcher.")
 
     result = false
-    if not p.selector.isEmpty():
-      var keys: array[64, ReadyKey]
-      var count = p.selector.selectInto(p.adjustedTimeout(timeout), keys)
-      for i in 0..<count:
-        var custom = false
-        let fd = keys[i].fd
-        let events = keys[i].events
-        var rLength = 0 # len(data.readList) after callback
-        var wLength = 0 # len(data.writeList) after callback
-
-        if Event.Read in events or events == {Event.Error}:
-          processBasicCallbacks(fd, readList)
-          result = true
-
-        if Event.Write in events or events == {Event.Error}:
-          processBasicCallbacks(fd, writeList)
-          result = true
-
-        if Event.User in events:
-          processBasicCallbacks(fd, readList)
+    var keys: array[64, ReadyKey]
+    let nextTimer = processTimers(p, result)
+    var count = p.selector.selectInto(adjustTimeout(timeout, nextTimer), keys)
+    for i in 0..<count:
+      var custom = false
+      let fd = keys[i].fd
+      let events = keys[i].events
+      var rLength = 0 # len(data.readList) after callback
+      var wLength = 0 # len(data.writeList) after callback
+
+      if Event.Read in events or events == {Event.Error}:
+        processBasicCallbacks(fd, readList)
+        result = true
+
+      if Event.Write in events or events == {Event.Error}:
+        processBasicCallbacks(fd, writeList)
+        result = true
+
+      if Event.User in events:
+        processBasicCallbacks(fd, readList)
+        custom = true
+        if rLength == 0:
+          p.selector.unregister(fd)
+        result = true
+
+      when ioselSupportedPlatform:
+        if (customSet * events) != {}:
           custom = true
-          if rLength == 0:
-            p.selector.unregister(fd)
+          processCustomCallbacks(fd)
           result = true
 
-        when ioselSupportedPlatform:
-          if (customSet * events) != {}:
-            custom = true
-            processCustomCallbacks(fd)
-            result = true
-
-        # because state `data` can be modified in callback we need to update
-        # descriptor events with currently registered callbacks.
-        if not custom:
-          var newEvents: set[Event] = {}
-          if rLength != -1 and wLength != -1:
-            if rLength > 0: incl(newEvents, Event.Read)
-            if wLength > 0: incl(newEvents, Event.Write)
-            p.selector.updateHandle(SocketHandle(fd), newEvents)
+      # because state `data` can be modified in callback we need to update
+      # descriptor events with currently registered callbacks.
+      if not custom:
+        var newEvents: set[Event] = {}
+        if rLength != -1 and wLength != -1:
+          if rLength > 0: incl(newEvents, Event.Read)
+          if wLength > 0: incl(newEvents, Event.Write)
+          p.selector.updateHandle(SocketHandle(fd), newEvents)
 
     # Timer processing.
-    processTimers(p, result)
+    discard processTimers(p, result)
     # Callback queue processing
     processPendingCallbacks(p, result)
 
@@ -1533,7 +1536,11 @@ proc withTimeout*[T](fut: Future[T], timeout: int): Future[bool] =
   var timeoutFuture = sleepAsync(timeout)
   fut.callback =
     proc () =
-      if not retFuture.finished: retFuture.complete(true)
+      if not retFuture.finished:
+        if fut.failed:
+          retFuture.fail(fut.error)
+        else:
+          retFuture.complete(true)
   timeoutFuture.callback =
     proc () =
       if not retFuture.finished: retFuture.complete(false)
diff --git a/lib/pure/asyncmacro.nim b/lib/pure/asyncmacro.nim
index 4665ad25f..9e0893a4d 100644
--- a/lib/pure/asyncmacro.nim
+++ b/lib/pure/asyncmacro.nim
@@ -327,8 +327,8 @@ macro async*(prc: untyped): untyped =
   ## Macro which processes async procedures into the appropriate
   ## iterators and yield statements.
   if prc.kind == nnkStmtList:
+    result = newStmtList()
     for oneProc in prc:
-      result = newStmtList()
       result.add asyncSingleProc(oneProc)
   else:
     result = asyncSingleProc(prc)
diff --git a/lib/pure/cgi.nim b/lib/pure/cgi.nim
index e0cdc2ec0..101146ace 100644
--- a/lib/pure/cgi.nim
+++ b/lib/pure/cgi.nim
@@ -135,10 +135,9 @@ iterator decodeData*(allowedMethods: set[RequestMethod] =
   ## Reads and decodes CGI data and yields the (name, value) pairs the
   ## data consists of. If the client does not use a method listed in the
   ## `allowedMethods` set, an `ECgi` exception is raised.
-  var data = getEncodedData(allowedMethods)
-  if not isNil(data):
-    for key, value in decodeData(data):
-      yield (key, value)
+  let data = getEncodedData(allowedMethods)
+  for key, value in decodeData(data):
+    yield (key, value)
 
 proc readData*(allowedMethods: set[RequestMethod] =
                {methodNone, methodPost, methodGet}): StringTableRef =
diff --git a/lib/pure/collections/deques.nim b/lib/pure/collections/deques.nim
index 409240b37..e8342e208 100644
--- a/lib/pure/collections/deques.nim
+++ b/lib/pure/collections/deques.nim
@@ -161,10 +161,7 @@ proc peekLast*[T](deq: Deque[T]): T {.inline.} =
   result = deq.data[(deq.tail - 1) and deq.mask]
 
 template destroy(x: untyped) =
-  when defined(nimNewRuntime) and not supportsCopyMem(type(x)):
-    `=destroy`(x)
-  else:
-    reset(x)
+  reset(x)
 
 proc popFirst*[T](deq: var Deque[T]): T {.inline, discardable.} =
   ## Remove and returns the first element of the `deq`.
diff --git a/lib/pure/collections/sequtils.nim b/lib/pure/collections/sequtils.nim
index 612624f1d..63d910a8e 100644
--- a/lib/pure/collections/sequtils.nim
+++ b/lib/pure/collections/sequtils.nim
@@ -183,7 +183,6 @@ proc distribute*[T](s: seq[T], num: Positive, spread = true): seq[seq[T]] =
   ##   assert numbers.distribute(3, false)  == @[@[1, 2, 3], @[4, 5, 6], @[7]]
   ##   assert numbers.distribute(6)[0] == @[1, 2]
   ##   assert numbers.distribute(6)[5] == @[7]
-  assert(not s.isNil, "`s` can't be nil")
   if num < 2:
     result = @[s]
     return
diff --git a/lib/pure/collections/sets.nim b/lib/pure/collections/sets.nim
index fdc3b4b03..31ca56963 100644
--- a/lib/pure/collections/sets.nim
+++ b/lib/pure/collections/sets.nim
@@ -74,7 +74,7 @@ proc isValid*[A](s: HashSet[A]): bool =
   ##   proc savePreferences(options: HashSet[string]) =
   ##     assert options.isValid, "Pass an initialized set!"
   ##     # Do stuff here, may crash in release builds!
-  result = not s.data.isNil
+  result = s.data.len > 0
 
 proc len*[A](s: HashSet[A]): int =
   ## Returns the number of keys in `s`.
@@ -654,7 +654,7 @@ proc isValid*[A](s: OrderedSet[A]): bool =
   ##   proc saveTarotCards(cards: OrderedSet[int]) =
   ##     assert cards.isValid, "Pass an initialized set!"
   ##     # Do stuff here, may crash in release builds!
-  result = not s.data.isNil
+  result = s.data.len > 0
 
 proc len*[A](s: OrderedSet[A]): int {.inline.} =
   ## Returns the number of keys in `s`.
diff --git a/lib/pure/coro.nim b/lib/pure/coro.nim
index 6d7dcf078..2fe34ed40 100644
--- a/lib/pure/coro.nim
+++ b/lib/pure/coro.nim
@@ -115,7 +115,12 @@ elif coroBackend == CORO_BACKEND_SETJMP:
 when defined(unix):
   # GLibc fails with "*** longjmp causes uninitialized stack frame ***" because
   # our custom stacks are not initialized to a magic value.
-  {.passC: "-U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=0"}
+  when defined(osx):
+    # workaround: error: The deprecated ucontext routines require _XOPEN_SOURCE to be defined
+    const extra = " -D_XOPEN_SOURCE"
+  else:
+    const extra = ""
+  {.passC: "-U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=0" & extra.}
 
 const
   CORO_CREATED = 0
diff --git a/lib/pure/htmlgen.nim b/lib/pure/htmlgen.nim
index 55b02ea60..a2e224f44 100644
--- a/lib/pure/htmlgen.nim
+++ b/lib/pure/htmlgen.nim
@@ -31,10 +31,18 @@ import
   macros, strutils
 
 const
-  coreAttr* = " id class title style "
-  eventAttr* = " onclick ondblclick onmousedown onmouseup " &
-    "onmouseover onmousemove onmouseout onkeypress onkeydown onkeyup onload "
-  commonAttr* = coreAttr & eventAttr
+  coreAttr* = " accesskey class contenteditable dir hidden id lang " &
+    "spellcheck style tabindex title translate "
+  eventAttr* = "onabort onblur oncancel oncanplay oncanplaythrough onchange " &
+    "onclick oncuechange ondblclick ondurationchange onemptied onended " &
+    "onerror onfocus oninput oninvalid onkeydown onkeypress onkeyup onload " &
+    "onloadeddata onloadedmetadata onloadstart onmousedown onmouseenter " &
+    "onmouseleave onmousemove onmouseout onmouseover onmouseup onmousewheel " &
+    "onpause onplay onplaying onprogress onratechange onreset onresize " &
+    "onscroll onseeked onseeking onselect onshow onstalled onsubmit " &
+    "onsuspend ontimeupdate ontoggle onvolumechange onwaiting "
+  ariaAttr* = " role "
+  commonAttr* = coreAttr & eventAttr & ariaAttr
 
 proc getIdent(e: NimNode): string {.compileTime.} =
   case e.kind
@@ -101,13 +109,13 @@ proc xmlCheckedTag*(e: NimNode, tag: string, optAttr = "", reqAttr = "",
 macro a*(e: varargs[untyped]): untyped =
   ## generates the HTML ``a`` element.
   let e = callsite()
-  result = xmlCheckedTag(e, "a", "href charset type hreflang rel rev " &
-    "accesskey tabindex" & commonAttr)
+  result = xmlCheckedTag(e, "a", "href target download rel hreflang type " &
+    commonAttr)
 
-macro acronym*(e: varargs[untyped]): untyped =
-  ## generates the HTML ``acronym`` element.
+macro abbr*(e: varargs[untyped]): untyped =
+  ## generates the HTML ``abbr`` element.
   let e = callsite()
-  result = xmlCheckedTag(e, "acronym", commonAttr)
+  result = xmlCheckedTag(e, "abbr", commonAttr)
 
 macro address*(e: varargs[untyped]): untyped =
   ## generates the HTML ``address`` element.
@@ -117,8 +125,24 @@ macro address*(e: varargs[untyped]): untyped =
 macro area*(e: varargs[untyped]): untyped =
   ## generates the HTML ``area`` element.
   let e = callsite()
-  result = xmlCheckedTag(e, "area", "shape coords href nohref" &
-    " accesskey tabindex" & commonAttr, "alt", true)
+  result = xmlCheckedTag(e, "area", "coords download href hreflang rel " &
+    "shape target type" & commonAttr, "alt", true)
+
+macro article*(e: varargs[untyped]): untyped =
+  ## generates the HTML ``article`` element.
+  let e = callsite()
+  result = xmlCheckedTag(e, "article", commonAttr)
+
+macro aside*(e: varargs[untyped]): untyped =
+  ## generates the HTML ``aside`` element.
+  let e = callsite()
+  result = xmlCheckedTag(e, "aside", commonAttr)
+
+macro audio*(e: varargs[untyped]): untyped =
+  ## generates the HTML ``audio`` element.
+  let e = callsite()
+  result = xmlCheckedTag(e, "audio", "src crossorigin preload " &
+    "autoplay mediagroup loop muted controls" & commonAttr)
 
 macro b*(e: varargs[untyped]): untyped =
   ## generates the HTML ``b`` element.
@@ -128,7 +152,17 @@ macro b*(e: varargs[untyped]): untyped =
 macro base*(e: varargs[untyped]): untyped =
   ## generates the HTML ``base`` element.
   let e = callsite()
-  result = xmlCheckedTag(e, "base", "", "href", true)
+  result = xmlCheckedTag(e, "base", "href target" & commonAttr, "", true)
+
+macro bdi*(e: varargs[untyped]): untyped =
+  ## generates the HTML ``bdi`` element.
+  let e = callsite()
+  result = xmlCheckedTag(e, "bdi", commonAttr)
+
+macro bdo*(e: varargs[untyped]): untyped =
+  ## generates the HTML ``bdo`` element.
+  let e = callsite()
+  result = xmlCheckedTag(e, "bdo", commonAttr)
 
 macro big*(e: varargs[untyped]): untyped =
   ## generates the HTML ``big`` element.
@@ -143,18 +177,26 @@ macro blockquote*(e: varargs[untyped]): untyped =
 macro body*(e: varargs[untyped]): untyped =
   ## generates the HTML ``body`` element.
   let e = callsite()
-  result = xmlCheckedTag(e, "body", commonAttr)
+  result = xmlCheckedTag(e, "body", "onafterprint onbeforeprint " &
+    "onbeforeunload onhashchange onmessage onoffline ononline onpagehide " &
+    "onpageshow onpopstate onstorage onunload" & commonAttr)
 
 macro br*(e: varargs[untyped]): untyped =
   ## generates the HTML ``br`` element.
   let e = callsite()
-  result = xmlCheckedTag(e, "br", "", "", true)
+  result = xmlCheckedTag(e, "br", commonAttr, "", true)
 
 macro button*(e: varargs[untyped]): untyped =
   ## generates the HTML ``button`` element.
   let e = callsite()
-  result = xmlCheckedTag(e, "button", "accesskey tabindex " &
-    "disabled name type value" & commonAttr)
+  result = xmlCheckedTag(e, "button", "autofocus disabled form formaction " &
+    "formenctype formmethod formnovalidate formtarget menu name type value" &
+    commonAttr)
+
+macro canvas*(e: varargs[untyped]): untyped =
+  ## generates the HTML ``canvas`` element.
+  let e = callsite()
+  result = xmlCheckedTag(e, "canvas", "width height" & commonAttr)
 
 macro caption*(e: varargs[untyped]): untyped =
   ## generates the HTML ``caption`` element.
@@ -174,12 +216,22 @@ macro code*(e: varargs[untyped]): untyped =
 macro col*(e: varargs[untyped]): untyped =
   ## generates the HTML ``col`` element.
   let e = callsite()
-  result = xmlCheckedTag(e, "col", "span align valign" & commonAttr, "", true)
+  result = xmlCheckedTag(e, "col", "span" & commonAttr, "", true)
 
 macro colgroup*(e: varargs[untyped]): untyped =
   ## generates the HTML ``colgroup`` element.
   let e = callsite()
-  result = xmlCheckedTag(e, "colgroup", "span align valign" & commonAttr)
+  result = xmlCheckedTag(e, "colgroup", "span" & commonAttr)
+
+macro data*(e: varargs[untyped]): untyped =
+  ## generates the HTML ``data`` element.
+  let e = callsite()
+  result = xmlCheckedTag(e, "data", "value" & commonAttr)
+
+macro datalist*(e: varargs[untyped]): untyped =
+  ## generates the HTML ``datalist`` element.
+  let e = callsite()
+  result = xmlCheckedTag(e, "datalist", commonAttr)
 
 macro dd*(e: varargs[untyped]): untyped =
   ## generates the HTML ``dd`` element.
@@ -216,16 +268,37 @@ macro em*(e: varargs[untyped]): untyped =
   let e = callsite()
   result = xmlCheckedTag(e, "em", commonAttr)
 
+macro embed*(e: varargs[untyped]): untyped =
+  ## generates the HTML ``embed`` element.
+  let e = callsite()
+  result = xmlCheckedTag(e, "embed", "src type height width" &
+    commonAttr, "", true)
+
 macro fieldset*(e: varargs[untyped]): untyped =
   ## generates the HTML ``fieldset`` element.
   let e = callsite()
-  result = xmlCheckedTag(e, "fieldset", commonAttr)
+  result = xmlCheckedTag(e, "fieldset", "disabled form name" & commonAttr)
+
+macro figure*(e: varargs[untyped]): untyped =
+  ## generates the HTML ``figure`` element.
+  let e = callsite()
+  result = xmlCheckedTag(e, "figure", commonAttr)
+
+macro figcaption*(e: varargs[untyped]): untyped =
+  ## generates the HTML ``figcaption`` element.
+  let e = callsite()
+  result = xmlCheckedTag(e, "figcaption", commonAttr)
+
+macro footer*(e: varargs[untyped]): untyped =
+  ## generates the HTML ``footer`` element.
+  let e = callsite()
+  result = xmlCheckedTag(e, "footer", commonAttr)
 
 macro form*(e: varargs[untyped]): untyped =
   ## generates the HTML ``form`` element.
   let e = callsite()
-  result = xmlCheckedTag(e, "form", "method encype accept accept-charset" &
-    commonAttr, "action")
+  result = xmlCheckedTag(e, "form", "accept-charset action autocomplete " &
+    "enctype method name novalidate target" & commonAttr)
 
 macro h1*(e: varargs[untyped]): untyped =
   ## generates the HTML ``h1`` element.
@@ -260,7 +333,12 @@ macro h6*(e: varargs[untyped]): untyped =
 macro head*(e: varargs[untyped]): untyped =
   ## generates the HTML ``head`` element.
   let e = callsite()
-  result = xmlCheckedTag(e, "head", "profile")
+  result = xmlCheckedTag(e, "head", commonAttr)
+
+macro header*(e: varargs[untyped]): untyped =
+  ## generates the HTML ``header`` element.
+  let e = callsite()
+  result = xmlCheckedTag(e, "header", commonAttr)
 
 macro html*(e: varargs[untyped]): untyped =
   ## generates the HTML ``html`` element.
@@ -277,16 +355,26 @@ macro i*(e: varargs[untyped]): untyped =
   let e = callsite()
   result = xmlCheckedTag(e, "i", commonAttr)
 
+macro iframe*(e: varargs[untyped]): untyped =
+  ## generates the HTML ``iframe`` element.
+  let e = callsite()
+  result = xmlCheckedTag(e, "iframe", "src srcdoc name sandbox width height" &
+    commonAttr)
+
 macro img*(e: varargs[untyped]): untyped =
   ## generates the HTML ``img`` element.
   let e = callsite()
-  result = xmlCheckedTag(e, "img", "longdesc height width", "src alt", true)
+  result = xmlCheckedTag(e, "img", "crossorigin usemap ismap height width" &
+    commonAttr, "src alt", true)
 
 macro input*(e: varargs[untyped]): untyped =
   ## generates the HTML ``input`` element.
   let e = callsite()
-  result = xmlCheckedTag(e, "input", "name type value checked maxlength src" &
-    " alt accept disabled readonly accesskey tabindex" & commonAttr, "", true)
+  result = xmlCheckedTag(e, "input", "accept alt autocomplete autofocus " &
+    "checked dirname disabled form formaction formenctype formmethod " &
+    "formnovalidate formtarget height inputmode list max maxlength min " &
+    "minlength multiple name pattern placeholder readonly required size " &
+    "src step type value width" & commonAttr, "", true)
 
 macro ins*(e: varargs[untyped]): untyped =
   ## generates the HTML ``ins`` element.
@@ -298,36 +386,64 @@ macro kbd*(e: varargs[untyped]): untyped =
   let e = callsite()
   result = xmlCheckedTag(e, "kbd", commonAttr)
 
+macro keygen*(e: varargs[untyped]): untyped =
+  ## generates the HTML ``keygen`` element.
+  let e = callsite()
+  result = xmlCheckedTag(e, "keygen", "autofocus challenge disabled " &
+    "form keytype name" & commonAttr)
+
 macro label*(e: varargs[untyped]): untyped =
   ## generates the HTML ``label`` element.
   let e = callsite()
-  result = xmlCheckedTag(e, "label", "for accesskey" & commonAttr)
+  result = xmlCheckedTag(e, "label", "form for" & commonAttr)
 
 macro legend*(e: varargs[untyped]): untyped =
   ## generates the HTML ``legend`` element.
   let e = callsite()
-  result = xmlCheckedTag(e, "legend", "accesskey" & commonAttr)
+  result = xmlCheckedTag(e, "legend", commonAttr)
 
 macro li*(e: varargs[untyped]): untyped =
   ## generates the HTML ``li`` element.
   let e = callsite()
-  result = xmlCheckedTag(e, "li", commonAttr)
+  result = xmlCheckedTag(e, "li", "value" & commonAttr)
 
 macro link*(e: varargs[untyped]): untyped =
   ## generates the HTML ``link`` element.
   let e = callsite()
-  result = xmlCheckedTag(e, "link", "href charset hreflang type rel rev media" &
-    commonAttr, "", true)
+  result = xmlCheckedTag(e, "link", "href crossorigin rel media hreflang " &
+    "type sizes" & commonAttr, "", true)
+
+macro main*(e: varargs[untyped]): untyped =
+  ## generates the HTML ``main`` element.
+  let e = callsite()
+  result = xmlCheckedTag(e, "main", commonAttr)
 
 macro map*(e: varargs[untyped]): untyped =
   ## generates the HTML ``map`` element.
   let e = callsite()
-  result = xmlCheckedTag(e, "map", "class title" & eventAttr, "id", false)
+  result = xmlCheckedTag(e, "map", "name" & commonAttr)
+
+macro mark*(e: varargs[untyped]): untyped =
+  ## generates the HTML ``mark`` element.
+  let e = callsite()
+  result = xmlCheckedTag(e, "mark", commonAttr)
 
 macro meta*(e: varargs[untyped]): untyped =
   ## generates the HTML ``meta`` element.
   let e = callsite()
-  result = xmlCheckedTag(e, "meta", "name http-equiv scheme", "content", true)
+  result = xmlCheckedTag(e, "meta", "name http-equiv content charset" &
+    commonAttr, "", true)
+
+macro meter*(e: varargs[untyped]): untyped =
+  ## generates the HTML ``meter`` element.
+  let e = callsite()
+  result = xmlCheckedTag(e, "meter", "value min max low high optimum" &
+    commonAttr)
+
+macro nav*(e: varargs[untyped]): untyped =
+  ## generates the HTML ``nav`` element.
+  let e = callsite()
+  result = xmlCheckedTag(e, "nav", commonAttr)
 
 macro noscript*(e: varargs[untyped]): untyped =
   ## generates the HTML ``noscript`` element.
@@ -337,13 +453,13 @@ macro noscript*(e: varargs[untyped]): untyped =
 macro `object`*(e: varargs[untyped]): untyped =
   ## generates the HTML ``object`` element.
   let e = callsite()
-  result = xmlCheckedTag(e, "object", "classid data codebase declare type " &
-    "codetype archive standby width height name tabindex" & commonAttr)
+  result = xmlCheckedTag(e, "object", "data type typemustmatch name usemap " &
+    "form width height" & commonAttr)
 
 macro ol*(e: varargs[untyped]): untyped =
   ## generates the HTML ``ol`` element.
   let e = callsite()
-  result = xmlCheckedTag(e, "ol", commonAttr)
+  result = xmlCheckedTag(e, "ol", "reversed start type" & commonAttr)
 
 macro optgroup*(e: varargs[untyped]): untyped =
   ## generates the HTML ``optgroup`` element.
@@ -353,7 +469,13 @@ macro optgroup*(e: varargs[untyped]): untyped =
 macro option*(e: varargs[untyped]): untyped =
   ## generates the HTML ``option`` element.
   let e = callsite()
-  result = xmlCheckedTag(e, "option", "selected value" & commonAttr)
+  result = xmlCheckedTag(e, "option", "disabled label selected value" &
+    commonAttr)
+
+macro output*(e: varargs[untyped]): untyped =
+  ## generates the HTML ``output`` element.
+  let e = callsite()
+  result = xmlCheckedTag(e, "output", "for form name" & commonAttr)
 
 macro p*(e: varargs[untyped]): untyped =
   ## generates the HTML ``p`` element.
@@ -363,18 +485,53 @@ macro p*(e: varargs[untyped]): untyped =
 macro param*(e: varargs[untyped]): untyped =
   ## generates the HTML ``param`` element.
   let e = callsite()
-  result = xmlCheckedTag(e, "param", "value id type valuetype", "name", true)
+  result = xmlCheckedTag(e, "param", commonAttr, "name value", true)
 
 macro pre*(e: varargs[untyped]): untyped =
   ## generates the HTML ``pre`` element.
   let e = callsite()
   result = xmlCheckedTag(e, "pre", commonAttr)
 
+macro progress*(e: varargs[untyped]): untyped =
+  ## generates the HTML ``progress`` element.
+  let e = callsite()
+  result = xmlCheckedTag(e, "progress", "value max" & commonAttr)
+
 macro q*(e: varargs[untyped]): untyped =
   ## generates the HTML ``q`` element.
   let e = callsite()
   result = xmlCheckedTag(e, "q", "cite" & commonAttr)
 
+macro rb*(e: varargs[untyped]): untyped =
+  ## generates the HTML ``rb`` element.
+  let e = callsite()
+  result = xmlCheckedTag(e, "rb", commonAttr)
+
+macro rp*(e: varargs[untyped]): untyped =
+  ## generates the HTML ``rp`` element.
+  let e = callsite()
+  result = xmlCheckedTag(e, "rp", commonAttr)
+
+macro rt*(e: varargs[untyped]): untyped =
+  ## generates the HTML ``rt`` element.
+  let e = callsite()
+  result = xmlCheckedTag(e, "rt", commonAttr)
+
+macro rtc*(e: varargs[untyped]): untyped =
+  ## generates the HTML ``rtc`` element.
+  let e = callsite()
+  result = xmlCheckedTag(e, "rtc", commonAttr)
+
+macro ruby*(e: varargs[untyped]): untyped =
+  ## generates the HTML ``ruby`` element.
+  let e = callsite()
+  result = xmlCheckedTag(e, "ruby", commonAttr)
+
+macro s*(e: varargs[untyped]): untyped =
+  ## generates the HTML ``s`` element.
+  let e = callsite()
+  result = xmlCheckedTag(e, "s", commonAttr)
+
 macro samp*(e: varargs[untyped]): untyped =
   ## generates the HTML ``samp`` element.
   let e = callsite()
@@ -383,19 +540,30 @@ macro samp*(e: varargs[untyped]): untyped =
 macro script*(e: varargs[untyped]): untyped =
   ## generates the HTML ``script`` element.
   let e = callsite()
-  result = xmlCheckedTag(e, "script", "src charset defer", "type", false)
+  result = xmlCheckedTag(e, "script", "src type charset async defer " &
+    "crossorigin" & commonAttr)
+
+macro section*(e: varargs[untyped]): untyped =
+  ## generates the HTML ``section`` element.
+  let e = callsite()
+  result = xmlCheckedTag(e, "section", commonAttr)
 
 macro select*(e: varargs[untyped]): untyped =
   ## generates the HTML ``select`` element.
   let e = callsite()
-  result = xmlCheckedTag(e, "select", "name size multiple disabled tabindex" &
-    commonAttr)
+  result = xmlCheckedTag(e, "select", "autofocus disabled form multiple " &
+    "name required size" & commonAttr)
 
 macro small*(e: varargs[untyped]): untyped =
   ## generates the HTML ``small`` element.
   let e = callsite()
   result = xmlCheckedTag(e, "small", commonAttr)
 
+macro source*(e: varargs[untyped]): untyped =
+  ## generates the HTML ``source`` element.
+  let e = callsite()
+  result = xmlCheckedTag(e, "source", "type" & commonAttr, "src", true)
+
 macro span*(e: varargs[untyped]): untyped =
   ## generates the HTML ``span`` element.
   let e = callsite()
@@ -409,7 +577,7 @@ macro strong*(e: varargs[untyped]): untyped =
 macro style*(e: varargs[untyped]): untyped =
   ## generates the HTML ``style`` element.
   let e = callsite()
-  result = xmlCheckedTag(e, "style", "media title", "type")
+  result = xmlCheckedTag(e, "style", "media type" & commonAttr)
 
 macro sub*(e: varargs[untyped]): untyped =
   ## generates the HTML ``sub`` element.
@@ -424,57 +592,77 @@ macro sup*(e: varargs[untyped]): untyped =
 macro table*(e: varargs[untyped]): untyped =
   ## generates the HTML ``table`` element.
   let e = callsite()
-  result = xmlCheckedTag(e, "table", "summary border cellpadding cellspacing" &
-    " frame rules width" & commonAttr)
+  result = xmlCheckedTag(e, "table", "border sortable" & commonAttr)
 
 macro tbody*(e: varargs[untyped]): untyped =
   ## generates the HTML ``tbody`` element.
   let e = callsite()
-  result = xmlCheckedTag(e, "tbody", "align valign" & commonAttr)
+  result = xmlCheckedTag(e, "tbody", commonAttr)
 
 macro td*(e: varargs[untyped]): untyped =
   ## generates the HTML ``td`` element.
   let e = callsite()
-  result = xmlCheckedTag(e, "td", "colspan rowspan abbr axis headers scope" &
-    " align valign" & commonAttr)
+  result = xmlCheckedTag(e, "td", "colspan rowspan headers" & commonAttr)
+
+macro `template`*(e: varargs[untyped]): untyped =
+  ## generates the HTML ``template`` element.
+  let e = callsite()
+  result = xmlCheckedTag(e, "template", commonAttr)
 
 macro textarea*(e: varargs[untyped]): untyped =
   ## generates the HTML ``textarea`` element.
   let e = callsite()
-  result = xmlCheckedTag(e, "textarea", " name disabled readonly accesskey" &
-    " tabindex" & commonAttr, "rows cols", false)
+  result = xmlCheckedTag(e, "textarea", "autocomplete autofocus cols " &
+    "dirname disabled form inputmode maxlength minlength name placeholder " &
+    "readonly required rows wrap" & commonAttr)
 
 macro tfoot*(e: varargs[untyped]): untyped =
   ## generates the HTML ``tfoot`` element.
   let e = callsite()
-  result = xmlCheckedTag(e, "tfoot", "align valign" & commonAttr)
+  result = xmlCheckedTag(e, "tfoot", commonAttr)
 
 macro th*(e: varargs[untyped]): untyped =
   ## generates the HTML ``th`` element.
   let e = callsite()
-  result = xmlCheckedTag(e, "th", "colspan rowspan abbr axis headers scope" &
-    " align valign" & commonAttr)
+  result = xmlCheckedTag(e, "th", "colspan rowspan headers abbr scope axis" &
+    " sorted" & commonAttr)
 
 macro thead*(e: varargs[untyped]): untyped =
   ## generates the HTML ``thead`` element.
   let e = callsite()
-  result = xmlCheckedTag(e, "thead", "align valign" & commonAttr)
+  result = xmlCheckedTag(e, "thead", commonAttr)
+
+macro time*(e: varargs[untyped]): untyped =
+  ## generates the HTML ``time`` element.
+  let e = callsite()
+  result = xmlCheckedTag(e, "time", "datetime" & commonAttr)
 
 macro title*(e: varargs[untyped]): untyped =
   ## generates the HTML ``title`` element.
   let e = callsite()
-  result = xmlCheckedTag(e, "title")
+  result = xmlCheckedTag(e, "title", commonAttr)
 
 macro tr*(e: varargs[untyped]): untyped =
   ## generates the HTML ``tr`` element.
   let e = callsite()
-  result = xmlCheckedTag(e, "tr", "align valign" & commonAttr)
+  result = xmlCheckedTag(e, "tr",  commonAttr)
+
+macro track*(e: varargs[untyped]): untyped =
+  ## generates the HTML ``track`` element.
+  let e = callsite()
+  result = xmlCheckedTag(e, "track", "kind srclang label default" &
+    commonAttr, "src", true)
 
 macro tt*(e: varargs[untyped]): untyped =
   ## generates the HTML ``tt`` element.
   let e = callsite()
   result = xmlCheckedTag(e, "tt", commonAttr)
 
+macro u*(e: varargs[untyped]): untyped =
+  ## generates the HTML ``u`` element.
+  let e = callsite()
+  result = xmlCheckedTag(e, "u", commonAttr)
+
 macro ul*(e: varargs[untyped]): untyped =
   ## generates the HTML ``ul`` element.
   let e = callsite()
@@ -485,6 +673,17 @@ macro `var`*(e: varargs[untyped]): untyped =
   let e = callsite()
   result = xmlCheckedTag(e, "var", commonAttr)
 
+macro video*(e: varargs[untyped]): untyped =
+  ## generates the HTML ``video`` element.
+  let e = callsite()
+  result = xmlCheckedTag(e, "video", "src crossorigin poster preload " &
+    "autoplay mediagroup loop muted controls width height" & commonAttr)
+
+macro wbr*(e: varargs[untyped]): untyped =
+  ## generates the HTML ``wbr`` element.
+  let e = callsite()
+  result = xmlCheckedTag(e, "wbr", commonAttr, "", true)
+
 when isMainModule:
   let nim = "Nim"
   assert h1(a(href="http://nim-lang.org", nim)) ==
diff --git a/lib/pure/htmlparser.nim b/lib/pure/htmlparser.nim
index f54fe87f7..fbf2b8e73 100644
--- a/lib/pure/htmlparser.nim
+++ b/lib/pure/htmlparser.nim
@@ -387,1481 +387,1484 @@ proc entityToRune*(entity: string): Rune =
     doAssert entityToRune("#x0003F") == "?".runeAt(0)
   if entity.len < 2: return # smallest entity has length 2
   if entity[0] == '#':
+    var runeValue = 0
     case entity[1]
     of '0'..'9':
-      try: return Rune(parseInt(entity[1..^1]))
-      except: return
+      try: runeValue = parseInt(entity[1..^1])
+      except: discard
     of 'x', 'X': # not case sensitive here
-      try: return Rune(parseHexInt(entity[2..^1]))
-      except: return
-    else: return # other entities are not defined with prefix ``#``
+      try: runeValue = parseHexInt(entity[2..^1])
+      except: discard
+    else: discard # other entities are not defined with prefix ``#``
+    if runeValue notin 0..0x10FFFF: runeValue = 0 # only return legal values
+    return Rune(runeValue)
   case entity # entity names are case sensitive
-  of "Tab": result = Rune(0x00009)
-  of "NewLine": result = Rune(0x0000A)
-  of "excl": result = Rune(0x00021)
-  of "quot", "QUOT": result = Rune(0x00022)
-  of "num": result = Rune(0x00023)
-  of "dollar": result = Rune(0x00024)
-  of "percnt": result = Rune(0x00025)
-  of "amp", "AMP": result = Rune(0x00026)
-  of "apos": result = Rune(0x00027)
-  of "lpar": result = Rune(0x00028)
-  of "rpar": result = Rune(0x00029)
-  of "ast", "midast": result = Rune(0x0002A)
-  of "plus": result = Rune(0x0002B)
-  of "comma": result = Rune(0x0002C)
-  of "period": result = Rune(0x0002E)
-  of "sol": result = Rune(0x0002F)
-  of "colon": result = Rune(0x0003A)
-  of "semi": result = Rune(0x0003B)
-  of "lt", "LT": result = Rune(0x0003C)
-  of "equals": result = Rune(0x0003D)
-  of "gt", "GT": result = Rune(0x0003E)
-  of "quest": result = Rune(0x0003F)
-  of "commat": result = Rune(0x00040)
-  of "lsqb", "lbrack": result = Rune(0x0005B)
-  of "bsol": result = Rune(0x0005C)
-  of "rsqb", "rbrack": result = Rune(0x0005D)
-  of "Hat": result = Rune(0x0005E)
-  of "lowbar": result = Rune(0x0005F)
-  of "grave", "DiacriticalGrave": result = Rune(0x00060)
-  of "lcub", "lbrace": result = Rune(0x0007B)
-  of "verbar", "vert", "VerticalLine": result = Rune(0x0007C)
-  of "rcub", "rbrace": result = Rune(0x0007D)
-  of "nbsp", "NonBreakingSpace": result = Rune(0x000A0)
-  of "iexcl": result = Rune(0x000A1)
-  of "cent": result = Rune(0x000A2)
-  of "pound": result = Rune(0x000A3)
-  of "curren": result = Rune(0x000A4)
-  of "yen": result = Rune(0x000A5)
-  of "brvbar": result = Rune(0x000A6)
-  of "sect": result = Rune(0x000A7)
-  of "Dot", "die", "DoubleDot", "uml": result = Rune(0x000A8)
-  of "copy", "COPY": result = Rune(0x000A9)
-  of "ordf": result = Rune(0x000AA)
-  of "laquo": result = Rune(0x000AB)
-  of "not": result = Rune(0x000AC)
-  of "shy": result = Rune(0x000AD)
-  of "reg", "circledR", "REG": result = Rune(0x000AE)
-  of "macr", "OverBar", "strns": result = Rune(0x000AF)
-  of "deg": result = Rune(0x000B0)
-  of "plusmn", "pm", "PlusMinus": result = Rune(0x000B1)
-  of "sup2": result = Rune(0x000B2)
-  of "sup3": result = Rune(0x000B3)
-  of "acute", "DiacriticalAcute": result = Rune(0x000B4)
-  of "micro": result = Rune(0x000B5)
-  of "para": result = Rune(0x000B6)
-  of "middot", "centerdot", "CenterDot": result = Rune(0x000B7)
-  of "cedil", "Cedilla": result = Rune(0x000B8)
-  of "sup1": result = Rune(0x000B9)
-  of "ordm": result = Rune(0x000BA)
-  of "raquo": result = Rune(0x000BB)
-  of "frac14": result = Rune(0x000BC)
-  of "frac12", "half": result = Rune(0x000BD)
-  of "frac34": result = Rune(0x000BE)
-  of "iquest": result = Rune(0x000BF)
-  of "Agrave": result = Rune(0x000C0)
-  of "Aacute": result = Rune(0x000C1)
-  of "Acirc": result = Rune(0x000C2)
-  of "Atilde": result = Rune(0x000C3)
-  of "Auml": result = Rune(0x000C4)
-  of "Aring": result = Rune(0x000C5)
-  of "AElig": result = Rune(0x000C6)
-  of "Ccedil": result = Rune(0x000C7)
-  of "Egrave": result = Rune(0x000C8)
-  of "Eacute": result = Rune(0x000C9)
-  of "Ecirc": result = Rune(0x000CA)
-  of "Euml": result = Rune(0x000CB)
-  of "Igrave": result = Rune(0x000CC)
-  of "Iacute": result = Rune(0x000CD)
-  of "Icirc": result = Rune(0x000CE)
-  of "Iuml": result = Rune(0x000CF)
-  of "ETH": result = Rune(0x000D0)
-  of "Ntilde": result = Rune(0x000D1)
-  of "Ograve": result = Rune(0x000D2)
-  of "Oacute": result = Rune(0x000D3)
-  of "Ocirc": result = Rune(0x000D4)
-  of "Otilde": result = Rune(0x000D5)
-  of "Ouml": result = Rune(0x000D6)
-  of "times": result = Rune(0x000D7)
-  of "Oslash": result = Rune(0x000D8)
-  of "Ugrave": result = Rune(0x000D9)
-  of "Uacute": result = Rune(0x000DA)
-  of "Ucirc": result = Rune(0x000DB)
-  of "Uuml": result = Rune(0x000DC)
-  of "Yacute": result = Rune(0x000DD)
-  of "THORN": result = Rune(0x000DE)
-  of "szlig": result = Rune(0x000DF)
-  of "agrave": result = Rune(0x000E0)
-  of "aacute": result = Rune(0x000E1)
-  of "acirc": result = Rune(0x000E2)
-  of "atilde": result = Rune(0x000E3)
-  of "auml": result = Rune(0x000E4)
-  of "aring": result = Rune(0x000E5)
-  of "aelig": result = Rune(0x000E6)
-  of "ccedil": result = Rune(0x000E7)
-  of "egrave": result = Rune(0x000E8)
-  of "eacute": result = Rune(0x000E9)
-  of "ecirc": result = Rune(0x000EA)
-  of "euml": result = Rune(0x000EB)
-  of "igrave": result = Rune(0x000EC)
-  of "iacute": result = Rune(0x000ED)
-  of "icirc": result = Rune(0x000EE)
-  of "iuml": result = Rune(0x000EF)
-  of "eth": result = Rune(0x000F0)
-  of "ntilde": result = Rune(0x000F1)
-  of "ograve": result = Rune(0x000F2)
-  of "oacute": result = Rune(0x000F3)
-  of "ocirc": result = Rune(0x000F4)
-  of "otilde": result = Rune(0x000F5)
-  of "ouml": result = Rune(0x000F6)
-  of "divide", "div": result = Rune(0x000F7)
-  of "oslash": result = Rune(0x000F8)
-  of "ugrave": result = Rune(0x000F9)
-  of "uacute": result = Rune(0x000FA)
-  of "ucirc": result = Rune(0x000FB)
-  of "uuml": result = Rune(0x000FC)
-  of "yacute": result = Rune(0x000FD)
-  of "thorn": result = Rune(0x000FE)
-  of "yuml": result = Rune(0x000FF)
-  of "Amacr": result = Rune(0x00100)
-  of "amacr": result = Rune(0x00101)
-  of "Abreve": result = Rune(0x00102)
-  of "abreve": result = Rune(0x00103)
-  of "Aogon": result = Rune(0x00104)
-  of "aogon": result = Rune(0x00105)
-  of "Cacute": result = Rune(0x00106)
-  of "cacute": result = Rune(0x00107)
-  of "Ccirc": result = Rune(0x00108)
-  of "ccirc": result = Rune(0x00109)
-  of "Cdot": result = Rune(0x0010A)
-  of "cdot": result = Rune(0x0010B)
-  of "Ccaron": result = Rune(0x0010C)
-  of "ccaron": result = Rune(0x0010D)
-  of "Dcaron": result = Rune(0x0010E)
-  of "dcaron": result = Rune(0x0010F)
-  of "Dstrok": result = Rune(0x00110)
-  of "dstrok": result = Rune(0x00111)
-  of "Emacr": result = Rune(0x00112)
-  of "emacr": result = Rune(0x00113)
-  of "Edot": result = Rune(0x00116)
-  of "edot": result = Rune(0x00117)
-  of "Eogon": result = Rune(0x00118)
-  of "eogon": result = Rune(0x00119)
-  of "Ecaron": result = Rune(0x0011A)
-  of "ecaron": result = Rune(0x0011B)
-  of "Gcirc": result = Rune(0x0011C)
-  of "gcirc": result = Rune(0x0011D)
-  of "Gbreve": result = Rune(0x0011E)
-  of "gbreve": result = Rune(0x0011F)
-  of "Gdot": result = Rune(0x00120)
-  of "gdot": result = Rune(0x00121)
-  of "Gcedil": result = Rune(0x00122)
-  of "Hcirc": result = Rune(0x00124)
-  of "hcirc": result = Rune(0x00125)
-  of "Hstrok": result = Rune(0x00126)
-  of "hstrok": result = Rune(0x00127)
-  of "Itilde": result = Rune(0x00128)
-  of "itilde": result = Rune(0x00129)
-  of "Imacr": result = Rune(0x0012A)
-  of "imacr": result = Rune(0x0012B)
-  of "Iogon": result = Rune(0x0012E)
-  of "iogon": result = Rune(0x0012F)
-  of "Idot": result = Rune(0x00130)
-  of "imath", "inodot": result = Rune(0x00131)
-  of "IJlig": result = Rune(0x00132)
-  of "ijlig": result = Rune(0x00133)
-  of "Jcirc": result = Rune(0x00134)
-  of "jcirc": result = Rune(0x00135)
-  of "Kcedil": result = Rune(0x00136)
-  of "kcedil": result = Rune(0x00137)
-  of "kgreen": result = Rune(0x00138)
-  of "Lacute": result = Rune(0x00139)
-  of "lacute": result = Rune(0x0013A)
-  of "Lcedil": result = Rune(0x0013B)
-  of "lcedil": result = Rune(0x0013C)
-  of "Lcaron": result = Rune(0x0013D)
-  of "lcaron": result = Rune(0x0013E)
-  of "Lmidot": result = Rune(0x0013F)
-  of "lmidot": result = Rune(0x00140)
-  of "Lstrok": result = Rune(0x00141)
-  of "lstrok": result = Rune(0x00142)
-  of "Nacute": result = Rune(0x00143)
-  of "nacute": result = Rune(0x00144)
-  of "Ncedil": result = Rune(0x00145)
-  of "ncedil": result = Rune(0x00146)
-  of "Ncaron": result = Rune(0x00147)
-  of "ncaron": result = Rune(0x00148)
-  of "napos": result = Rune(0x00149)
-  of "ENG": result = Rune(0x0014A)
-  of "eng": result = Rune(0x0014B)
-  of "Omacr": result = Rune(0x0014C)
-  of "omacr": result = Rune(0x0014D)
-  of "Odblac": result = Rune(0x00150)
-  of "odblac": result = Rune(0x00151)
-  of "OElig": result = Rune(0x00152)
-  of "oelig": result = Rune(0x00153)
-  of "Racute": result = Rune(0x00154)
-  of "racute": result = Rune(0x00155)
-  of "Rcedil": result = Rune(0x00156)
-  of "rcedil": result = Rune(0x00157)
-  of "Rcaron": result = Rune(0x00158)
-  of "rcaron": result = Rune(0x00159)
-  of "Sacute": result = Rune(0x0015A)
-  of "sacute": result = Rune(0x0015B)
-  of "Scirc": result = Rune(0x0015C)
-  of "scirc": result = Rune(0x0015D)
-  of "Scedil": result = Rune(0x0015E)
-  of "scedil": result = Rune(0x0015F)
-  of "Scaron": result = Rune(0x00160)
-  of "scaron": result = Rune(0x00161)
-  of "Tcedil": result = Rune(0x00162)
-  of "tcedil": result = Rune(0x00163)
-  of "Tcaron": result = Rune(0x00164)
-  of "tcaron": result = Rune(0x00165)
-  of "Tstrok": result = Rune(0x00166)
-  of "tstrok": result = Rune(0x00167)
-  of "Utilde": result = Rune(0x00168)
-  of "utilde": result = Rune(0x00169)
-  of "Umacr": result = Rune(0x0016A)
-  of "umacr": result = Rune(0x0016B)
-  of "Ubreve": result = Rune(0x0016C)
-  of "ubreve": result = Rune(0x0016D)
-  of "Uring": result = Rune(0x0016E)
-  of "uring": result = Rune(0x0016F)
-  of "Udblac": result = Rune(0x00170)
-  of "udblac": result = Rune(0x00171)
-  of "Uogon": result = Rune(0x00172)
-  of "uogon": result = Rune(0x00173)
-  of "Wcirc": result = Rune(0x00174)
-  of "wcirc": result = Rune(0x00175)
-  of "Ycirc": result = Rune(0x00176)
-  of "ycirc": result = Rune(0x00177)
-  of "Yuml": result = Rune(0x00178)
-  of "Zacute": result = Rune(0x00179)
-  of "zacute": result = Rune(0x0017A)
-  of "Zdot": result = Rune(0x0017B)
-  of "zdot": result = Rune(0x0017C)
-  of "Zcaron": result = Rune(0x0017D)
-  of "zcaron": result = Rune(0x0017E)
-  of "fnof": result = Rune(0x00192)
-  of "imped": result = Rune(0x001B5)
-  of "gacute": result = Rune(0x001F5)
-  of "jmath": result = Rune(0x00237)
-  of "circ": result = Rune(0x002C6)
-  of "caron", "Hacek": result = Rune(0x002C7)
-  of "breve", "Breve": result = Rune(0x002D8)
-  of "dot", "DiacriticalDot": result = Rune(0x002D9)
-  of "ring": result = Rune(0x002DA)
-  of "ogon": result = Rune(0x002DB)
-  of "tilde", "DiacriticalTilde": result = Rune(0x002DC)
-  of "dblac", "DiacriticalDoubleAcute": result = Rune(0x002DD)
-  of "DownBreve": result = Rune(0x00311)
-  of "UnderBar": result = Rune(0x00332)
-  of "Alpha": result = Rune(0x00391)
-  of "Beta": result = Rune(0x00392)
-  of "Gamma": result = Rune(0x00393)
-  of "Delta": result = Rune(0x00394)
-  of "Epsilon": result = Rune(0x00395)
-  of "Zeta": result = Rune(0x00396)
-  of "Eta": result = Rune(0x00397)
-  of "Theta": result = Rune(0x00398)
-  of "Iota": result = Rune(0x00399)
-  of "Kappa": result = Rune(0x0039A)
-  of "Lambda": result = Rune(0x0039B)
-  of "Mu": result = Rune(0x0039C)
-  of "Nu": result = Rune(0x0039D)
-  of "Xi": result = Rune(0x0039E)
-  of "Omicron": result = Rune(0x0039F)
-  of "Pi": result = Rune(0x003A0)
-  of "Rho": result = Rune(0x003A1)
-  of "Sigma": result = Rune(0x003A3)
-  of "Tau": result = Rune(0x003A4)
-  of "Upsilon": result = Rune(0x003A5)
-  of "Phi": result = Rune(0x003A6)
-  of "Chi": result = Rune(0x003A7)
-  of "Psi": result = Rune(0x003A8)
-  of "Omega": result = Rune(0x003A9)
-  of "alpha": result = Rune(0x003B1)
-  of "beta": result = Rune(0x003B2)
-  of "gamma": result = Rune(0x003B3)
-  of "delta": result = Rune(0x003B4)
-  of "epsiv", "varepsilon", "epsilon": result = Rune(0x003B5)
-  of "zeta": result = Rune(0x003B6)
-  of "eta": result = Rune(0x003B7)
-  of "theta": result = Rune(0x003B8)
-  of "iota": result = Rune(0x003B9)
-  of "kappa": result = Rune(0x003BA)
-  of "lambda": result = Rune(0x003BB)
-  of "mu": result = Rune(0x003BC)
-  of "nu": result = Rune(0x003BD)
-  of "xi": result = Rune(0x003BE)
-  of "omicron": result = Rune(0x003BF)
-  of "pi": result = Rune(0x003C0)
-  of "rho": result = Rune(0x003C1)
-  of "sigmav", "varsigma", "sigmaf": result = Rune(0x003C2)
-  of "sigma": result = Rune(0x003C3)
-  of "tau": result = Rune(0x003C4)
-  of "upsi", "upsilon": result = Rune(0x003C5)
-  of "phi", "phiv", "varphi": result = Rune(0x003C6)
-  of "chi": result = Rune(0x003C7)
-  of "psi": result = Rune(0x003C8)
-  of "omega": result = Rune(0x003C9)
-  of "thetav", "vartheta", "thetasym": result = Rune(0x003D1)
-  of "Upsi", "upsih": result = Rune(0x003D2)
-  of "straightphi": result = Rune(0x003D5)
-  of "piv", "varpi": result = Rune(0x003D6)
-  of "Gammad": result = Rune(0x003DC)
-  of "gammad", "digamma": result = Rune(0x003DD)
-  of "kappav", "varkappa": result = Rune(0x003F0)
-  of "rhov", "varrho": result = Rune(0x003F1)
-  of "epsi", "straightepsilon": result = Rune(0x003F5)
-  of "bepsi", "backepsilon": result = Rune(0x003F6)
-  of "IOcy": result = Rune(0x00401)
-  of "DJcy": result = Rune(0x00402)
-  of "GJcy": result = Rune(0x00403)
-  of "Jukcy": result = Rune(0x00404)
-  of "DScy": result = Rune(0x00405)
-  of "Iukcy": result = Rune(0x00406)
-  of "YIcy": result = Rune(0x00407)
-  of "Jsercy": result = Rune(0x00408)
-  of "LJcy": result = Rune(0x00409)
-  of "NJcy": result = Rune(0x0040A)
-  of "TSHcy": result = Rune(0x0040B)
-  of "KJcy": result = Rune(0x0040C)
-  of "Ubrcy": result = Rune(0x0040E)
-  of "DZcy": result = Rune(0x0040F)
-  of "Acy": result = Rune(0x00410)
-  of "Bcy": result = Rune(0x00411)
-  of "Vcy": result = Rune(0x00412)
-  of "Gcy": result = Rune(0x00413)
-  of "Dcy": result = Rune(0x00414)
-  of "IEcy": result = Rune(0x00415)
-  of "ZHcy": result = Rune(0x00416)
-  of "Zcy": result = Rune(0x00417)
-  of "Icy": result = Rune(0x00418)
-  of "Jcy": result = Rune(0x00419)
-  of "Kcy": result = Rune(0x0041A)
-  of "Lcy": result = Rune(0x0041B)
-  of "Mcy": result = Rune(0x0041C)
-  of "Ncy": result = Rune(0x0041D)
-  of "Ocy": result = Rune(0x0041E)
-  of "Pcy": result = Rune(0x0041F)
-  of "Rcy": result = Rune(0x00420)
-  of "Scy": result = Rune(0x00421)
-  of "Tcy": result = Rune(0x00422)
-  of "Ucy": result = Rune(0x00423)
-  of "Fcy": result = Rune(0x00424)
-  of "KHcy": result = Rune(0x00425)
-  of "TScy": result = Rune(0x00426)
-  of "CHcy": result = Rune(0x00427)
-  of "SHcy": result = Rune(0x00428)
-  of "SHCHcy": result = Rune(0x00429)
-  of "HARDcy": result = Rune(0x0042A)
-  of "Ycy": result = Rune(0x0042B)
-  of "SOFTcy": result = Rune(0x0042C)
-  of "Ecy": result = Rune(0x0042D)
-  of "YUcy": result = Rune(0x0042E)
-  of "YAcy": result = Rune(0x0042F)
-  of "acy": result = Rune(0x00430)
-  of "bcy": result = Rune(0x00431)
-  of "vcy": result = Rune(0x00432)
-  of "gcy": result = Rune(0x00433)
-  of "dcy": result = Rune(0x00434)
-  of "iecy": result = Rune(0x00435)
-  of "zhcy": result = Rune(0x00436)
-  of "zcy": result = Rune(0x00437)
-  of "icy": result = Rune(0x00438)
-  of "jcy": result = Rune(0x00439)
-  of "kcy": result = Rune(0x0043A)
-  of "lcy": result = Rune(0x0043B)
-  of "mcy": result = Rune(0x0043C)
-  of "ncy": result = Rune(0x0043D)
-  of "ocy": result = Rune(0x0043E)
-  of "pcy": result = Rune(0x0043F)
-  of "rcy": result = Rune(0x00440)
-  of "scy": result = Rune(0x00441)
-  of "tcy": result = Rune(0x00442)
-  of "ucy": result = Rune(0x00443)
-  of "fcy": result = Rune(0x00444)
-  of "khcy": result = Rune(0x00445)
-  of "tscy": result = Rune(0x00446)
-  of "chcy": result = Rune(0x00447)
-  of "shcy": result = Rune(0x00448)
-  of "shchcy": result = Rune(0x00449)
-  of "hardcy": result = Rune(0x0044A)
-  of "ycy": result = Rune(0x0044B)
-  of "softcy": result = Rune(0x0044C)
-  of "ecy": result = Rune(0x0044D)
-  of "yucy": result = Rune(0x0044E)
-  of "yacy": result = Rune(0x0044F)
-  of "iocy": result = Rune(0x00451)
-  of "djcy": result = Rune(0x00452)
-  of "gjcy": result = Rune(0x00453)
-  of "jukcy": result = Rune(0x00454)
-  of "dscy": result = Rune(0x00455)
-  of "iukcy": result = Rune(0x00456)
-  of "yicy": result = Rune(0x00457)
-  of "jsercy": result = Rune(0x00458)
-  of "ljcy": result = Rune(0x00459)
-  of "njcy": result = Rune(0x0045A)
-  of "tshcy": result = Rune(0x0045B)
-  of "kjcy": result = Rune(0x0045C)
-  of "ubrcy": result = Rune(0x0045E)
-  of "dzcy": result = Rune(0x0045F)
-  of "ensp": result = Rune(0x02002)
-  of "emsp": result = Rune(0x02003)
-  of "emsp13": result = Rune(0x02004)
-  of "emsp14": result = Rune(0x02005)
-  of "numsp": result = Rune(0x02007)
-  of "puncsp": result = Rune(0x02008)
-  of "thinsp", "ThinSpace": result = Rune(0x02009)
-  of "hairsp", "VeryThinSpace": result = Rune(0x0200A)
+  of "Tab": Rune(0x00009)
+  of "NewLine": Rune(0x0000A)
+  of "excl": Rune(0x00021)
+  of "quot", "QUOT": Rune(0x00022)
+  of "num": Rune(0x00023)
+  of "dollar": Rune(0x00024)
+  of "percnt": Rune(0x00025)
+  of "amp", "AMP": Rune(0x00026)
+  of "apos": Rune(0x00027)
+  of "lpar": Rune(0x00028)
+  of "rpar": Rune(0x00029)
+  of "ast", "midast": Rune(0x0002A)
+  of "plus": Rune(0x0002B)
+  of "comma": Rune(0x0002C)
+  of "period": Rune(0x0002E)
+  of "sol": Rune(0x0002F)
+  of "colon": Rune(0x0003A)
+  of "semi": Rune(0x0003B)
+  of "lt", "LT": Rune(0x0003C)
+  of "equals": Rune(0x0003D)
+  of "gt", "GT": Rune(0x0003E)
+  of "quest": Rune(0x0003F)
+  of "commat": Rune(0x00040)
+  of "lsqb", "lbrack": Rune(0x0005B)
+  of "bsol": Rune(0x0005C)
+  of "rsqb", "rbrack": Rune(0x0005D)
+  of "Hat": Rune(0x0005E)
+  of "lowbar": Rune(0x0005F)
+  of "grave", "DiacriticalGrave": Rune(0x00060)
+  of "lcub", "lbrace": Rune(0x0007B)
+  of "verbar", "vert", "VerticalLine": Rune(0x0007C)
+  of "rcub", "rbrace": Rune(0x0007D)
+  of "nbsp", "NonBreakingSpace": Rune(0x000A0)
+  of "iexcl": Rune(0x000A1)
+  of "cent": Rune(0x000A2)
+  of "pound": Rune(0x000A3)
+  of "curren": Rune(0x000A4)
+  of "yen": Rune(0x000A5)
+  of "brvbar": Rune(0x000A6)
+  of "sect": Rune(0x000A7)
+  of "Dot", "die", "DoubleDot", "uml": Rune(0x000A8)
+  of "copy", "COPY": Rune(0x000A9)
+  of "ordf": Rune(0x000AA)
+  of "laquo": Rune(0x000AB)
+  of "not": Rune(0x000AC)
+  of "shy": Rune(0x000AD)
+  of "reg", "circledR", "REG": Rune(0x000AE)
+  of "macr", "OverBar", "strns": Rune(0x000AF)
+  of "deg": Rune(0x000B0)
+  of "plusmn", "pm", "PlusMinus": Rune(0x000B1)
+  of "sup2": Rune(0x000B2)
+  of "sup3": Rune(0x000B3)
+  of "acute", "DiacriticalAcute": Rune(0x000B4)
+  of "micro": Rune(0x000B5)
+  of "para": Rune(0x000B6)
+  of "middot", "centerdot", "CenterDot": Rune(0x000B7)
+  of "cedil", "Cedilla": Rune(0x000B8)
+  of "sup1": Rune(0x000B9)
+  of "ordm": Rune(0x000BA)
+  of "raquo": Rune(0x000BB)
+  of "frac14": Rune(0x000BC)
+  of "frac12", "half": Rune(0x000BD)
+  of "frac34": Rune(0x000BE)
+  of "iquest": Rune(0x000BF)
+  of "Agrave": Rune(0x000C0)
+  of "Aacute": Rune(0x000C1)
+  of "Acirc": Rune(0x000C2)
+  of "Atilde": Rune(0x000C3)
+  of "Auml": Rune(0x000C4)
+  of "Aring": Rune(0x000C5)
+  of "AElig": Rune(0x000C6)
+  of "Ccedil": Rune(0x000C7)
+  of "Egrave": Rune(0x000C8)
+  of "Eacute": Rune(0x000C9)
+  of "Ecirc": Rune(0x000CA)
+  of "Euml": Rune(0x000CB)
+  of "Igrave": Rune(0x000CC)
+  of "Iacute": Rune(0x000CD)
+  of "Icirc": Rune(0x000CE)
+  of "Iuml": Rune(0x000CF)
+  of "ETH": Rune(0x000D0)
+  of "Ntilde": Rune(0x000D1)
+  of "Ograve": Rune(0x000D2)
+  of "Oacute": Rune(0x000D3)
+  of "Ocirc": Rune(0x000D4)
+  of "Otilde": Rune(0x000D5)
+  of "Ouml": Rune(0x000D6)
+  of "times": Rune(0x000D7)
+  of "Oslash": Rune(0x000D8)
+  of "Ugrave": Rune(0x000D9)
+  of "Uacute": Rune(0x000DA)
+  of "Ucirc": Rune(0x000DB)
+  of "Uuml": Rune(0x000DC)
+  of "Yacute": Rune(0x000DD)
+  of "THORN": Rune(0x000DE)
+  of "szlig": Rune(0x000DF)
+  of "agrave": Rune(0x000E0)
+  of "aacute": Rune(0x000E1)
+  of "acirc": Rune(0x000E2)
+  of "atilde": Rune(0x000E3)
+  of "auml": Rune(0x000E4)
+  of "aring": Rune(0x000E5)
+  of "aelig": Rune(0x000E6)
+  of "ccedil": Rune(0x000E7)
+  of "egrave": Rune(0x000E8)
+  of "eacute": Rune(0x000E9)
+  of "ecirc": Rune(0x000EA)
+  of "euml": Rune(0x000EB)
+  of "igrave": Rune(0x000EC)
+  of "iacute": Rune(0x000ED)
+  of "icirc": Rune(0x000EE)
+  of "iuml": Rune(0x000EF)
+  of "eth": Rune(0x000F0)
+  of "ntilde": Rune(0x000F1)
+  of "ograve": Rune(0x000F2)
+  of "oacute": Rune(0x000F3)
+  of "ocirc": Rune(0x000F4)
+  of "otilde": Rune(0x000F5)
+  of "ouml": Rune(0x000F6)
+  of "divide", "div": Rune(0x000F7)
+  of "oslash": Rune(0x000F8)
+  of "ugrave": Rune(0x000F9)
+  of "uacute": Rune(0x000FA)
+  of "ucirc": Rune(0x000FB)
+  of "uuml": Rune(0x000FC)
+  of "yacute": Rune(0x000FD)
+  of "thorn": Rune(0x000FE)
+  of "yuml": Rune(0x000FF)
+  of "Amacr": Rune(0x00100)
+  of "amacr": Rune(0x00101)
+  of "Abreve": Rune(0x00102)
+  of "abreve": Rune(0x00103)
+  of "Aogon": Rune(0x00104)
+  of "aogon": Rune(0x00105)
+  of "Cacute": Rune(0x00106)
+  of "cacute": Rune(0x00107)
+  of "Ccirc": Rune(0x00108)
+  of "ccirc": Rune(0x00109)
+  of "Cdot": Rune(0x0010A)
+  of "cdot": Rune(0x0010B)
+  of "Ccaron": Rune(0x0010C)
+  of "ccaron": Rune(0x0010D)
+  of "Dcaron": Rune(0x0010E)
+  of "dcaron": Rune(0x0010F)
+  of "Dstrok": Rune(0x00110)
+  of "dstrok": Rune(0x00111)
+  of "Emacr": Rune(0x00112)
+  of "emacr": Rune(0x00113)
+  of "Edot": Rune(0x00116)
+  of "edot": Rune(0x00117)
+  of "Eogon": Rune(0x00118)
+  of "eogon": Rune(0x00119)
+  of "Ecaron": Rune(0x0011A)
+  of "ecaron": Rune(0x0011B)
+  of "Gcirc": Rune(0x0011C)
+  of "gcirc": Rune(0x0011D)
+  of "Gbreve": Rune(0x0011E)
+  of "gbreve": Rune(0x0011F)
+  of "Gdot": Rune(0x00120)
+  of "gdot": Rune(0x00121)
+  of "Gcedil": Rune(0x00122)
+  of "Hcirc": Rune(0x00124)
+  of "hcirc": Rune(0x00125)
+  of "Hstrok": Rune(0x00126)
+  of "hstrok": Rune(0x00127)
+  of "Itilde": Rune(0x00128)
+  of "itilde": Rune(0x00129)
+  of "Imacr": Rune(0x0012A)
+  of "imacr": Rune(0x0012B)
+  of "Iogon": Rune(0x0012E)
+  of "iogon": Rune(0x0012F)
+  of "Idot": Rune(0x00130)
+  of "imath", "inodot": Rune(0x00131)
+  of "IJlig": Rune(0x00132)
+  of "ijlig": Rune(0x00133)
+  of "Jcirc": Rune(0x00134)
+  of "jcirc": Rune(0x00135)
+  of "Kcedil": Rune(0x00136)
+  of "kcedil": Rune(0x00137)
+  of "kgreen": Rune(0x00138)
+  of "Lacute": Rune(0x00139)
+  of "lacute": Rune(0x0013A)
+  of "Lcedil": Rune(0x0013B)
+  of "lcedil": Rune(0x0013C)
+  of "Lcaron": Rune(0x0013D)
+  of "lcaron": Rune(0x0013E)
+  of "Lmidot": Rune(0x0013F)
+  of "lmidot": Rune(0x00140)
+  of "Lstrok": Rune(0x00141)
+  of "lstrok": Rune(0x00142)
+  of "Nacute": Rune(0x00143)
+  of "nacute": Rune(0x00144)
+  of "Ncedil": Rune(0x00145)
+  of "ncedil": Rune(0x00146)
+  of "Ncaron": Rune(0x00147)
+  of "ncaron": Rune(0x00148)
+  of "napos": Rune(0x00149)
+  of "ENG": Rune(0x0014A)
+  of "eng": Rune(0x0014B)
+  of "Omacr": Rune(0x0014C)
+  of "omacr": Rune(0x0014D)
+  of "Odblac": Rune(0x00150)
+  of "odblac": Rune(0x00151)
+  of "OElig": Rune(0x00152)
+  of "oelig": Rune(0x00153)
+  of "Racute": Rune(0x00154)
+  of "racute": Rune(0x00155)
+  of "Rcedil": Rune(0x00156)
+  of "rcedil": Rune(0x00157)
+  of "Rcaron": Rune(0x00158)
+  of "rcaron": Rune(0x00159)
+  of "Sacute": Rune(0x0015A)
+  of "sacute": Rune(0x0015B)
+  of "Scirc": Rune(0x0015C)
+  of "scirc": Rune(0x0015D)
+  of "Scedil": Rune(0x0015E)
+  of "scedil": Rune(0x0015F)
+  of "Scaron": Rune(0x00160)
+  of "scaron": Rune(0x00161)
+  of "Tcedil": Rune(0x00162)
+  of "tcedil": Rune(0x00163)
+  of "Tcaron": Rune(0x00164)
+  of "tcaron": Rune(0x00165)
+  of "Tstrok": Rune(0x00166)
+  of "tstrok": Rune(0x00167)
+  of "Utilde": Rune(0x00168)
+  of "utilde": Rune(0x00169)
+  of "Umacr": Rune(0x0016A)
+  of "umacr": Rune(0x0016B)
+  of "Ubreve": Rune(0x0016C)
+  of "ubreve": Rune(0x0016D)
+  of "Uring": Rune(0x0016E)
+  of "uring": Rune(0x0016F)
+  of "Udblac": Rune(0x00170)
+  of "udblac": Rune(0x00171)
+  of "Uogon": Rune(0x00172)
+  of "uogon": Rune(0x00173)
+  of "Wcirc": Rune(0x00174)
+  of "wcirc": Rune(0x00175)
+  of "Ycirc": Rune(0x00176)
+  of "ycirc": Rune(0x00177)
+  of "Yuml": Rune(0x00178)
+  of "Zacute": Rune(0x00179)
+  of "zacute": Rune(0x0017A)
+  of "Zdot": Rune(0x0017B)
+  of "zdot": Rune(0x0017C)
+  of "Zcaron": Rune(0x0017D)
+  of "zcaron": Rune(0x0017E)
+  of "fnof": Rune(0x00192)
+  of "imped": Rune(0x001B5)
+  of "gacute": Rune(0x001F5)
+  of "jmath": Rune(0x00237)
+  of "circ": Rune(0x002C6)
+  of "caron", "Hacek": Rune(0x002C7)
+  of "breve", "Breve": Rune(0x002D8)
+  of "dot", "DiacriticalDot": Rune(0x002D9)
+  of "ring": Rune(0x002DA)
+  of "ogon": Rune(0x002DB)
+  of "tilde", "DiacriticalTilde": Rune(0x002DC)
+  of "dblac", "DiacriticalDoubleAcute": Rune(0x002DD)
+  of "DownBreve": Rune(0x00311)
+  of "UnderBar": Rune(0x00332)
+  of "Alpha": Rune(0x00391)
+  of "Beta": Rune(0x00392)
+  of "Gamma": Rune(0x00393)
+  of "Delta": Rune(0x00394)
+  of "Epsilon": Rune(0x00395)
+  of "Zeta": Rune(0x00396)
+  of "Eta": Rune(0x00397)
+  of "Theta": Rune(0x00398)
+  of "Iota": Rune(0x00399)
+  of "Kappa": Rune(0x0039A)
+  of "Lambda": Rune(0x0039B)
+  of "Mu": Rune(0x0039C)
+  of "Nu": Rune(0x0039D)
+  of "Xi": Rune(0x0039E)
+  of "Omicron": Rune(0x0039F)
+  of "Pi": Rune(0x003A0)
+  of "Rho": Rune(0x003A1)
+  of "Sigma": Rune(0x003A3)
+  of "Tau": Rune(0x003A4)
+  of "Upsilon": Rune(0x003A5)
+  of "Phi": Rune(0x003A6)
+  of "Chi": Rune(0x003A7)
+  of "Psi": Rune(0x003A8)
+  of "Omega": Rune(0x003A9)
+  of "alpha": Rune(0x003B1)
+  of "beta": Rune(0x003B2)
+  of "gamma": Rune(0x003B3)
+  of "delta": Rune(0x003B4)
+  of "epsiv", "varepsilon", "epsilon": Rune(0x003B5)
+  of "zeta": Rune(0x003B6)
+  of "eta": Rune(0x003B7)
+  of "theta": Rune(0x003B8)
+  of "iota": Rune(0x003B9)
+  of "kappa": Rune(0x003BA)
+  of "lambda": Rune(0x003BB)
+  of "mu": Rune(0x003BC)
+  of "nu": Rune(0x003BD)
+  of "xi": Rune(0x003BE)
+  of "omicron": Rune(0x003BF)
+  of "pi": Rune(0x003C0)
+  of "rho": Rune(0x003C1)
+  of "sigmav", "varsigma", "sigmaf": Rune(0x003C2)
+  of "sigma": Rune(0x003C3)
+  of "tau": Rune(0x003C4)
+  of "upsi", "upsilon": Rune(0x003C5)
+  of "phi", "phiv", "varphi": Rune(0x003C6)
+  of "chi": Rune(0x003C7)
+  of "psi": Rune(0x003C8)
+  of "omega": Rune(0x003C9)
+  of "thetav", "vartheta", "thetasym": Rune(0x003D1)
+  of "Upsi", "upsih": Rune(0x003D2)
+  of "straightphi": Rune(0x003D5)
+  of "piv", "varpi": Rune(0x003D6)
+  of "Gammad": Rune(0x003DC)
+  of "gammad", "digamma": Rune(0x003DD)
+  of "kappav", "varkappa": Rune(0x003F0)
+  of "rhov", "varrho": Rune(0x003F1)
+  of "epsi", "straightepsilon": Rune(0x003F5)
+  of "bepsi", "backepsilon": Rune(0x003F6)
+  of "IOcy": Rune(0x00401)
+  of "DJcy": Rune(0x00402)
+  of "GJcy": Rune(0x00403)
+  of "Jukcy": Rune(0x00404)
+  of "DScy": Rune(0x00405)
+  of "Iukcy": Rune(0x00406)
+  of "YIcy": Rune(0x00407)
+  of "Jsercy": Rune(0x00408)
+  of "LJcy": Rune(0x00409)
+  of "NJcy": Rune(0x0040A)
+  of "TSHcy": Rune(0x0040B)
+  of "KJcy": Rune(0x0040C)
+  of "Ubrcy": Rune(0x0040E)
+  of "DZcy": Rune(0x0040F)
+  of "Acy": Rune(0x00410)
+  of "Bcy": Rune(0x00411)
+  of "Vcy": Rune(0x00412)
+  of "Gcy": Rune(0x00413)
+  of "Dcy": Rune(0x00414)
+  of "IEcy": Rune(0x00415)
+  of "ZHcy": Rune(0x00416)
+  of "Zcy": Rune(0x00417)
+  of "Icy": Rune(0x00418)
+  of "Jcy": Rune(0x00419)
+  of "Kcy": Rune(0x0041A)
+  of "Lcy": Rune(0x0041B)
+  of "Mcy": Rune(0x0041C)
+  of "Ncy": Rune(0x0041D)
+  of "Ocy": Rune(0x0041E)
+  of "Pcy": Rune(0x0041F)
+  of "Rcy": Rune(0x00420)
+  of "Scy": Rune(0x00421)
+  of "Tcy": Rune(0x00422)
+  of "Ucy": Rune(0x00423)
+  of "Fcy": Rune(0x00424)
+  of "KHcy": Rune(0x00425)
+  of "TScy": Rune(0x00426)
+  of "CHcy": Rune(0x00427)
+  of "SHcy": Rune(0x00428)
+  of "SHCHcy": Rune(0x00429)
+  of "HARDcy": Rune(0x0042A)
+  of "Ycy": Rune(0x0042B)
+  of "SOFTcy": Rune(0x0042C)
+  of "Ecy": Rune(0x0042D)
+  of "YUcy": Rune(0x0042E)
+  of "YAcy": Rune(0x0042F)
+  of "acy": Rune(0x00430)
+  of "bcy": Rune(0x00431)
+  of "vcy": Rune(0x00432)
+  of "gcy": Rune(0x00433)
+  of "dcy": Rune(0x00434)
+  of "iecy": Rune(0x00435)
+  of "zhcy": Rune(0x00436)
+  of "zcy": Rune(0x00437)
+  of "icy": Rune(0x00438)
+  of "jcy": Rune(0x00439)
+  of "kcy": Rune(0x0043A)
+  of "lcy": Rune(0x0043B)
+  of "mcy": Rune(0x0043C)
+  of "ncy": Rune(0x0043D)
+  of "ocy": Rune(0x0043E)
+  of "pcy": Rune(0x0043F)
+  of "rcy": Rune(0x00440)
+  of "scy": Rune(0x00441)
+  of "tcy": Rune(0x00442)
+  of "ucy": Rune(0x00443)
+  of "fcy": Rune(0x00444)
+  of "khcy": Rune(0x00445)
+  of "tscy": Rune(0x00446)
+  of "chcy": Rune(0x00447)
+  of "shcy": Rune(0x00448)
+  of "shchcy": Rune(0x00449)
+  of "hardcy": Rune(0x0044A)
+  of "ycy": Rune(0x0044B)
+  of "softcy": Rune(0x0044C)
+  of "ecy": Rune(0x0044D)
+  of "yucy": Rune(0x0044E)
+  of "yacy": Rune(0x0044F)
+  of "iocy": Rune(0x00451)
+  of "djcy": Rune(0x00452)
+  of "gjcy": Rune(0x00453)
+  of "jukcy": Rune(0x00454)
+  of "dscy": Rune(0x00455)
+  of "iukcy": Rune(0x00456)
+  of "yicy": Rune(0x00457)
+  of "jsercy": Rune(0x00458)
+  of "ljcy": Rune(0x00459)
+  of "njcy": Rune(0x0045A)
+  of "tshcy": Rune(0x0045B)
+  of "kjcy": Rune(0x0045C)
+  of "ubrcy": Rune(0x0045E)
+  of "dzcy": Rune(0x0045F)
+  of "ensp": Rune(0x02002)
+  of "emsp": Rune(0x02003)
+  of "emsp13": Rune(0x02004)
+  of "emsp14": Rune(0x02005)
+  of "numsp": Rune(0x02007)
+  of "puncsp": Rune(0x02008)
+  of "thinsp", "ThinSpace": Rune(0x02009)
+  of "hairsp", "VeryThinSpace": Rune(0x0200A)
   of "ZeroWidthSpace", "NegativeVeryThinSpace", "NegativeThinSpace",
-    "NegativeMediumSpace", "NegativeThickSpace": result = Rune(0x0200B)
-  of "zwnj": result = Rune(0x0200C)
-  of "zwj": result = Rune(0x0200D)
-  of "lrm": result = Rune(0x0200E)
-  of "rlm": result = Rune(0x0200F)
-  of "hyphen", "dash": result = Rune(0x02010)
-  of "ndash": result = Rune(0x02013)
-  of "mdash": result = Rune(0x02014)
-  of "horbar": result = Rune(0x02015)
-  of "Verbar", "Vert": result = Rune(0x02016)
-  of "lsquo", "OpenCurlyQuote": result = Rune(0x02018)
-  of "rsquo", "rsquor", "CloseCurlyQuote": result = Rune(0x02019)
-  of "lsquor", "sbquo": result = Rune(0x0201A)
-  of "ldquo", "OpenCurlyDoubleQuote": result = Rune(0x0201C)
-  of "rdquo", "rdquor", "CloseCurlyDoubleQuote": result = Rune(0x0201D)
-  of "ldquor", "bdquo": result = Rune(0x0201E)
-  of "dagger": result = Rune(0x02020)
-  of "Dagger", "ddagger": result = Rune(0x02021)
-  of "bull", "bullet": result = Rune(0x02022)
-  of "nldr": result = Rune(0x02025)
-  of "hellip", "mldr": result = Rune(0x02026)
-  of "permil": result = Rune(0x02030)
-  of "pertenk": result = Rune(0x02031)
-  of "prime": result = Rune(0x02032)
-  of "Prime": result = Rune(0x02033)
-  of "tprime": result = Rune(0x02034)
-  of "bprime", "backprime": result = Rune(0x02035)
-  of "lsaquo": result = Rune(0x02039)
-  of "rsaquo": result = Rune(0x0203A)
-  of "oline": result = Rune(0x0203E)
-  of "caret": result = Rune(0x02041)
-  of "hybull": result = Rune(0x02043)
-  of "frasl": result = Rune(0x02044)
-  of "bsemi": result = Rune(0x0204F)
-  of "qprime": result = Rune(0x02057)
-  of "MediumSpace": result = Rune(0x0205F)
-  of "NoBreak": result = Rune(0x02060)
-  of "ApplyFunction", "af": result = Rune(0x02061)
-  of "InvisibleTimes", "it": result = Rune(0x02062)
-  of "InvisibleComma", "ic": result = Rune(0x02063)
-  of "euro": result = Rune(0x020AC)
-  of "tdot", "TripleDot": result = Rune(0x020DB)
-  of "DotDot": result = Rune(0x020DC)
-  of "Copf", "complexes": result = Rune(0x02102)
-  of "incare": result = Rune(0x02105)
-  of "gscr": result = Rune(0x0210A)
-  of "hamilt", "HilbertSpace", "Hscr": result = Rune(0x0210B)
-  of "Hfr", "Poincareplane": result = Rune(0x0210C)
-  of "quaternions", "Hopf": result = Rune(0x0210D)
-  of "planckh": result = Rune(0x0210E)
-  of "planck", "hbar", "plankv", "hslash": result = Rune(0x0210F)
-  of "Iscr", "imagline": result = Rune(0x02110)
-  of "image", "Im", "imagpart", "Ifr": result = Rune(0x02111)
-  of "Lscr", "lagran", "Laplacetrf": result = Rune(0x02112)
-  of "ell": result = Rune(0x02113)
-  of "Nopf", "naturals": result = Rune(0x02115)
-  of "numero": result = Rune(0x02116)
-  of "copysr": result = Rune(0x02117)
-  of "weierp", "wp": result = Rune(0x02118)
-  of "Popf", "primes": result = Rune(0x02119)
-  of "rationals", "Qopf": result = Rune(0x0211A)
-  of "Rscr", "realine": result = Rune(0x0211B)
-  of "real", "Re", "realpart", "Rfr": result = Rune(0x0211C)
-  of "reals", "Ropf": result = Rune(0x0211D)
-  of "rx": result = Rune(0x0211E)
-  of "trade", "TRADE": result = Rune(0x02122)
-  of "integers", "Zopf": result = Rune(0x02124)
-  of "ohm": result = Rune(0x02126)
-  of "mho": result = Rune(0x02127)
-  of "Zfr", "zeetrf": result = Rune(0x02128)
-  of "iiota": result = Rune(0x02129)
-  of "angst": result = Rune(0x0212B)
-  of "bernou", "Bernoullis", "Bscr": result = Rune(0x0212C)
-  of "Cfr", "Cayleys": result = Rune(0x0212D)
-  of "escr": result = Rune(0x0212F)
-  of "Escr", "expectation": result = Rune(0x02130)
-  of "Fscr", "Fouriertrf": result = Rune(0x02131)
-  of "phmmat", "Mellintrf", "Mscr": result = Rune(0x02133)
-  of "order", "orderof", "oscr": result = Rune(0x02134)
-  of "alefsym", "aleph": result = Rune(0x02135)
-  of "beth": result = Rune(0x02136)
-  of "gimel": result = Rune(0x02137)
-  of "daleth": result = Rune(0x02138)
-  of "CapitalDifferentialD", "DD": result = Rune(0x02145)
-  of "DifferentialD", "dd": result = Rune(0x02146)
-  of "ExponentialE", "exponentiale", "ee": result = Rune(0x02147)
-  of "ImaginaryI", "ii": result = Rune(0x02148)
-  of "frac13": result = Rune(0x02153)
-  of "frac23": result = Rune(0x02154)
-  of "frac15": result = Rune(0x02155)
-  of "frac25": result = Rune(0x02156)
-  of "frac35": result = Rune(0x02157)
-  of "frac45": result = Rune(0x02158)
-  of "frac16": result = Rune(0x02159)
-  of "frac56": result = Rune(0x0215A)
-  of "frac18": result = Rune(0x0215B)
-  of "frac38": result = Rune(0x0215C)
-  of "frac58": result = Rune(0x0215D)
-  of "frac78": result = Rune(0x0215E)
+    "NegativeMediumSpace", "NegativeThickSpace": Rune(0x0200B)
+  of "zwnj": Rune(0x0200C)
+  of "zwj": Rune(0x0200D)
+  of "lrm": Rune(0x0200E)
+  of "rlm": Rune(0x0200F)
+  of "hyphen", "dash": Rune(0x02010)
+  of "ndash": Rune(0x02013)
+  of "mdash": Rune(0x02014)
+  of "horbar": Rune(0x02015)
+  of "Verbar", "Vert": Rune(0x02016)
+  of "lsquo", "OpenCurlyQuote": Rune(0x02018)
+  of "rsquo", "rsquor", "CloseCurlyQuote": Rune(0x02019)
+  of "lsquor", "sbquo": Rune(0x0201A)
+  of "ldquo", "OpenCurlyDoubleQuote": Rune(0x0201C)
+  of "rdquo", "rdquor", "CloseCurlyDoubleQuote": Rune(0x0201D)
+  of "ldquor", "bdquo": Rune(0x0201E)
+  of "dagger": Rune(0x02020)
+  of "Dagger", "ddagger": Rune(0x02021)
+  of "bull", "bullet": Rune(0x02022)
+  of "nldr": Rune(0x02025)
+  of "hellip", "mldr": Rune(0x02026)
+  of "permil": Rune(0x02030)
+  of "pertenk": Rune(0x02031)
+  of "prime": Rune(0x02032)
+  of "Prime": Rune(0x02033)
+  of "tprime": Rune(0x02034)
+  of "bprime", "backprime": Rune(0x02035)
+  of "lsaquo": Rune(0x02039)
+  of "rsaquo": Rune(0x0203A)
+  of "oline": Rune(0x0203E)
+  of "caret": Rune(0x02041)
+  of "hybull": Rune(0x02043)
+  of "frasl": Rune(0x02044)
+  of "bsemi": Rune(0x0204F)
+  of "qprime": Rune(0x02057)
+  of "MediumSpace": Rune(0x0205F)
+  of "NoBreak": Rune(0x02060)
+  of "ApplyFunction", "af": Rune(0x02061)
+  of "InvisibleTimes", "it": Rune(0x02062)
+  of "InvisibleComma", "ic": Rune(0x02063)
+  of "euro": Rune(0x020AC)
+  of "tdot", "TripleDot": Rune(0x020DB)
+  of "DotDot": Rune(0x020DC)
+  of "Copf", "complexes": Rune(0x02102)
+  of "incare": Rune(0x02105)
+  of "gscr": Rune(0x0210A)
+  of "hamilt", "HilbertSpace", "Hscr": Rune(0x0210B)
+  of "Hfr", "Poincareplane": Rune(0x0210C)
+  of "quaternions", "Hopf": Rune(0x0210D)
+  of "planckh": Rune(0x0210E)
+  of "planck", "hbar", "plankv", "hslash": Rune(0x0210F)
+  of "Iscr", "imagline": Rune(0x02110)
+  of "image", "Im", "imagpart", "Ifr": Rune(0x02111)
+  of "Lscr", "lagran", "Laplacetrf": Rune(0x02112)
+  of "ell": Rune(0x02113)
+  of "Nopf", "naturals": Rune(0x02115)
+  of "numero": Rune(0x02116)
+  of "copysr": Rune(0x02117)
+  of "weierp", "wp": Rune(0x02118)
+  of "Popf", "primes": Rune(0x02119)
+  of "rationals", "Qopf": Rune(0x0211A)
+  of "Rscr", "realine": Rune(0x0211B)
+  of "real", "Re", "realpart", "Rfr": Rune(0x0211C)
+  of "reals", "Ropf": Rune(0x0211D)
+  of "rx": Rune(0x0211E)
+  of "trade", "TRADE": Rune(0x02122)
+  of "integers", "Zopf": Rune(0x02124)
+  of "ohm": Rune(0x02126)
+  of "mho": Rune(0x02127)
+  of "Zfr", "zeetrf": Rune(0x02128)
+  of "iiota": Rune(0x02129)
+  of "angst": Rune(0x0212B)
+  of "bernou", "Bernoullis", "Bscr": Rune(0x0212C)
+  of "Cfr", "Cayleys": Rune(0x0212D)
+  of "escr": Rune(0x0212F)
+  of "Escr", "expectation": Rune(0x02130)
+  of "Fscr", "Fouriertrf": Rune(0x02131)
+  of "phmmat", "Mellintrf", "Mscr": Rune(0x02133)
+  of "order", "orderof", "oscr": Rune(0x02134)
+  of "alefsym", "aleph": Rune(0x02135)
+  of "beth": Rune(0x02136)
+  of "gimel": Rune(0x02137)
+  of "daleth": Rune(0x02138)
+  of "CapitalDifferentialD", "DD": Rune(0x02145)
+  of "DifferentialD", "dd": Rune(0x02146)
+  of "ExponentialE", "exponentiale", "ee": Rune(0x02147)
+  of "ImaginaryI", "ii": Rune(0x02148)
+  of "frac13": Rune(0x02153)
+  of "frac23": Rune(0x02154)
+  of "frac15": Rune(0x02155)
+  of "frac25": Rune(0x02156)
+  of "frac35": Rune(0x02157)
+  of "frac45": Rune(0x02158)
+  of "frac16": Rune(0x02159)
+  of "frac56": Rune(0x0215A)
+  of "frac18": Rune(0x0215B)
+  of "frac38": Rune(0x0215C)
+  of "frac58": Rune(0x0215D)
+  of "frac78": Rune(0x0215E)
   of "larr", "leftarrow", "LeftArrow", "slarr",
-    "ShortLeftArrow": result = Rune(0x02190)
-  of "uarr", "uparrow", "UpArrow", "ShortUpArrow": result = Rune(0x02191)
+    "ShortLeftArrow": Rune(0x02190)
+  of "uarr", "uparrow", "UpArrow", "ShortUpArrow": Rune(0x02191)
   of "rarr", "rightarrow", "RightArrow", "srarr",
-    "ShortRightArrow": result = Rune(0x02192)
+    "ShortRightArrow": Rune(0x02192)
   of "darr", "downarrow", "DownArrow",
-    "ShortDownArrow": result = Rune(0x02193)
-  of "harr", "leftrightarrow", "LeftRightArrow": result = Rune(0x02194)
-  of "varr", "updownarrow", "UpDownArrow": result = Rune(0x02195)
-  of "nwarr", "UpperLeftArrow", "nwarrow": result = Rune(0x02196)
-  of "nearr", "UpperRightArrow", "nearrow": result = Rune(0x02197)
-  of "searr", "searrow", "LowerRightArrow": result = Rune(0x02198)
-  of "swarr", "swarrow", "LowerLeftArrow": result = Rune(0x02199)
-  of "nlarr", "nleftarrow": result = Rune(0x0219A)
-  of "nrarr", "nrightarrow": result = Rune(0x0219B)
-  of "rarrw", "rightsquigarrow": result = Rune(0x0219D)
-  of "Larr", "twoheadleftarrow": result = Rune(0x0219E)
-  of "Uarr": result = Rune(0x0219F)
-  of "Rarr", "twoheadrightarrow": result = Rune(0x021A0)
-  of "Darr": result = Rune(0x021A1)
-  of "larrtl", "leftarrowtail": result = Rune(0x021A2)
-  of "rarrtl", "rightarrowtail": result = Rune(0x021A3)
-  of "LeftTeeArrow", "mapstoleft": result = Rune(0x021A4)
-  of "UpTeeArrow", "mapstoup": result = Rune(0x021A5)
-  of "map", "RightTeeArrow", "mapsto": result = Rune(0x021A6)
-  of "DownTeeArrow", "mapstodown": result = Rune(0x021A7)
-  of "larrhk", "hookleftarrow": result = Rune(0x021A9)
-  of "rarrhk", "hookrightarrow": result = Rune(0x021AA)
-  of "larrlp", "looparrowleft": result = Rune(0x021AB)
-  of "rarrlp", "looparrowright": result = Rune(0x021AC)
-  of "harrw", "leftrightsquigarrow": result = Rune(0x021AD)
-  of "nharr", "nleftrightarrow": result = Rune(0x021AE)
-  of "lsh", "Lsh": result = Rune(0x021B0)
-  of "rsh", "Rsh": result = Rune(0x021B1)
-  of "ldsh": result = Rune(0x021B2)
-  of "rdsh": result = Rune(0x021B3)
-  of "crarr": result = Rune(0x021B5)
-  of "cularr", "curvearrowleft": result = Rune(0x021B6)
-  of "curarr", "curvearrowright": result = Rune(0x021B7)
-  of "olarr", "circlearrowleft": result = Rune(0x021BA)
-  of "orarr", "circlearrowright": result = Rune(0x021BB)
-  of "lharu", "LeftVector", "leftharpoonup": result = Rune(0x021BC)
-  of "lhard", "leftharpoondown", "DownLeftVector": result = Rune(0x021BD)
-  of "uharr", "upharpoonright", "RightUpVector": result = Rune(0x021BE)
-  of "uharl", "upharpoonleft", "LeftUpVector": result = Rune(0x021BF)
-  of "rharu", "RightVector", "rightharpoonup": result = Rune(0x021C0)
-  of "rhard", "rightharpoondown", "DownRightVector": result = Rune(0x021C1)
-  of "dharr", "RightDownVector", "downharpoonright": result = Rune(0x021C2)
-  of "dharl", "LeftDownVector", "downharpoonleft": result = Rune(0x021C3)
-  of "rlarr", "rightleftarrows", "RightArrowLeftArrow": result = Rune(0x021C4)
-  of "udarr", "UpArrowDownArrow": result = Rune(0x021C5)
-  of "lrarr", "leftrightarrows", "LeftArrowRightArrow": result = Rune(0x021C6)
-  of "llarr", "leftleftarrows": result = Rune(0x021C7)
-  of "uuarr", "upuparrows": result = Rune(0x021C8)
-  of "rrarr", "rightrightarrows": result = Rune(0x021C9)
-  of "ddarr", "downdownarrows": result = Rune(0x021CA)
+    "ShortDownArrow": Rune(0x02193)
+  of "harr", "leftrightarrow", "LeftRightArrow": Rune(0x02194)
+  of "varr", "updownarrow", "UpDownArrow": Rune(0x02195)
+  of "nwarr", "UpperLeftArrow", "nwarrow": Rune(0x02196)
+  of "nearr", "UpperRightArrow", "nearrow": Rune(0x02197)
+  of "searr", "searrow", "LowerRightArrow": Rune(0x02198)
+  of "swarr", "swarrow", "LowerLeftArrow": Rune(0x02199)
+  of "nlarr", "nleftarrow": Rune(0x0219A)
+  of "nrarr", "nrightarrow": Rune(0x0219B)
+  of "rarrw", "rightsquigarrow": Rune(0x0219D)
+  of "Larr", "twoheadleftarrow": Rune(0x0219E)
+  of "Uarr": Rune(0x0219F)
+  of "Rarr", "twoheadrightarrow": Rune(0x021A0)
+  of "Darr": Rune(0x021A1)
+  of "larrtl", "leftarrowtail": Rune(0x021A2)
+  of "rarrtl", "rightarrowtail": Rune(0x021A3)
+  of "LeftTeeArrow", "mapstoleft": Rune(0x021A4)
+  of "UpTeeArrow", "mapstoup": Rune(0x021A5)
+  of "map", "RightTeeArrow", "mapsto": Rune(0x021A6)
+  of "DownTeeArrow", "mapstodown": Rune(0x021A7)
+  of "larrhk", "hookleftarrow": Rune(0x021A9)
+  of "rarrhk", "hookrightarrow": Rune(0x021AA)
+  of "larrlp", "looparrowleft": Rune(0x021AB)
+  of "rarrlp", "looparrowright": Rune(0x021AC)
+  of "harrw", "leftrightsquigarrow": Rune(0x021AD)
+  of "nharr", "nleftrightarrow": Rune(0x021AE)
+  of "lsh", "Lsh": Rune(0x021B0)
+  of "rsh", "Rsh": Rune(0x021B1)
+  of "ldsh": Rune(0x021B2)
+  of "rdsh": Rune(0x021B3)
+  of "crarr": Rune(0x021B5)
+  of "cularr", "curvearrowleft": Rune(0x021B6)
+  of "curarr", "curvearrowright": Rune(0x021B7)
+  of "olarr", "circlearrowleft": Rune(0x021BA)
+  of "orarr", "circlearrowright": Rune(0x021BB)
+  of "lharu", "LeftVector", "leftharpoonup": Rune(0x021BC)
+  of "lhard", "leftharpoondown", "DownLeftVector": Rune(0x021BD)
+  of "uharr", "upharpoonright", "RightUpVector": Rune(0x021BE)
+  of "uharl", "upharpoonleft", "LeftUpVector": Rune(0x021BF)
+  of "rharu", "RightVector", "rightharpoonup": Rune(0x021C0)
+  of "rhard", "rightharpoondown", "DownRightVector": Rune(0x021C1)
+  of "dharr", "RightDownVector", "downharpoonright": Rune(0x021C2)
+  of "dharl", "LeftDownVector", "downharpoonleft": Rune(0x021C3)
+  of "rlarr", "rightleftarrows", "RightArrowLeftArrow": Rune(0x021C4)
+  of "udarr", "UpArrowDownArrow": Rune(0x021C5)
+  of "lrarr", "leftrightarrows", "LeftArrowRightArrow": Rune(0x021C6)
+  of "llarr", "leftleftarrows": Rune(0x021C7)
+  of "uuarr", "upuparrows": Rune(0x021C8)
+  of "rrarr", "rightrightarrows": Rune(0x021C9)
+  of "ddarr", "downdownarrows": Rune(0x021CA)
   of "lrhar", "ReverseEquilibrium",
-    "leftrightharpoons": result = Rune(0x021CB)
-  of "rlhar", "rightleftharpoons", "Equilibrium": result = Rune(0x021CC)
-  of "nlArr", "nLeftarrow": result = Rune(0x021CD)
-  of "nhArr", "nLeftrightarrow": result = Rune(0x021CE)
-  of "nrArr", "nRightarrow": result = Rune(0x021CF)
-  of "lArr", "Leftarrow", "DoubleLeftArrow": result = Rune(0x021D0)
-  of "uArr", "Uparrow", "DoubleUpArrow": result = Rune(0x021D1)
+    "leftrightharpoons": Rune(0x021CB)
+  of "rlhar", "rightleftharpoons", "Equilibrium": Rune(0x021CC)
+  of "nlArr", "nLeftarrow": Rune(0x021CD)
+  of "nhArr", "nLeftrightarrow": Rune(0x021CE)
+  of "nrArr", "nRightarrow": Rune(0x021CF)
+  of "lArr", "Leftarrow", "DoubleLeftArrow": Rune(0x021D0)
+  of "uArr", "Uparrow", "DoubleUpArrow": Rune(0x021D1)
   of "rArr", "Rightarrow", "Implies",
-    "DoubleRightArrow": result = Rune(0x021D2)
-  of "dArr", "Downarrow", "DoubleDownArrow": result = Rune(0x021D3)
+    "DoubleRightArrow": Rune(0x021D2)
+  of "dArr", "Downarrow", "DoubleDownArrow": Rune(0x021D3)
   of "hArr", "Leftrightarrow", "DoubleLeftRightArrow",
-    "iff": result = Rune(0x021D4)
-  of "vArr", "Updownarrow", "DoubleUpDownArrow": result = Rune(0x021D5)
-  of "nwArr": result = Rune(0x021D6)
-  of "neArr": result = Rune(0x021D7)
-  of "seArr": result = Rune(0x021D8)
-  of "swArr": result = Rune(0x021D9)
-  of "lAarr", "Lleftarrow": result = Rune(0x021DA)
-  of "rAarr", "Rrightarrow": result = Rune(0x021DB)
-  of "zigrarr": result = Rune(0x021DD)
-  of "larrb", "LeftArrowBar": result = Rune(0x021E4)
-  of "rarrb", "RightArrowBar": result = Rune(0x021E5)
-  of "duarr", "DownArrowUpArrow": result = Rune(0x021F5)
-  of "loarr": result = Rune(0x021FD)
-  of "roarr": result = Rune(0x021FE)
-  of "hoarr": result = Rune(0x021FF)
-  of "forall", "ForAll": result = Rune(0x02200)
-  of "comp", "complement": result = Rune(0x02201)
-  of "part", "PartialD": result = Rune(0x02202)
-  of "exist", "Exists": result = Rune(0x02203)
-  of "nexist", "NotExists", "nexists": result = Rune(0x02204)
-  of "empty", "emptyset", "emptyv", "varnothing": result = Rune(0x02205)
-  of "nabla", "Del": result = Rune(0x02207)
-  of "isin", "isinv", "Element", "in": result = Rune(0x02208)
-  of "notin", "NotElement", "notinva": result = Rune(0x02209)
-  of "niv", "ReverseElement", "ni", "SuchThat": result = Rune(0x0220B)
-  of "notni", "notniva", "NotReverseElement": result = Rune(0x0220C)
-  of "prod", "Product": result = Rune(0x0220F)
-  of "coprod", "Coproduct": result = Rune(0x02210)
-  of "sum", "Sum": result = Rune(0x02211)
-  of "minus": result = Rune(0x02212)
-  of "mnplus", "mp", "MinusPlus": result = Rune(0x02213)
-  of "plusdo", "dotplus": result = Rune(0x02214)
+    "iff": Rune(0x021D4)
+  of "vArr", "Updownarrow", "DoubleUpDownArrow": Rune(0x021D5)
+  of "nwArr": Rune(0x021D6)
+  of "neArr": Rune(0x021D7)
+  of "seArr": Rune(0x021D8)
+  of "swArr": Rune(0x021D9)
+  of "lAarr", "Lleftarrow": Rune(0x021DA)
+  of "rAarr", "Rrightarrow": Rune(0x021DB)
+  of "zigrarr": Rune(0x021DD)
+  of "larrb", "LeftArrowBar": Rune(0x021E4)
+  of "rarrb", "RightArrowBar": Rune(0x021E5)
+  of "duarr", "DownArrowUpArrow": Rune(0x021F5)
+  of "loarr": Rune(0x021FD)
+  of "roarr": Rune(0x021FE)
+  of "hoarr": Rune(0x021FF)
+  of "forall", "ForAll": Rune(0x02200)
+  of "comp", "complement": Rune(0x02201)
+  of "part", "PartialD": Rune(0x02202)
+  of "exist", "Exists": Rune(0x02203)
+  of "nexist", "NotExists", "nexists": Rune(0x02204)
+  of "empty", "emptyset", "emptyv", "varnothing": Rune(0x02205)
+  of "nabla", "Del": Rune(0x02207)
+  of "isin", "isinv", "Element", "in": Rune(0x02208)
+  of "notin", "NotElement", "notinva": Rune(0x02209)
+  of "niv", "ReverseElement", "ni", "SuchThat": Rune(0x0220B)
+  of "notni", "notniva", "NotReverseElement": Rune(0x0220C)
+  of "prod", "Product": Rune(0x0220F)
+  of "coprod", "Coproduct": Rune(0x02210)
+  of "sum", "Sum": Rune(0x02211)
+  of "minus": Rune(0x02212)
+  of "mnplus", "mp", "MinusPlus": Rune(0x02213)
+  of "plusdo", "dotplus": Rune(0x02214)
   of "setmn", "setminus", "Backslash", "ssetmn",
-    "smallsetminus": result = Rune(0x02216)
-  of "lowast": result = Rune(0x02217)
-  of "compfn", "SmallCircle": result = Rune(0x02218)
-  of "radic", "Sqrt": result = Rune(0x0221A)
+    "smallsetminus": Rune(0x02216)
+  of "lowast": Rune(0x02217)
+  of "compfn", "SmallCircle": Rune(0x02218)
+  of "radic", "Sqrt": Rune(0x0221A)
   of "prop", "propto", "Proportional", "vprop",
-    "varpropto": result = Rune(0x0221D)
-  of "infin": result = Rune(0x0221E)
-  of "angrt": result = Rune(0x0221F)
-  of "ang", "angle": result = Rune(0x02220)
-  of "angmsd", "measuredangle": result = Rune(0x02221)
-  of "angsph": result = Rune(0x02222)
-  of "mid", "VerticalBar", "smid", "shortmid": result = Rune(0x02223)
-  of "nmid", "NotVerticalBar", "nsmid", "nshortmid": result = Rune(0x02224)
+    "varpropto": Rune(0x0221D)
+  of "infin": Rune(0x0221E)
+  of "angrt": Rune(0x0221F)
+  of "ang", "angle": Rune(0x02220)
+  of "angmsd", "measuredangle": Rune(0x02221)
+  of "angsph": Rune(0x02222)
+  of "mid", "VerticalBar", "smid", "shortmid": Rune(0x02223)
+  of "nmid", "NotVerticalBar", "nsmid", "nshortmid": Rune(0x02224)
   of "par", "parallel", "DoubleVerticalBar", "spar",
-    "shortparallel": result = Rune(0x02225)
+    "shortparallel": Rune(0x02225)
   of "npar", "nparallel", "NotDoubleVerticalBar", "nspar",
-    "nshortparallel": result = Rune(0x02226)
-  of "and", "wedge": result = Rune(0x02227)
-  of "or", "vee": result = Rune(0x02228)
-  of "cap": result = Rune(0x02229)
-  of "cup": result = Rune(0x0222A)
-  of "int", "Integral": result = Rune(0x0222B)
-  of "Int": result = Rune(0x0222C)
-  of "tint", "iiint": result = Rune(0x0222D)
-  of "conint", "oint", "ContourIntegral": result = Rune(0x0222E)
-  of "Conint", "DoubleContourIntegral": result = Rune(0x0222F)
-  of "Cconint": result = Rune(0x02230)
-  of "cwint": result = Rune(0x02231)
-  of "cwconint", "ClockwiseContourIntegral": result = Rune(0x02232)
-  of "awconint", "CounterClockwiseContourIntegral": result = Rune(0x02233)
-  of "there4", "therefore", "Therefore": result = Rune(0x02234)
-  of "becaus", "because", "Because": result = Rune(0x02235)
-  of "ratio": result = Rune(0x02236)
-  of "Colon", "Proportion": result = Rune(0x02237)
-  of "minusd", "dotminus": result = Rune(0x02238)
-  of "mDDot": result = Rune(0x0223A)
-  of "homtht": result = Rune(0x0223B)
-  of "sim", "Tilde", "thksim", "thicksim": result = Rune(0x0223C)
-  of "bsim", "backsim": result = Rune(0x0223D)
-  of "ac", "mstpos": result = Rune(0x0223E)
-  of "acd": result = Rune(0x0223F)
-  of "wreath", "VerticalTilde", "wr": result = Rune(0x02240)
-  of "nsim", "NotTilde": result = Rune(0x02241)
-  of "esim", "EqualTilde", "eqsim": result = Rune(0x02242)
-  of "sime", "TildeEqual", "simeq": result = Rune(0x02243)
-  of "nsime", "nsimeq", "NotTildeEqual": result = Rune(0x02244)
-  of "cong", "TildeFullEqual": result = Rune(0x02245)
-  of "simne": result = Rune(0x02246)
-  of "ncong", "NotTildeFullEqual": result = Rune(0x02247)
+    "nshortparallel": Rune(0x02226)
+  of "and", "wedge": Rune(0x02227)
+  of "or", "vee": Rune(0x02228)
+  of "cap": Rune(0x02229)
+  of "cup": Rune(0x0222A)
+  of "int", "Integral": Rune(0x0222B)
+  of "Int": Rune(0x0222C)
+  of "tint", "iiint": Rune(0x0222D)
+  of "conint", "oint", "ContourIntegral": Rune(0x0222E)
+  of "Conint", "DoubleContourIntegral": Rune(0x0222F)
+  of "Cconint": Rune(0x02230)
+  of "cwint": Rune(0x02231)
+  of "cwconint", "ClockwiseContourIntegral": Rune(0x02232)
+  of "awconint", "CounterClockwiseContourIntegral": Rune(0x02233)
+  of "there4", "therefore", "Therefore": Rune(0x02234)
+  of "becaus", "because", "Because": Rune(0x02235)
+  of "ratio": Rune(0x02236)
+  of "Colon", "Proportion": Rune(0x02237)
+  of "minusd", "dotminus": Rune(0x02238)
+  of "mDDot": Rune(0x0223A)
+  of "homtht": Rune(0x0223B)
+  of "sim", "Tilde", "thksim", "thicksim": Rune(0x0223C)
+  of "bsim", "backsim": Rune(0x0223D)
+  of "ac", "mstpos": Rune(0x0223E)
+  of "acd": Rune(0x0223F)
+  of "wreath", "VerticalTilde", "wr": Rune(0x02240)
+  of "nsim", "NotTilde": Rune(0x02241)
+  of "esim", "EqualTilde", "eqsim": Rune(0x02242)
+  of "sime", "TildeEqual", "simeq": Rune(0x02243)
+  of "nsime", "nsimeq", "NotTildeEqual": Rune(0x02244)
+  of "cong", "TildeFullEqual": Rune(0x02245)
+  of "simne": Rune(0x02246)
+  of "ncong", "NotTildeFullEqual": Rune(0x02247)
   of "asymp", "ap", "TildeTilde", "approx", "thkap",
-    "thickapprox": result = Rune(0x02248)
-  of "nap", "NotTildeTilde", "napprox": result = Rune(0x02249)
-  of "ape", "approxeq": result = Rune(0x0224A)
-  of "apid": result = Rune(0x0224B)
-  of "bcong", "backcong": result = Rune(0x0224C)
-  of "asympeq", "CupCap": result = Rune(0x0224D)
-  of "bump", "HumpDownHump", "Bumpeq": result = Rune(0x0224E)
-  of "bumpe", "HumpEqual", "bumpeq": result = Rune(0x0224F)
-  of "esdot", "DotEqual", "doteq": result = Rune(0x02250)
-  of "eDot", "doteqdot": result = Rune(0x02251)
-  of "efDot", "fallingdotseq": result = Rune(0x02252)
-  of "erDot", "risingdotseq": result = Rune(0x02253)
-  of "colone", "coloneq", "Assign": result = Rune(0x02254)
-  of "ecolon", "eqcolon": result = Rune(0x02255)
-  of "ecir", "eqcirc": result = Rune(0x02256)
-  of "cire", "circeq": result = Rune(0x02257)
-  of "wedgeq": result = Rune(0x02259)
-  of "veeeq": result = Rune(0x0225A)
-  of "trie", "triangleq": result = Rune(0x0225C)
-  of "equest", "questeq": result = Rune(0x0225F)
-  of "ne", "NotEqual": result = Rune(0x02260)
-  of "equiv", "Congruent": result = Rune(0x02261)
-  of "nequiv", "NotCongruent": result = Rune(0x02262)
-  of "le", "leq": result = Rune(0x02264)
-  of "ge", "GreaterEqual", "geq": result = Rune(0x02265)
-  of "lE", "LessFullEqual", "leqq": result = Rune(0x02266)
-  of "gE", "GreaterFullEqual", "geqq": result = Rune(0x02267)
-  of "lnE", "lneqq": result = Rune(0x02268)
-  of "gnE", "gneqq": result = Rune(0x02269)
-  of "Lt", "NestedLessLess", "ll": result = Rune(0x0226A)
-  of "Gt", "NestedGreaterGreater", "gg": result = Rune(0x0226B)
-  of "twixt", "between": result = Rune(0x0226C)
-  of "NotCupCap": result = Rune(0x0226D)
-  of "nlt", "NotLess", "nless": result = Rune(0x0226E)
-  of "ngt", "NotGreater", "ngtr": result = Rune(0x0226F)
-  of "nle", "NotLessEqual", "nleq": result = Rune(0x02270)
-  of "nge", "NotGreaterEqual", "ngeq": result = Rune(0x02271)
-  of "lsim", "LessTilde", "lesssim": result = Rune(0x02272)
-  of "gsim", "gtrsim", "GreaterTilde": result = Rune(0x02273)
-  of "nlsim", "NotLessTilde": result = Rune(0x02274)
-  of "ngsim", "NotGreaterTilde": result = Rune(0x02275)
-  of "lg", "lessgtr", "LessGreater": result = Rune(0x02276)
-  of "gl", "gtrless", "GreaterLess": result = Rune(0x02277)
-  of "ntlg", "NotLessGreater": result = Rune(0x02278)
-  of "ntgl", "NotGreaterLess": result = Rune(0x02279)
-  of "pr", "Precedes", "prec": result = Rune(0x0227A)
-  of "sc", "Succeeds", "succ": result = Rune(0x0227B)
-  of "prcue", "PrecedesSlantEqual", "preccurlyeq": result = Rune(0x0227C)
-  of "sccue", "SucceedsSlantEqual", "succcurlyeq": result = Rune(0x0227D)
-  of "prsim", "precsim", "PrecedesTilde": result = Rune(0x0227E)
-  of "scsim", "succsim", "SucceedsTilde": result = Rune(0x0227F)
-  of "npr", "nprec", "NotPrecedes": result = Rune(0x02280)
-  of "nsc", "nsucc", "NotSucceeds": result = Rune(0x02281)
-  of "sub", "subset": result = Rune(0x02282)
-  of "sup", "supset", "Superset": result = Rune(0x02283)
-  of "nsub": result = Rune(0x02284)
-  of "nsup": result = Rune(0x02285)
-  of "sube", "SubsetEqual", "subseteq": result = Rune(0x02286)
-  of "supe", "supseteq", "SupersetEqual": result = Rune(0x02287)
-  of "nsube", "nsubseteq", "NotSubsetEqual": result = Rune(0x02288)
-  of "nsupe", "nsupseteq", "NotSupersetEqual": result = Rune(0x02289)
-  of "subne", "subsetneq": result = Rune(0x0228A)
-  of "supne", "supsetneq": result = Rune(0x0228B)
-  of "cupdot": result = Rune(0x0228D)
-  of "uplus", "UnionPlus": result = Rune(0x0228E)
-  of "sqsub", "SquareSubset", "sqsubset": result = Rune(0x0228F)
-  of "sqsup", "SquareSuperset", "sqsupset": result = Rune(0x02290)
-  of "sqsube", "SquareSubsetEqual", "sqsubseteq": result = Rune(0x02291)
-  of "sqsupe", "SquareSupersetEqual", "sqsupseteq": result = Rune(0x02292)
-  of "sqcap", "SquareIntersection": result = Rune(0x02293)
-  of "sqcup", "SquareUnion": result = Rune(0x02294)
-  of "oplus", "CirclePlus": result = Rune(0x02295)
-  of "ominus", "CircleMinus": result = Rune(0x02296)
-  of "otimes", "CircleTimes": result = Rune(0x02297)
-  of "osol": result = Rune(0x02298)
-  of "odot", "CircleDot": result = Rune(0x02299)
-  of "ocir", "circledcirc": result = Rune(0x0229A)
-  of "oast", "circledast": result = Rune(0x0229B)
-  of "odash", "circleddash": result = Rune(0x0229D)
-  of "plusb", "boxplus": result = Rune(0x0229E)
-  of "minusb", "boxminus": result = Rune(0x0229F)
-  of "timesb", "boxtimes": result = Rune(0x022A0)
-  of "sdotb", "dotsquare": result = Rune(0x022A1)
-  of "vdash", "RightTee": result = Rune(0x022A2)
-  of "dashv", "LeftTee": result = Rune(0x022A3)
-  of "top", "DownTee": result = Rune(0x022A4)
-  of "bottom", "bot", "perp", "UpTee": result = Rune(0x022A5)
-  of "models": result = Rune(0x022A7)
-  of "vDash", "DoubleRightTee": result = Rune(0x022A8)
-  of "Vdash": result = Rune(0x022A9)
-  of "Vvdash": result = Rune(0x022AA)
-  of "VDash": result = Rune(0x022AB)
-  of "nvdash": result = Rune(0x022AC)
-  of "nvDash": result = Rune(0x022AD)
-  of "nVdash": result = Rune(0x022AE)
-  of "nVDash": result = Rune(0x022AF)
-  of "prurel": result = Rune(0x022B0)
-  of "vltri", "vartriangleleft", "LeftTriangle": result = Rune(0x022B2)
-  of "vrtri", "vartriangleright", "RightTriangle": result = Rune(0x022B3)
-  of "ltrie", "trianglelefteq", "LeftTriangleEqual": result = Rune(0x022B4)
-  of "rtrie", "trianglerighteq", "RightTriangleEqual": result = Rune(0x022B5)
-  of "origof": result = Rune(0x022B6)
-  of "imof": result = Rune(0x022B7)
-  of "mumap", "multimap": result = Rune(0x022B8)
-  of "hercon": result = Rune(0x022B9)
-  of "intcal", "intercal": result = Rune(0x022BA)
-  of "veebar": result = Rune(0x022BB)
-  of "barvee": result = Rune(0x022BD)
-  of "angrtvb": result = Rune(0x022BE)
-  of "lrtri": result = Rune(0x022BF)
-  of "xwedge", "Wedge", "bigwedge": result = Rune(0x022C0)
-  of "xvee", "Vee", "bigvee": result = Rune(0x022C1)
-  of "xcap", "Intersection", "bigcap": result = Rune(0x022C2)
-  of "xcup", "Union", "bigcup": result = Rune(0x022C3)
-  of "diam", "diamond", "Diamond": result = Rune(0x022C4)
-  of "sdot": result = Rune(0x022C5)
-  of "sstarf", "Star": result = Rune(0x022C6)
-  of "divonx", "divideontimes": result = Rune(0x022C7)
-  of "bowtie": result = Rune(0x022C8)
-  of "ltimes": result = Rune(0x022C9)
-  of "rtimes": result = Rune(0x022CA)
-  of "lthree", "leftthreetimes": result = Rune(0x022CB)
-  of "rthree", "rightthreetimes": result = Rune(0x022CC)
-  of "bsime", "backsimeq": result = Rune(0x022CD)
-  of "cuvee", "curlyvee": result = Rune(0x022CE)
-  of "cuwed", "curlywedge": result = Rune(0x022CF)
-  of "Sub", "Subset": result = Rune(0x022D0)
-  of "Sup", "Supset": result = Rune(0x022D1)
-  of "Cap": result = Rune(0x022D2)
-  of "Cup": result = Rune(0x022D3)
-  of "fork", "pitchfork": result = Rune(0x022D4)
-  of "epar": result = Rune(0x022D5)
-  of "ltdot", "lessdot": result = Rune(0x022D6)
-  of "gtdot", "gtrdot": result = Rune(0x022D7)
-  of "Ll": result = Rune(0x022D8)
-  of "Gg", "ggg": result = Rune(0x022D9)
-  of "leg", "LessEqualGreater", "lesseqgtr": result = Rune(0x022DA)
-  of "gel", "gtreqless", "GreaterEqualLess": result = Rune(0x022DB)
-  of "cuepr", "curlyeqprec": result = Rune(0x022DE)
-  of "cuesc", "curlyeqsucc": result = Rune(0x022DF)
-  of "nprcue", "NotPrecedesSlantEqual": result = Rune(0x022E0)
-  of "nsccue", "NotSucceedsSlantEqual": result = Rune(0x022E1)
-  of "nsqsube", "NotSquareSubsetEqual": result = Rune(0x022E2)
-  of "nsqsupe", "NotSquareSupersetEqual": result = Rune(0x022E3)
-  of "lnsim": result = Rune(0x022E6)
-  of "gnsim": result = Rune(0x022E7)
-  of "prnsim", "precnsim": result = Rune(0x022E8)
-  of "scnsim", "succnsim": result = Rune(0x022E9)
-  of "nltri", "ntriangleleft", "NotLeftTriangle": result = Rune(0x022EA)
-  of "nrtri", "ntriangleright", "NotRightTriangle": result = Rune(0x022EB)
+    "thickapprox": Rune(0x02248)
+  of "nap", "NotTildeTilde", "napprox": Rune(0x02249)
+  of "ape", "approxeq": Rune(0x0224A)
+  of "apid": Rune(0x0224B)
+  of "bcong", "backcong": Rune(0x0224C)
+  of "asympeq", "CupCap": Rune(0x0224D)
+  of "bump", "HumpDownHump", "Bumpeq": Rune(0x0224E)
+  of "bumpe", "HumpEqual", "bumpeq": Rune(0x0224F)
+  of "esdot", "DotEqual", "doteq": Rune(0x02250)
+  of "eDot", "doteqdot": Rune(0x02251)
+  of "efDot", "fallingdotseq": Rune(0x02252)
+  of "erDot", "risingdotseq": Rune(0x02253)
+  of "colone", "coloneq", "Assign": Rune(0x02254)
+  of "ecolon", "eqcolon": Rune(0x02255)
+  of "ecir", "eqcirc": Rune(0x02256)
+  of "cire", "circeq": Rune(0x02257)
+  of "wedgeq": Rune(0x02259)
+  of "veeeq": Rune(0x0225A)
+  of "trie", "triangleq": Rune(0x0225C)
+  of "equest", "questeq": Rune(0x0225F)
+  of "ne", "NotEqual": Rune(0x02260)
+  of "equiv", "Congruent": Rune(0x02261)
+  of "nequiv", "NotCongruent": Rune(0x02262)
+  of "le", "leq": Rune(0x02264)
+  of "ge", "GreaterEqual", "geq": Rune(0x02265)
+  of "lE", "LessFullEqual", "leqq": Rune(0x02266)
+  of "gE", "GreaterFullEqual", "geqq": Rune(0x02267)
+  of "lnE", "lneqq": Rune(0x02268)
+  of "gnE", "gneqq": Rune(0x02269)
+  of "Lt", "NestedLessLess", "ll": Rune(0x0226A)
+  of "Gt", "NestedGreaterGreater", "gg": Rune(0x0226B)
+  of "twixt", "between": Rune(0x0226C)
+  of "NotCupCap": Rune(0x0226D)
+  of "nlt", "NotLess", "nless": Rune(0x0226E)
+  of "ngt", "NotGreater", "ngtr": Rune(0x0226F)
+  of "nle", "NotLessEqual", "nleq": Rune(0x02270)
+  of "nge", "NotGreaterEqual", "ngeq": Rune(0x02271)
+  of "lsim", "LessTilde", "lesssim": Rune(0x02272)
+  of "gsim", "gtrsim", "GreaterTilde": Rune(0x02273)
+  of "nlsim", "NotLessTilde": Rune(0x02274)
+  of "ngsim", "NotGreaterTilde": Rune(0x02275)
+  of "lg", "lessgtr", "LessGreater": Rune(0x02276)
+  of "gl", "gtrless", "GreaterLess": Rune(0x02277)
+  of "ntlg", "NotLessGreater": Rune(0x02278)
+  of "ntgl", "NotGreaterLess": Rune(0x02279)
+  of "pr", "Precedes", "prec": Rune(0x0227A)
+  of "sc", "Succeeds", "succ": Rune(0x0227B)
+  of "prcue", "PrecedesSlantEqual", "preccurlyeq": Rune(0x0227C)
+  of "sccue", "SucceedsSlantEqual", "succcurlyeq": Rune(0x0227D)
+  of "prsim", "precsim", "PrecedesTilde": Rune(0x0227E)
+  of "scsim", "succsim", "SucceedsTilde": Rune(0x0227F)
+  of "npr", "nprec", "NotPrecedes": Rune(0x02280)
+  of "nsc", "nsucc", "NotSucceeds": Rune(0x02281)
+  of "sub", "subset": Rune(0x02282)
+  of "sup", "supset", "Superset": Rune(0x02283)
+  of "nsub": Rune(0x02284)
+  of "nsup": Rune(0x02285)
+  of "sube", "SubsetEqual", "subseteq": Rune(0x02286)
+  of "supe", "supseteq", "SupersetEqual": Rune(0x02287)
+  of "nsube", "nsubseteq", "NotSubsetEqual": Rune(0x02288)
+  of "nsupe", "nsupseteq", "NotSupersetEqual": Rune(0x02289)
+  of "subne", "subsetneq": Rune(0x0228A)
+  of "supne", "supsetneq": Rune(0x0228B)
+  of "cupdot": Rune(0x0228D)
+  of "uplus", "UnionPlus": Rune(0x0228E)
+  of "sqsub", "SquareSubset", "sqsubset": Rune(0x0228F)
+  of "sqsup", "SquareSuperset", "sqsupset": Rune(0x02290)
+  of "sqsube", "SquareSubsetEqual", "sqsubseteq": Rune(0x02291)
+  of "sqsupe", "SquareSupersetEqual", "sqsupseteq": Rune(0x02292)
+  of "sqcap", "SquareIntersection": Rune(0x02293)
+  of "sqcup", "SquareUnion": Rune(0x02294)
+  of "oplus", "CirclePlus": Rune(0x02295)
+  of "ominus", "CircleMinus": Rune(0x02296)
+  of "otimes", "CircleTimes": Rune(0x02297)
+  of "osol": Rune(0x02298)
+  of "odot", "CircleDot": Rune(0x02299)
+  of "ocir", "circledcirc": Rune(0x0229A)
+  of "oast", "circledast": Rune(0x0229B)
+  of "odash", "circleddash": Rune(0x0229D)
+  of "plusb", "boxplus": Rune(0x0229E)
+  of "minusb", "boxminus": Rune(0x0229F)
+  of "timesb", "boxtimes": Rune(0x022A0)
+  of "sdotb", "dotsquare": Rune(0x022A1)
+  of "vdash", "RightTee": Rune(0x022A2)
+  of "dashv", "LeftTee": Rune(0x022A3)
+  of "top", "DownTee": Rune(0x022A4)
+  of "bottom", "bot", "perp", "UpTee": Rune(0x022A5)
+  of "models": Rune(0x022A7)
+  of "vDash", "DoubleRightTee": Rune(0x022A8)
+  of "Vdash": Rune(0x022A9)
+  of "Vvdash": Rune(0x022AA)
+  of "VDash": Rune(0x022AB)
+  of "nvdash": Rune(0x022AC)
+  of "nvDash": Rune(0x022AD)
+  of "nVdash": Rune(0x022AE)
+  of "nVDash": Rune(0x022AF)
+  of "prurel": Rune(0x022B0)
+  of "vltri", "vartriangleleft", "LeftTriangle": Rune(0x022B2)
+  of "vrtri", "vartriangleright", "RightTriangle": Rune(0x022B3)
+  of "ltrie", "trianglelefteq", "LeftTriangleEqual": Rune(0x022B4)
+  of "rtrie", "trianglerighteq", "RightTriangleEqual": Rune(0x022B5)
+  of "origof": Rune(0x022B6)
+  of "imof": Rune(0x022B7)
+  of "mumap", "multimap": Rune(0x022B8)
+  of "hercon": Rune(0x022B9)
+  of "intcal", "intercal": Rune(0x022BA)
+  of "veebar": Rune(0x022BB)
+  of "barvee": Rune(0x022BD)
+  of "angrtvb": Rune(0x022BE)
+  of "lrtri": Rune(0x022BF)
+  of "xwedge", "Wedge", "bigwedge": Rune(0x022C0)
+  of "xvee", "Vee", "bigvee": Rune(0x022C1)
+  of "xcap", "Intersection", "bigcap": Rune(0x022C2)
+  of "xcup", "Union", "bigcup": Rune(0x022C3)
+  of "diam", "diamond", "Diamond": Rune(0x022C4)
+  of "sdot": Rune(0x022C5)
+  of "sstarf", "Star": Rune(0x022C6)
+  of "divonx", "divideontimes": Rune(0x022C7)
+  of "bowtie": Rune(0x022C8)
+  of "ltimes": Rune(0x022C9)
+  of "rtimes": Rune(0x022CA)
+  of "lthree", "leftthreetimes": Rune(0x022CB)
+  of "rthree", "rightthreetimes": Rune(0x022CC)
+  of "bsime", "backsimeq": Rune(0x022CD)
+  of "cuvee", "curlyvee": Rune(0x022CE)
+  of "cuwed", "curlywedge": Rune(0x022CF)
+  of "Sub", "Subset": Rune(0x022D0)
+  of "Sup", "Supset": Rune(0x022D1)
+  of "Cap": Rune(0x022D2)
+  of "Cup": Rune(0x022D3)
+  of "fork", "pitchfork": Rune(0x022D4)
+  of "epar": Rune(0x022D5)
+  of "ltdot", "lessdot": Rune(0x022D6)
+  of "gtdot", "gtrdot": Rune(0x022D7)
+  of "Ll": Rune(0x022D8)
+  of "Gg", "ggg": Rune(0x022D9)
+  of "leg", "LessEqualGreater", "lesseqgtr": Rune(0x022DA)
+  of "gel", "gtreqless", "GreaterEqualLess": Rune(0x022DB)
+  of "cuepr", "curlyeqprec": Rune(0x022DE)
+  of "cuesc", "curlyeqsucc": Rune(0x022DF)
+  of "nprcue", "NotPrecedesSlantEqual": Rune(0x022E0)
+  of "nsccue", "NotSucceedsSlantEqual": Rune(0x022E1)
+  of "nsqsube", "NotSquareSubsetEqual": Rune(0x022E2)
+  of "nsqsupe", "NotSquareSupersetEqual": Rune(0x022E3)
+  of "lnsim": Rune(0x022E6)
+  of "gnsim": Rune(0x022E7)
+  of "prnsim", "precnsim": Rune(0x022E8)
+  of "scnsim", "succnsim": Rune(0x022E9)
+  of "nltri", "ntriangleleft", "NotLeftTriangle": Rune(0x022EA)
+  of "nrtri", "ntriangleright", "NotRightTriangle": Rune(0x022EB)
   of "nltrie", "ntrianglelefteq",
-    "NotLeftTriangleEqual": result = Rune(0x022EC)
+    "NotLeftTriangleEqual": Rune(0x022EC)
   of "nrtrie", "ntrianglerighteq",
-    "NotRightTriangleEqual": result = Rune(0x022ED)
-  of "vellip": result = Rune(0x022EE)
-  of "ctdot": result = Rune(0x022EF)
-  of "utdot": result = Rune(0x022F0)
-  of "dtdot": result = Rune(0x022F1)
-  of "disin": result = Rune(0x022F2)
-  of "isinsv": result = Rune(0x022F3)
-  of "isins": result = Rune(0x022F4)
-  of "isindot": result = Rune(0x022F5)
-  of "notinvc": result = Rune(0x022F6)
-  of "notinvb": result = Rune(0x022F7)
-  of "isinE": result = Rune(0x022F9)
-  of "nisd": result = Rune(0x022FA)
-  of "xnis": result = Rune(0x022FB)
-  of "nis": result = Rune(0x022FC)
-  of "notnivc": result = Rune(0x022FD)
-  of "notnivb": result = Rune(0x022FE)
-  of "barwed", "barwedge": result = Rune(0x02305)
-  of "Barwed", "doublebarwedge": result = Rune(0x02306)
-  of "lceil", "LeftCeiling": result = Rune(0x02308)
-  of "rceil", "RightCeiling": result = Rune(0x02309)
-  of "lfloor", "LeftFloor": result = Rune(0x0230A)
-  of "rfloor", "RightFloor": result = Rune(0x0230B)
-  of "drcrop": result = Rune(0x0230C)
-  of "dlcrop": result = Rune(0x0230D)
-  of "urcrop": result = Rune(0x0230E)
-  of "ulcrop": result = Rune(0x0230F)
-  of "bnot": result = Rune(0x02310)
-  of "profline": result = Rune(0x02312)
-  of "profsurf": result = Rune(0x02313)
-  of "telrec": result = Rune(0x02315)
-  of "target": result = Rune(0x02316)
-  of "ulcorn", "ulcorner": result = Rune(0x0231C)
-  of "urcorn", "urcorner": result = Rune(0x0231D)
-  of "dlcorn", "llcorner": result = Rune(0x0231E)
-  of "drcorn", "lrcorner": result = Rune(0x0231F)
-  of "frown", "sfrown": result = Rune(0x02322)
-  of "smile", "ssmile": result = Rune(0x02323)
-  of "cylcty": result = Rune(0x0232D)
-  of "profalar": result = Rune(0x0232E)
-  of "topbot": result = Rune(0x02336)
-  of "ovbar": result = Rune(0x0233D)
-  of "solbar": result = Rune(0x0233F)
-  of "angzarr": result = Rune(0x0237C)
-  of "lmoust", "lmoustache": result = Rune(0x023B0)
-  of "rmoust", "rmoustache": result = Rune(0x023B1)
-  of "tbrk", "OverBracket": result = Rune(0x023B4)
-  of "bbrk", "UnderBracket": result = Rune(0x023B5)
-  of "bbrktbrk": result = Rune(0x023B6)
-  of "OverParenthesis": result = Rune(0x023DC)
-  of "UnderParenthesis": result = Rune(0x023DD)
-  of "OverBrace": result = Rune(0x023DE)
-  of "UnderBrace": result = Rune(0x023DF)
-  of "trpezium": result = Rune(0x023E2)
-  of "elinters": result = Rune(0x023E7)
-  of "blank": result = Rune(0x02423)
-  of "oS", "circledS": result = Rune(0x024C8)
-  of "boxh", "HorizontalLine": result = Rune(0x02500)
-  of "boxv": result = Rune(0x02502)
-  of "boxdr": result = Rune(0x0250C)
-  of "boxdl": result = Rune(0x02510)
-  of "boxur": result = Rune(0x02514)
-  of "boxul": result = Rune(0x02518)
-  of "boxvr": result = Rune(0x0251C)
-  of "boxvl": result = Rune(0x02524)
-  of "boxhd": result = Rune(0x0252C)
-  of "boxhu": result = Rune(0x02534)
-  of "boxvh": result = Rune(0x0253C)
-  of "boxH": result = Rune(0x02550)
-  of "boxV": result = Rune(0x02551)
-  of "boxdR": result = Rune(0x02552)
-  of "boxDr": result = Rune(0x02553)
-  of "boxDR": result = Rune(0x02554)
-  of "boxdL": result = Rune(0x02555)
-  of "boxDl": result = Rune(0x02556)
-  of "boxDL": result = Rune(0x02557)
-  of "boxuR": result = Rune(0x02558)
-  of "boxUr": result = Rune(0x02559)
-  of "boxUR": result = Rune(0x0255A)
-  of "boxuL": result = Rune(0x0255B)
-  of "boxUl": result = Rune(0x0255C)
-  of "boxUL": result = Rune(0x0255D)
-  of "boxvR": result = Rune(0x0255E)
-  of "boxVr": result = Rune(0x0255F)
-  of "boxVR": result = Rune(0x02560)
-  of "boxvL": result = Rune(0x02561)
-  of "boxVl": result = Rune(0x02562)
-  of "boxVL": result = Rune(0x02563)
-  of "boxHd": result = Rune(0x02564)
-  of "boxhD": result = Rune(0x02565)
-  of "boxHD": result = Rune(0x02566)
-  of "boxHu": result = Rune(0x02567)
-  of "boxhU": result = Rune(0x02568)
-  of "boxHU": result = Rune(0x02569)
-  of "boxvH": result = Rune(0x0256A)
-  of "boxVh": result = Rune(0x0256B)
-  of "boxVH": result = Rune(0x0256C)
-  of "uhblk": result = Rune(0x02580)
-  of "lhblk": result = Rune(0x02584)
-  of "block": result = Rune(0x02588)
-  of "blk14": result = Rune(0x02591)
-  of "blk12": result = Rune(0x02592)
-  of "blk34": result = Rune(0x02593)
-  of "squ", "square", "Square": result = Rune(0x025A1)
+    "NotRightTriangleEqual": Rune(0x022ED)
+  of "vellip": Rune(0x022EE)
+  of "ctdot": Rune(0x022EF)
+  of "utdot": Rune(0x022F0)
+  of "dtdot": Rune(0x022F1)
+  of "disin": Rune(0x022F2)
+  of "isinsv": Rune(0x022F3)
+  of "isins": Rune(0x022F4)
+  of "isindot": Rune(0x022F5)
+  of "notinvc": Rune(0x022F6)
+  of "notinvb": Rune(0x022F7)
+  of "isinE": Rune(0x022F9)
+  of "nisd": Rune(0x022FA)
+  of "xnis": Rune(0x022FB)
+  of "nis": Rune(0x022FC)
+  of "notnivc": Rune(0x022FD)
+  of "notnivb": Rune(0x022FE)
+  of "barwed", "barwedge": Rune(0x02305)
+  of "Barwed", "doublebarwedge": Rune(0x02306)
+  of "lceil", "LeftCeiling": Rune(0x02308)
+  of "rceil", "RightCeiling": Rune(0x02309)
+  of "lfloor", "LeftFloor": Rune(0x0230A)
+  of "rfloor", "RightFloor": Rune(0x0230B)
+  of "drcrop": Rune(0x0230C)
+  of "dlcrop": Rune(0x0230D)
+  of "urcrop": Rune(0x0230E)
+  of "ulcrop": Rune(0x0230F)
+  of "bnot": Rune(0x02310)
+  of "profline": Rune(0x02312)
+  of "profsurf": Rune(0x02313)
+  of "telrec": Rune(0x02315)
+  of "target": Rune(0x02316)
+  of "ulcorn", "ulcorner": Rune(0x0231C)
+  of "urcorn", "urcorner": Rune(0x0231D)
+  of "dlcorn", "llcorner": Rune(0x0231E)
+  of "drcorn", "lrcorner": Rune(0x0231F)
+  of "frown", "sfrown": Rune(0x02322)
+  of "smile", "ssmile": Rune(0x02323)
+  of "cylcty": Rune(0x0232D)
+  of "profalar": Rune(0x0232E)
+  of "topbot": Rune(0x02336)
+  of "ovbar": Rune(0x0233D)
+  of "solbar": Rune(0x0233F)
+  of "angzarr": Rune(0x0237C)
+  of "lmoust", "lmoustache": Rune(0x023B0)
+  of "rmoust", "rmoustache": Rune(0x023B1)
+  of "tbrk", "OverBracket": Rune(0x023B4)
+  of "bbrk", "UnderBracket": Rune(0x023B5)
+  of "bbrktbrk": Rune(0x023B6)
+  of "OverParenthesis": Rune(0x023DC)
+  of "UnderParenthesis": Rune(0x023DD)
+  of "OverBrace": Rune(0x023DE)
+  of "UnderBrace": Rune(0x023DF)
+  of "trpezium": Rune(0x023E2)
+  of "elinters": Rune(0x023E7)
+  of "blank": Rune(0x02423)
+  of "oS", "circledS": Rune(0x024C8)
+  of "boxh", "HorizontalLine": Rune(0x02500)
+  of "boxv": Rune(0x02502)
+  of "boxdr": Rune(0x0250C)
+  of "boxdl": Rune(0x02510)
+  of "boxur": Rune(0x02514)
+  of "boxul": Rune(0x02518)
+  of "boxvr": Rune(0x0251C)
+  of "boxvl": Rune(0x02524)
+  of "boxhd": Rune(0x0252C)
+  of "boxhu": Rune(0x02534)
+  of "boxvh": Rune(0x0253C)
+  of "boxH": Rune(0x02550)
+  of "boxV": Rune(0x02551)
+  of "boxdR": Rune(0x02552)
+  of "boxDr": Rune(0x02553)
+  of "boxDR": Rune(0x02554)
+  of "boxdL": Rune(0x02555)
+  of "boxDl": Rune(0x02556)
+  of "boxDL": Rune(0x02557)
+  of "boxuR": Rune(0x02558)
+  of "boxUr": Rune(0x02559)
+  of "boxUR": Rune(0x0255A)
+  of "boxuL": Rune(0x0255B)
+  of "boxUl": Rune(0x0255C)
+  of "boxUL": Rune(0x0255D)
+  of "boxvR": Rune(0x0255E)
+  of "boxVr": Rune(0x0255F)
+  of "boxVR": Rune(0x02560)
+  of "boxvL": Rune(0x02561)
+  of "boxVl": Rune(0x02562)
+  of "boxVL": Rune(0x02563)
+  of "boxHd": Rune(0x02564)
+  of "boxhD": Rune(0x02565)
+  of "boxHD": Rune(0x02566)
+  of "boxHu": Rune(0x02567)
+  of "boxhU": Rune(0x02568)
+  of "boxHU": Rune(0x02569)
+  of "boxvH": Rune(0x0256A)
+  of "boxVh": Rune(0x0256B)
+  of "boxVH": Rune(0x0256C)
+  of "uhblk": Rune(0x02580)
+  of "lhblk": Rune(0x02584)
+  of "block": Rune(0x02588)
+  of "blk14": Rune(0x02591)
+  of "blk12": Rune(0x02592)
+  of "blk34": Rune(0x02593)
+  of "squ", "square", "Square": Rune(0x025A1)
   of "squf", "squarf", "blacksquare",
-    "FilledVerySmallSquare": result = Rune(0x025AA)
-  of "EmptyVerySmallSquare": result = Rune(0x025AB)
-  of "rect": result = Rune(0x025AD)
-  of "marker": result = Rune(0x025AE)
-  of "fltns": result = Rune(0x025B1)
-  of "xutri", "bigtriangleup": result = Rune(0x025B3)
-  of "utrif", "blacktriangle": result = Rune(0x025B4)
-  of "utri", "triangle": result = Rune(0x025B5)
-  of "rtrif", "blacktriangleright": result = Rune(0x025B8)
-  of "rtri", "triangleright": result = Rune(0x025B9)
-  of "xdtri", "bigtriangledown": result = Rune(0x025BD)
-  of "dtrif", "blacktriangledown": result = Rune(0x025BE)
-  of "dtri", "triangledown": result = Rune(0x025BF)
-  of "ltrif", "blacktriangleleft": result = Rune(0x025C2)
-  of "ltri", "triangleleft": result = Rune(0x025C3)
-  of "loz", "lozenge": result = Rune(0x025CA)
-  of "cir": result = Rune(0x025CB)
-  of "tridot": result = Rune(0x025EC)
-  of "xcirc", "bigcirc": result = Rune(0x025EF)
-  of "ultri": result = Rune(0x025F8)
-  of "urtri": result = Rune(0x025F9)
-  of "lltri": result = Rune(0x025FA)
-  of "EmptySmallSquare": result = Rune(0x025FB)
-  of "FilledSmallSquare": result = Rune(0x025FC)
-  of "starf", "bigstar": result = Rune(0x02605)
-  of "star": result = Rune(0x02606)
-  of "phone": result = Rune(0x0260E)
-  of "female": result = Rune(0x02640)
-  of "male": result = Rune(0x02642)
-  of "spades", "spadesuit": result = Rune(0x02660)
-  of "clubs", "clubsuit": result = Rune(0x02663)
-  of "hearts", "heartsuit": result = Rune(0x02665)
-  of "diams", "diamondsuit": result = Rune(0x02666)
-  of "sung": result = Rune(0x0266A)
-  of "flat": result = Rune(0x0266D)
-  of "natur", "natural": result = Rune(0x0266E)
-  of "sharp": result = Rune(0x0266F)
-  of "check", "checkmark": result = Rune(0x02713)
-  of "cross": result = Rune(0x02717)
-  of "malt", "maltese": result = Rune(0x02720)
-  of "sext": result = Rune(0x02736)
-  of "VerticalSeparator": result = Rune(0x02758)
-  of "lbbrk": result = Rune(0x02772)
-  of "rbbrk": result = Rune(0x02773)
-  of "lobrk", "LeftDoubleBracket": result = Rune(0x027E6)
-  of "robrk", "RightDoubleBracket": result = Rune(0x027E7)
-  of "lang", "LeftAngleBracket", "langle": result = Rune(0x027E8)
-  of "rang", "RightAngleBracket", "rangle": result = Rune(0x027E9)
-  of "Lang": result = Rune(0x027EA)
-  of "Rang": result = Rune(0x027EB)
-  of "loang": result = Rune(0x027EC)
-  of "roang": result = Rune(0x027ED)
-  of "xlarr", "longleftarrow", "LongLeftArrow": result = Rune(0x027F5)
-  of "xrarr", "longrightarrow", "LongRightArrow": result = Rune(0x027F6)
+    "FilledVerySmallSquare": Rune(0x025AA)
+  of "EmptyVerySmallSquare": Rune(0x025AB)
+  of "rect": Rune(0x025AD)
+  of "marker": Rune(0x025AE)
+  of "fltns": Rune(0x025B1)
+  of "xutri", "bigtriangleup": Rune(0x025B3)
+  of "utrif", "blacktriangle": Rune(0x025B4)
+  of "utri", "triangle": Rune(0x025B5)
+  of "rtrif", "blacktriangleright": Rune(0x025B8)
+  of "rtri", "triangleright": Rune(0x025B9)
+  of "xdtri", "bigtriangledown": Rune(0x025BD)
+  of "dtrif", "blacktriangledown": Rune(0x025BE)
+  of "dtri", "triangledown": Rune(0x025BF)
+  of "ltrif", "blacktriangleleft": Rune(0x025C2)
+  of "ltri", "triangleleft": Rune(0x025C3)
+  of "loz", "lozenge": Rune(0x025CA)
+  of "cir": Rune(0x025CB)
+  of "tridot": Rune(0x025EC)
+  of "xcirc", "bigcirc": Rune(0x025EF)
+  of "ultri": Rune(0x025F8)
+  of "urtri": Rune(0x025F9)
+  of "lltri": Rune(0x025FA)
+  of "EmptySmallSquare": Rune(0x025FB)
+  of "FilledSmallSquare": Rune(0x025FC)
+  of "starf", "bigstar": Rune(0x02605)
+  of "star": Rune(0x02606)
+  of "phone": Rune(0x0260E)
+  of "female": Rune(0x02640)
+  of "male": Rune(0x02642)
+  of "spades", "spadesuit": Rune(0x02660)
+  of "clubs", "clubsuit": Rune(0x02663)
+  of "hearts", "heartsuit": Rune(0x02665)
+  of "diams", "diamondsuit": Rune(0x02666)
+  of "sung": Rune(0x0266A)
+  of "flat": Rune(0x0266D)
+  of "natur", "natural": Rune(0x0266E)
+  of "sharp": Rune(0x0266F)
+  of "check", "checkmark": Rune(0x02713)
+  of "cross": Rune(0x02717)
+  of "malt", "maltese": Rune(0x02720)
+  of "sext": Rune(0x02736)
+  of "VerticalSeparator": Rune(0x02758)
+  of "lbbrk": Rune(0x02772)
+  of "rbbrk": Rune(0x02773)
+  of "lobrk", "LeftDoubleBracket": Rune(0x027E6)
+  of "robrk", "RightDoubleBracket": Rune(0x027E7)
+  of "lang", "LeftAngleBracket", "langle": Rune(0x027E8)
+  of "rang", "RightAngleBracket", "rangle": Rune(0x027E9)
+  of "Lang": Rune(0x027EA)
+  of "Rang": Rune(0x027EB)
+  of "loang": Rune(0x027EC)
+  of "roang": Rune(0x027ED)
+  of "xlarr", "longleftarrow", "LongLeftArrow": Rune(0x027F5)
+  of "xrarr", "longrightarrow", "LongRightArrow": Rune(0x027F6)
   of "xharr", "longleftrightarrow",
-    "LongLeftRightArrow": result = Rune(0x027F7)
-  of "xlArr", "Longleftarrow", "DoubleLongLeftArrow": result = Rune(0x027F8)
-  of "xrArr", "Longrightarrow", "DoubleLongRightArrow": result = Rune(0x027F9)
+    "LongLeftRightArrow": Rune(0x027F7)
+  of "xlArr", "Longleftarrow", "DoubleLongLeftArrow": Rune(0x027F8)
+  of "xrArr", "Longrightarrow", "DoubleLongRightArrow": Rune(0x027F9)
   of "xhArr", "Longleftrightarrow",
-    "DoubleLongLeftRightArrow": result = Rune(0x027FA)
-  of "xmap", "longmapsto": result = Rune(0x027FC)
-  of "dzigrarr": result = Rune(0x027FF)
-  of "nvlArr": result = Rune(0x02902)
-  of "nvrArr": result = Rune(0x02903)
-  of "nvHarr": result = Rune(0x02904)
-  of "Map": result = Rune(0x02905)
-  of "lbarr": result = Rune(0x0290C)
-  of "rbarr", "bkarow": result = Rune(0x0290D)
-  of "lBarr": result = Rune(0x0290E)
-  of "rBarr", "dbkarow": result = Rune(0x0290F)
-  of "RBarr", "drbkarow": result = Rune(0x02910)
-  of "DDotrahd": result = Rune(0x02911)
-  of "UpArrowBar": result = Rune(0x02912)
-  of "DownArrowBar": result = Rune(0x02913)
-  of "Rarrtl": result = Rune(0x02916)
-  of "latail": result = Rune(0x02919)
-  of "ratail": result = Rune(0x0291A)
-  of "lAtail": result = Rune(0x0291B)
-  of "rAtail": result = Rune(0x0291C)
-  of "larrfs": result = Rune(0x0291D)
-  of "rarrfs": result = Rune(0x0291E)
-  of "larrbfs": result = Rune(0x0291F)
-  of "rarrbfs": result = Rune(0x02920)
-  of "nwarhk": result = Rune(0x02923)
-  of "nearhk": result = Rune(0x02924)
-  of "searhk", "hksearow": result = Rune(0x02925)
-  of "swarhk", "hkswarow": result = Rune(0x02926)
-  of "nwnear": result = Rune(0x02927)
-  of "nesear", "toea": result = Rune(0x02928)
-  of "seswar", "tosa": result = Rune(0x02929)
-  of "swnwar": result = Rune(0x0292A)
-  of "rarrc": result = Rune(0x02933)
-  of "cudarrr": result = Rune(0x02935)
-  of "ldca": result = Rune(0x02936)
-  of "rdca": result = Rune(0x02937)
-  of "cudarrl": result = Rune(0x02938)
-  of "larrpl": result = Rune(0x02939)
-  of "curarrm": result = Rune(0x0293C)
-  of "cularrp": result = Rune(0x0293D)
-  of "rarrpl": result = Rune(0x02945)
-  of "harrcir": result = Rune(0x02948)
-  of "Uarrocir": result = Rune(0x02949)
-  of "lurdshar": result = Rune(0x0294A)
-  of "ldrushar": result = Rune(0x0294B)
-  of "LeftRightVector": result = Rune(0x0294E)
-  of "RightUpDownVector": result = Rune(0x0294F)
-  of "DownLeftRightVector": result = Rune(0x02950)
-  of "LeftUpDownVector": result = Rune(0x02951)
-  of "LeftVectorBar": result = Rune(0x02952)
-  of "RightVectorBar": result = Rune(0x02953)
-  of "RightUpVectorBar": result = Rune(0x02954)
-  of "RightDownVectorBar": result = Rune(0x02955)
-  of "DownLeftVectorBar": result = Rune(0x02956)
-  of "DownRightVectorBar": result = Rune(0x02957)
-  of "LeftUpVectorBar": result = Rune(0x02958)
-  of "LeftDownVectorBar": result = Rune(0x02959)
-  of "LeftTeeVector": result = Rune(0x0295A)
-  of "RightTeeVector": result = Rune(0x0295B)
-  of "RightUpTeeVector": result = Rune(0x0295C)
-  of "RightDownTeeVector": result = Rune(0x0295D)
-  of "DownLeftTeeVector": result = Rune(0x0295E)
-  of "DownRightTeeVector": result = Rune(0x0295F)
-  of "LeftUpTeeVector": result = Rune(0x02960)
-  of "LeftDownTeeVector": result = Rune(0x02961)
-  of "lHar": result = Rune(0x02962)
-  of "uHar": result = Rune(0x02963)
-  of "rHar": result = Rune(0x02964)
-  of "dHar": result = Rune(0x02965)
-  of "luruhar": result = Rune(0x02966)
-  of "ldrdhar": result = Rune(0x02967)
-  of "ruluhar": result = Rune(0x02968)
-  of "rdldhar": result = Rune(0x02969)
-  of "lharul": result = Rune(0x0296A)
-  of "llhard": result = Rune(0x0296B)
-  of "rharul": result = Rune(0x0296C)
-  of "lrhard": result = Rune(0x0296D)
-  of "udhar", "UpEquilibrium": result = Rune(0x0296E)
-  of "duhar", "ReverseUpEquilibrium": result = Rune(0x0296F)
-  of "RoundImplies": result = Rune(0x02970)
-  of "erarr": result = Rune(0x02971)
-  of "simrarr": result = Rune(0x02972)
-  of "larrsim": result = Rune(0x02973)
-  of "rarrsim": result = Rune(0x02974)
-  of "rarrap": result = Rune(0x02975)
-  of "ltlarr": result = Rune(0x02976)
-  of "gtrarr": result = Rune(0x02978)
-  of "subrarr": result = Rune(0x02979)
-  of "suplarr": result = Rune(0x0297B)
-  of "lfisht": result = Rune(0x0297C)
-  of "rfisht": result = Rune(0x0297D)
-  of "ufisht": result = Rune(0x0297E)
-  of "dfisht": result = Rune(0x0297F)
-  of "lopar": result = Rune(0x02985)
-  of "ropar": result = Rune(0x02986)
-  of "lbrke": result = Rune(0x0298B)
-  of "rbrke": result = Rune(0x0298C)
-  of "lbrkslu": result = Rune(0x0298D)
-  of "rbrksld": result = Rune(0x0298E)
-  of "lbrksld": result = Rune(0x0298F)
-  of "rbrkslu": result = Rune(0x02990)
-  of "langd": result = Rune(0x02991)
-  of "rangd": result = Rune(0x02992)
-  of "lparlt": result = Rune(0x02993)
-  of "rpargt": result = Rune(0x02994)
-  of "gtlPar": result = Rune(0x02995)
-  of "ltrPar": result = Rune(0x02996)
-  of "vzigzag": result = Rune(0x0299A)
-  of "vangrt": result = Rune(0x0299C)
-  of "angrtvbd": result = Rune(0x0299D)
-  of "ange": result = Rune(0x029A4)
-  of "range": result = Rune(0x029A5)
-  of "dwangle": result = Rune(0x029A6)
-  of "uwangle": result = Rune(0x029A7)
-  of "angmsdaa": result = Rune(0x029A8)
-  of "angmsdab": result = Rune(0x029A9)
-  of "angmsdac": result = Rune(0x029AA)
-  of "angmsdad": result = Rune(0x029AB)
-  of "angmsdae": result = Rune(0x029AC)
-  of "angmsdaf": result = Rune(0x029AD)
-  of "angmsdag": result = Rune(0x029AE)
-  of "angmsdah": result = Rune(0x029AF)
-  of "bemptyv": result = Rune(0x029B0)
-  of "demptyv": result = Rune(0x029B1)
-  of "cemptyv": result = Rune(0x029B2)
-  of "raemptyv": result = Rune(0x029B3)
-  of "laemptyv": result = Rune(0x029B4)
-  of "ohbar": result = Rune(0x029B5)
-  of "omid": result = Rune(0x029B6)
-  of "opar": result = Rune(0x029B7)
-  of "operp": result = Rune(0x029B9)
-  of "olcross": result = Rune(0x029BB)
-  of "odsold": result = Rune(0x029BC)
-  of "olcir": result = Rune(0x029BE)
-  of "ofcir": result = Rune(0x029BF)
-  of "olt": result = Rune(0x029C0)
-  of "ogt": result = Rune(0x029C1)
-  of "cirscir": result = Rune(0x029C2)
-  of "cirE": result = Rune(0x029C3)
-  of "solb": result = Rune(0x029C4)
-  of "bsolb": result = Rune(0x029C5)
-  of "boxbox": result = Rune(0x029C9)
-  of "trisb": result = Rune(0x029CD)
-  of "rtriltri": result = Rune(0x029CE)
-  of "LeftTriangleBar": result = Rune(0x029CF)
-  of "RightTriangleBar": result = Rune(0x029D0)
-  of "race": result = Rune(0x029DA)
-  of "iinfin": result = Rune(0x029DC)
-  of "infintie": result = Rune(0x029DD)
-  of "nvinfin": result = Rune(0x029DE)
-  of "eparsl": result = Rune(0x029E3)
-  of "smeparsl": result = Rune(0x029E4)
-  of "eqvparsl": result = Rune(0x029E5)
-  of "lozf", "blacklozenge": result = Rune(0x029EB)
-  of "RuleDelayed": result = Rune(0x029F4)
-  of "dsol": result = Rune(0x029F6)
-  of "xodot", "bigodot": result = Rune(0x02A00)
-  of "xoplus", "bigoplus": result = Rune(0x02A01)
-  of "xotime", "bigotimes": result = Rune(0x02A02)
-  of "xuplus", "biguplus": result = Rune(0x02A04)
-  of "xsqcup", "bigsqcup": result = Rune(0x02A06)
-  of "qint", "iiiint": result = Rune(0x02A0C)
-  of "fpartint": result = Rune(0x02A0D)
-  of "cirfnint": result = Rune(0x02A10)
-  of "awint": result = Rune(0x02A11)
-  of "rppolint": result = Rune(0x02A12)
-  of "scpolint": result = Rune(0x02A13)
-  of "npolint": result = Rune(0x02A14)
-  of "pointint": result = Rune(0x02A15)
-  of "quatint": result = Rune(0x02A16)
-  of "intlarhk": result = Rune(0x02A17)
-  of "pluscir": result = Rune(0x02A22)
-  of "plusacir": result = Rune(0x02A23)
-  of "simplus": result = Rune(0x02A24)
-  of "plusdu": result = Rune(0x02A25)
-  of "plussim": result = Rune(0x02A26)
-  of "plustwo": result = Rune(0x02A27)
-  of "mcomma": result = Rune(0x02A29)
-  of "minusdu": result = Rune(0x02A2A)
-  of "loplus": result = Rune(0x02A2D)
-  of "roplus": result = Rune(0x02A2E)
-  of "Cross": result = Rune(0x02A2F)
-  of "timesd": result = Rune(0x02A30)
-  of "timesbar": result = Rune(0x02A31)
-  of "smashp": result = Rune(0x02A33)
-  of "lotimes": result = Rune(0x02A34)
-  of "rotimes": result = Rune(0x02A35)
-  of "otimesas": result = Rune(0x02A36)
-  of "Otimes": result = Rune(0x02A37)
-  of "odiv": result = Rune(0x02A38)
-  of "triplus": result = Rune(0x02A39)
-  of "triminus": result = Rune(0x02A3A)
-  of "tritime": result = Rune(0x02A3B)
-  of "iprod", "intprod": result = Rune(0x02A3C)
-  of "amalg": result = Rune(0x02A3F)
-  of "capdot": result = Rune(0x02A40)
-  of "ncup": result = Rune(0x02A42)
-  of "ncap": result = Rune(0x02A43)
-  of "capand": result = Rune(0x02A44)
-  of "cupor": result = Rune(0x02A45)
-  of "cupcap": result = Rune(0x02A46)
-  of "capcup": result = Rune(0x02A47)
-  of "cupbrcap": result = Rune(0x02A48)
-  of "capbrcup": result = Rune(0x02A49)
-  of "cupcup": result = Rune(0x02A4A)
-  of "capcap": result = Rune(0x02A4B)
-  of "ccups": result = Rune(0x02A4C)
-  of "ccaps": result = Rune(0x02A4D)
-  of "ccupssm": result = Rune(0x02A50)
-  of "And": result = Rune(0x02A53)
-  of "Or": result = Rune(0x02A54)
-  of "andand": result = Rune(0x02A55)
-  of "oror": result = Rune(0x02A56)
-  of "orslope": result = Rune(0x02A57)
-  of "andslope": result = Rune(0x02A58)
-  of "andv": result = Rune(0x02A5A)
-  of "orv": result = Rune(0x02A5B)
-  of "andd": result = Rune(0x02A5C)
-  of "ord": result = Rune(0x02A5D)
-  of "wedbar": result = Rune(0x02A5F)
-  of "sdote": result = Rune(0x02A66)
-  of "simdot": result = Rune(0x02A6A)
-  of "congdot": result = Rune(0x02A6D)
-  of "easter": result = Rune(0x02A6E)
-  of "apacir": result = Rune(0x02A6F)
-  of "apE": result = Rune(0x02A70)
-  of "eplus": result = Rune(0x02A71)
-  of "pluse": result = Rune(0x02A72)
-  of "Esim": result = Rune(0x02A73)
-  of "Colone": result = Rune(0x02A74)
-  of "Equal": result = Rune(0x02A75)
-  of "eDDot", "ddotseq": result = Rune(0x02A77)
-  of "equivDD": result = Rune(0x02A78)
-  of "ltcir": result = Rune(0x02A79)
-  of "gtcir": result = Rune(0x02A7A)
-  of "ltquest": result = Rune(0x02A7B)
-  of "gtquest": result = Rune(0x02A7C)
-  of "les", "LessSlantEqual", "leqslant": result = Rune(0x02A7D)
-  of "ges", "GreaterSlantEqual", "geqslant": result = Rune(0x02A7E)
-  of "lesdot": result = Rune(0x02A7F)
-  of "gesdot": result = Rune(0x02A80)
-  of "lesdoto": result = Rune(0x02A81)
-  of "gesdoto": result = Rune(0x02A82)
-  of "lesdotor": result = Rune(0x02A83)
-  of "gesdotol": result = Rune(0x02A84)
-  of "lap", "lessapprox": result = Rune(0x02A85)
-  of "gap", "gtrapprox": result = Rune(0x02A86)
-  of "lne", "lneq": result = Rune(0x02A87)
-  of "gne", "gneq": result = Rune(0x02A88)
-  of "lnap", "lnapprox": result = Rune(0x02A89)
-  of "gnap", "gnapprox": result = Rune(0x02A8A)
-  of "lEg", "lesseqqgtr": result = Rune(0x02A8B)
-  of "gEl", "gtreqqless": result = Rune(0x02A8C)
-  of "lsime": result = Rune(0x02A8D)
-  of "gsime": result = Rune(0x02A8E)
-  of "lsimg": result = Rune(0x02A8F)
-  of "gsiml": result = Rune(0x02A90)
-  of "lgE": result = Rune(0x02A91)
-  of "glE": result = Rune(0x02A92)
-  of "lesges": result = Rune(0x02A93)
-  of "gesles": result = Rune(0x02A94)
-  of "els", "eqslantless": result = Rune(0x02A95)
-  of "egs", "eqslantgtr": result = Rune(0x02A96)
-  of "elsdot": result = Rune(0x02A97)
-  of "egsdot": result = Rune(0x02A98)
-  of "el": result = Rune(0x02A99)
-  of "eg": result = Rune(0x02A9A)
-  of "siml": result = Rune(0x02A9D)
-  of "simg": result = Rune(0x02A9E)
-  of "simlE": result = Rune(0x02A9F)
-  of "simgE": result = Rune(0x02AA0)
-  of "LessLess": result = Rune(0x02AA1)
-  of "GreaterGreater": result = Rune(0x02AA2)
-  of "glj": result = Rune(0x02AA4)
-  of "gla": result = Rune(0x02AA5)
-  of "ltcc": result = Rune(0x02AA6)
-  of "gtcc": result = Rune(0x02AA7)
-  of "lescc": result = Rune(0x02AA8)
-  of "gescc": result = Rune(0x02AA9)
-  of "smt": result = Rune(0x02AAA)
-  of "lat": result = Rune(0x02AAB)
-  of "smte": result = Rune(0x02AAC)
-  of "late": result = Rune(0x02AAD)
-  of "bumpE": result = Rune(0x02AAE)
-  of "pre", "preceq", "PrecedesEqual": result = Rune(0x02AAF)
-  of "sce", "succeq", "SucceedsEqual": result = Rune(0x02AB0)
-  of "prE": result = Rune(0x02AB3)
-  of "scE": result = Rune(0x02AB4)
-  of "prnE", "precneqq": result = Rune(0x02AB5)
-  of "scnE", "succneqq": result = Rune(0x02AB6)
-  of "prap", "precapprox": result = Rune(0x02AB7)
-  of "scap", "succapprox": result = Rune(0x02AB8)
-  of "prnap", "precnapprox": result = Rune(0x02AB9)
-  of "scnap", "succnapprox": result = Rune(0x02ABA)
-  of "Pr": result = Rune(0x02ABB)
-  of "Sc": result = Rune(0x02ABC)
-  of "subdot": result = Rune(0x02ABD)
-  of "supdot": result = Rune(0x02ABE)
-  of "subplus": result = Rune(0x02ABF)
-  of "supplus": result = Rune(0x02AC0)
-  of "submult": result = Rune(0x02AC1)
-  of "supmult": result = Rune(0x02AC2)
-  of "subedot": result = Rune(0x02AC3)
-  of "supedot": result = Rune(0x02AC4)
-  of "subE", "subseteqq": result = Rune(0x02AC5)
-  of "supE", "supseteqq": result = Rune(0x02AC6)
-  of "subsim": result = Rune(0x02AC7)
-  of "supsim": result = Rune(0x02AC8)
-  of "subnE", "subsetneqq": result = Rune(0x02ACB)
-  of "supnE", "supsetneqq": result = Rune(0x02ACC)
-  of "csub": result = Rune(0x02ACF)
-  of "csup": result = Rune(0x02AD0)
-  of "csube": result = Rune(0x02AD1)
-  of "csupe": result = Rune(0x02AD2)
-  of "subsup": result = Rune(0x02AD3)
-  of "supsub": result = Rune(0x02AD4)
-  of "subsub": result = Rune(0x02AD5)
-  of "supsup": result = Rune(0x02AD6)
-  of "suphsub": result = Rune(0x02AD7)
-  of "supdsub": result = Rune(0x02AD8)
-  of "forkv": result = Rune(0x02AD9)
-  of "topfork": result = Rune(0x02ADA)
-  of "mlcp": result = Rune(0x02ADB)
-  of "Dashv", "DoubleLeftTee": result = Rune(0x02AE4)
-  of "Vdashl": result = Rune(0x02AE6)
-  of "Barv": result = Rune(0x02AE7)
-  of "vBar": result = Rune(0x02AE8)
-  of "vBarv": result = Rune(0x02AE9)
-  of "Vbar": result = Rune(0x02AEB)
-  of "Not": result = Rune(0x02AEC)
-  of "bNot": result = Rune(0x02AED)
-  of "rnmid": result = Rune(0x02AEE)
-  of "cirmid": result = Rune(0x02AEF)
-  of "midcir": result = Rune(0x02AF0)
-  of "topcir": result = Rune(0x02AF1)
-  of "nhpar": result = Rune(0x02AF2)
-  of "parsim": result = Rune(0x02AF3)
-  of "parsl": result = Rune(0x02AFD)
-  of "fflig": result = Rune(0x0FB00)
-  of "filig": result = Rune(0x0FB01)
-  of "fllig": result = Rune(0x0FB02)
-  of "ffilig": result = Rune(0x0FB03)
-  of "ffllig": result = Rune(0x0FB04)
-  of "Ascr": result = Rune(0x1D49C)
-  of "Cscr": result = Rune(0x1D49E)
-  of "Dscr": result = Rune(0x1D49F)
-  of "Gscr": result = Rune(0x1D4A2)
-  of "Jscr": result = Rune(0x1D4A5)
-  of "Kscr": result = Rune(0x1D4A6)
-  of "Nscr": result = Rune(0x1D4A9)
-  of "Oscr": result = Rune(0x1D4AA)
-  of "Pscr": result = Rune(0x1D4AB)
-  of "Qscr": result = Rune(0x1D4AC)
-  of "Sscr": result = Rune(0x1D4AE)
-  of "Tscr": result = Rune(0x1D4AF)
-  of "Uscr": result = Rune(0x1D4B0)
-  of "Vscr": result = Rune(0x1D4B1)
-  of "Wscr": result = Rune(0x1D4B2)
-  of "Xscr": result = Rune(0x1D4B3)
-  of "Yscr": result = Rune(0x1D4B4)
-  of "Zscr": result = Rune(0x1D4B5)
-  of "ascr": result = Rune(0x1D4B6)
-  of "bscr": result = Rune(0x1D4B7)
-  of "cscr": result = Rune(0x1D4B8)
-  of "dscr": result = Rune(0x1D4B9)
-  of "fscr": result = Rune(0x1D4BB)
-  of "hscr": result = Rune(0x1D4BD)
-  of "iscr": result = Rune(0x1D4BE)
-  of "jscr": result = Rune(0x1D4BF)
-  of "kscr": result = Rune(0x1D4C0)
-  of "lscr": result = Rune(0x1D4C1)
-  of "mscr": result = Rune(0x1D4C2)
-  of "nscr": result = Rune(0x1D4C3)
-  of "pscr": result = Rune(0x1D4C5)
-  of "qscr": result = Rune(0x1D4C6)
-  of "rscr": result = Rune(0x1D4C7)
-  of "sscr": result = Rune(0x1D4C8)
-  of "tscr": result = Rune(0x1D4C9)
-  of "uscr": result = Rune(0x1D4CA)
-  of "vscr": result = Rune(0x1D4CB)
-  of "wscr": result = Rune(0x1D4CC)
-  of "xscr": result = Rune(0x1D4CD)
-  of "yscr": result = Rune(0x1D4CE)
-  of "zscr": result = Rune(0x1D4CF)
-  of "Afr": result = Rune(0x1D504)
-  of "Bfr": result = Rune(0x1D505)
-  of "Dfr": result = Rune(0x1D507)
-  of "Efr": result = Rune(0x1D508)
-  of "Ffr": result = Rune(0x1D509)
-  of "Gfr": result = Rune(0x1D50A)
-  of "Jfr": result = Rune(0x1D50D)
-  of "Kfr": result = Rune(0x1D50E)
-  of "Lfr": result = Rune(0x1D50F)
-  of "Mfr": result = Rune(0x1D510)
-  of "Nfr": result = Rune(0x1D511)
-  of "Ofr": result = Rune(0x1D512)
-  of "Pfr": result = Rune(0x1D513)
-  of "Qfr": result = Rune(0x1D514)
-  of "Sfr": result = Rune(0x1D516)
-  of "Tfr": result = Rune(0x1D517)
-  of "Ufr": result = Rune(0x1D518)
-  of "Vfr": result = Rune(0x1D519)
-  of "Wfr": result = Rune(0x1D51A)
-  of "Xfr": result = Rune(0x1D51B)
-  of "Yfr": result = Rune(0x1D51C)
-  of "afr": result = Rune(0x1D51E)
-  of "bfr": result = Rune(0x1D51F)
-  of "cfr": result = Rune(0x1D520)
-  of "dfr": result = Rune(0x1D521)
-  of "efr": result = Rune(0x1D522)
-  of "ffr": result = Rune(0x1D523)
-  of "gfr": result = Rune(0x1D524)
-  of "hfr": result = Rune(0x1D525)
-  of "ifr": result = Rune(0x1D526)
-  of "jfr": result = Rune(0x1D527)
-  of "kfr": result = Rune(0x1D528)
-  of "lfr": result = Rune(0x1D529)
-  of "mfr": result = Rune(0x1D52A)
-  of "nfr": result = Rune(0x1D52B)
-  of "ofr": result = Rune(0x1D52C)
-  of "pfr": result = Rune(0x1D52D)
-  of "qfr": result = Rune(0x1D52E)
-  of "rfr": result = Rune(0x1D52F)
-  of "sfr": result = Rune(0x1D530)
-  of "tfr": result = Rune(0x1D531)
-  of "ufr": result = Rune(0x1D532)
-  of "vfr": result = Rune(0x1D533)
-  of "wfr": result = Rune(0x1D534)
-  of "xfr": result = Rune(0x1D535)
-  of "yfr": result = Rune(0x1D536)
-  of "zfr": result = Rune(0x1D537)
-  of "Aopf": result = Rune(0x1D538)
-  of "Bopf": result = Rune(0x1D539)
-  of "Dopf": result = Rune(0x1D53B)
-  of "Eopf": result = Rune(0x1D53C)
-  of "Fopf": result = Rune(0x1D53D)
-  of "Gopf": result = Rune(0x1D53E)
-  of "Iopf": result = Rune(0x1D540)
-  of "Jopf": result = Rune(0x1D541)
-  of "Kopf": result = Rune(0x1D542)
-  of "Lopf": result = Rune(0x1D543)
-  of "Mopf": result = Rune(0x1D544)
-  of "Oopf": result = Rune(0x1D546)
-  of "Sopf": result = Rune(0x1D54A)
-  of "Topf": result = Rune(0x1D54B)
-  of "Uopf": result = Rune(0x1D54C)
-  of "Vopf": result = Rune(0x1D54D)
-  of "Wopf": result = Rune(0x1D54E)
-  of "Xopf": result = Rune(0x1D54F)
-  of "Yopf": result = Rune(0x1D550)
-  of "aopf": result = Rune(0x1D552)
-  of "bopf": result = Rune(0x1D553)
-  of "copf": result = Rune(0x1D554)
-  of "dopf": result = Rune(0x1D555)
-  of "eopf": result = Rune(0x1D556)
-  of "fopf": result = Rune(0x1D557)
-  of "gopf": result = Rune(0x1D558)
-  of "hopf": result = Rune(0x1D559)
-  of "iopf": result = Rune(0x1D55A)
-  of "jopf": result = Rune(0x1D55B)
-  of "kopf": result = Rune(0x1D55C)
-  of "lopf": result = Rune(0x1D55D)
-  of "mopf": result = Rune(0x1D55E)
-  of "nopf": result = Rune(0x1D55F)
-  of "oopf": result = Rune(0x1D560)
-  of "popf": result = Rune(0x1D561)
-  of "qopf": result = Rune(0x1D562)
-  of "ropf": result = Rune(0x1D563)
-  of "sopf": result = Rune(0x1D564)
-  of "topf": result = Rune(0x1D565)
-  of "uopf": result = Rune(0x1D566)
-  of "vopf": result = Rune(0x1D567)
-  of "wopf": result = Rune(0x1D568)
-  of "xopf": result = Rune(0x1D569)
-  of "yopf": result = Rune(0x1D56A)
-  of "zopf": result = Rune(0x1D56B)
-  else: discard
+    "DoubleLongLeftRightArrow": Rune(0x027FA)
+  of "xmap", "longmapsto": Rune(0x027FC)
+  of "dzigrarr": Rune(0x027FF)
+  of "nvlArr": Rune(0x02902)
+  of "nvrArr": Rune(0x02903)
+  of "nvHarr": Rune(0x02904)
+  of "Map": Rune(0x02905)
+  of "lbarr": Rune(0x0290C)
+  of "rbarr", "bkarow": Rune(0x0290D)
+  of "lBarr": Rune(0x0290E)
+  of "rBarr", "dbkarow": Rune(0x0290F)
+  of "RBarr", "drbkarow": Rune(0x02910)
+  of "DDotrahd": Rune(0x02911)
+  of "UpArrowBar": Rune(0x02912)
+  of "DownArrowBar": Rune(0x02913)
+  of "Rarrtl": Rune(0x02916)
+  of "latail": Rune(0x02919)
+  of "ratail": Rune(0x0291A)
+  of "lAtail": Rune(0x0291B)
+  of "rAtail": Rune(0x0291C)
+  of "larrfs": Rune(0x0291D)
+  of "rarrfs": Rune(0x0291E)
+  of "larrbfs": Rune(0x0291F)
+  of "rarrbfs": Rune(0x02920)
+  of "nwarhk": Rune(0x02923)
+  of "nearhk": Rune(0x02924)
+  of "searhk", "hksearow": Rune(0x02925)
+  of "swarhk", "hkswarow": Rune(0x02926)
+  of "nwnear": Rune(0x02927)
+  of "nesear", "toea": Rune(0x02928)
+  of "seswar", "tosa": Rune(0x02929)
+  of "swnwar": Rune(0x0292A)
+  of "rarrc": Rune(0x02933)
+  of "cudarrr": Rune(0x02935)
+  of "ldca": Rune(0x02936)
+  of "rdca": Rune(0x02937)
+  of "cudarrl": Rune(0x02938)
+  of "larrpl": Rune(0x02939)
+  of "curarrm": Rune(0x0293C)
+  of "cularrp": Rune(0x0293D)
+  of "rarrpl": Rune(0x02945)
+  of "harrcir": Rune(0x02948)
+  of "Uarrocir": Rune(0x02949)
+  of "lurdshar": Rune(0x0294A)
+  of "ldrushar": Rune(0x0294B)
+  of "LeftRightVector": Rune(0x0294E)
+  of "RightUpDownVector": Rune(0x0294F)
+  of "DownLeftRightVector": Rune(0x02950)
+  of "LeftUpDownVector": Rune(0x02951)
+  of "LeftVectorBar": Rune(0x02952)
+  of "RightVectorBar": Rune(0x02953)
+  of "RightUpVectorBar": Rune(0x02954)
+  of "RightDownVectorBar": Rune(0x02955)
+  of "DownLeftVectorBar": Rune(0x02956)
+  of "DownRightVectorBar": Rune(0x02957)
+  of "LeftUpVectorBar": Rune(0x02958)
+  of "LeftDownVectorBar": Rune(0x02959)
+  of "LeftTeeVector": Rune(0x0295A)
+  of "RightTeeVector": Rune(0x0295B)
+  of "RightUpTeeVector": Rune(0x0295C)
+  of "RightDownTeeVector": Rune(0x0295D)
+  of "DownLeftTeeVector": Rune(0x0295E)
+  of "DownRightTeeVector": Rune(0x0295F)
+  of "LeftUpTeeVector": Rune(0x02960)
+  of "LeftDownTeeVector": Rune(0x02961)
+  of "lHar": Rune(0x02962)
+  of "uHar": Rune(0x02963)
+  of "rHar": Rune(0x02964)
+  of "dHar": Rune(0x02965)
+  of "luruhar": Rune(0x02966)
+  of "ldrdhar": Rune(0x02967)
+  of "ruluhar": Rune(0x02968)
+  of "rdldhar": Rune(0x02969)
+  of "lharul": Rune(0x0296A)
+  of "llhard": Rune(0x0296B)
+  of "rharul": Rune(0x0296C)
+  of "lrhard": Rune(0x0296D)
+  of "udhar", "UpEquilibrium": Rune(0x0296E)
+  of "duhar", "ReverseUpEquilibrium": Rune(0x0296F)
+  of "RoundImplies": Rune(0x02970)
+  of "erarr": Rune(0x02971)
+  of "simrarr": Rune(0x02972)
+  of "larrsim": Rune(0x02973)
+  of "rarrsim": Rune(0x02974)
+  of "rarrap": Rune(0x02975)
+  of "ltlarr": Rune(0x02976)
+  of "gtrarr": Rune(0x02978)
+  of "subrarr": Rune(0x02979)
+  of "suplarr": Rune(0x0297B)
+  of "lfisht": Rune(0x0297C)
+  of "rfisht": Rune(0x0297D)
+  of "ufisht": Rune(0x0297E)
+  of "dfisht": Rune(0x0297F)
+  of "lopar": Rune(0x02985)
+  of "ropar": Rune(0x02986)
+  of "lbrke": Rune(0x0298B)
+  of "rbrke": Rune(0x0298C)
+  of "lbrkslu": Rune(0x0298D)
+  of "rbrksld": Rune(0x0298E)
+  of "lbrksld": Rune(0x0298F)
+  of "rbrkslu": Rune(0x02990)
+  of "langd": Rune(0x02991)
+  of "rangd": Rune(0x02992)
+  of "lparlt": Rune(0x02993)
+  of "rpargt": Rune(0x02994)
+  of "gtlPar": Rune(0x02995)
+  of "ltrPar": Rune(0x02996)
+  of "vzigzag": Rune(0x0299A)
+  of "vangrt": Rune(0x0299C)
+  of "angrtvbd": Rune(0x0299D)
+  of "ange": Rune(0x029A4)
+  of "range": Rune(0x029A5)
+  of "dwangle": Rune(0x029A6)
+  of "uwangle": Rune(0x029A7)
+  of "angmsdaa": Rune(0x029A8)
+  of "angmsdab": Rune(0x029A9)
+  of "angmsdac": Rune(0x029AA)
+  of "angmsdad": Rune(0x029AB)
+  of "angmsdae": Rune(0x029AC)
+  of "angmsdaf": Rune(0x029AD)
+  of "angmsdag": Rune(0x029AE)
+  of "angmsdah": Rune(0x029AF)
+  of "bemptyv": Rune(0x029B0)
+  of "demptyv": Rune(0x029B1)
+  of "cemptyv": Rune(0x029B2)
+  of "raemptyv": Rune(0x029B3)
+  of "laemptyv": Rune(0x029B4)
+  of "ohbar": Rune(0x029B5)
+  of "omid": Rune(0x029B6)
+  of "opar": Rune(0x029B7)
+  of "operp": Rune(0x029B9)
+  of "olcross": Rune(0x029BB)
+  of "odsold": Rune(0x029BC)
+  of "olcir": Rune(0x029BE)
+  of "ofcir": Rune(0x029BF)
+  of "olt": Rune(0x029C0)
+  of "ogt": Rune(0x029C1)
+  of "cirscir": Rune(0x029C2)
+  of "cirE": Rune(0x029C3)
+  of "solb": Rune(0x029C4)
+  of "bsolb": Rune(0x029C5)
+  of "boxbox": Rune(0x029C9)
+  of "trisb": Rune(0x029CD)
+  of "rtriltri": Rune(0x029CE)
+  of "LeftTriangleBar": Rune(0x029CF)
+  of "RightTriangleBar": Rune(0x029D0)
+  of "race": Rune(0x029DA)
+  of "iinfin": Rune(0x029DC)
+  of "infintie": Rune(0x029DD)
+  of "nvinfin": Rune(0x029DE)
+  of "eparsl": Rune(0x029E3)
+  of "smeparsl": Rune(0x029E4)
+  of "eqvparsl": Rune(0x029E5)
+  of "lozf", "blacklozenge": Rune(0x029EB)
+  of "RuleDelayed": Rune(0x029F4)
+  of "dsol": Rune(0x029F6)
+  of "xodot", "bigodot": Rune(0x02A00)
+  of "xoplus", "bigoplus": Rune(0x02A01)
+  of "xotime", "bigotimes": Rune(0x02A02)
+  of "xuplus", "biguplus": Rune(0x02A04)
+  of "xsqcup", "bigsqcup": Rune(0x02A06)
+  of "qint", "iiiint": Rune(0x02A0C)
+  of "fpartint": Rune(0x02A0D)
+  of "cirfnint": Rune(0x02A10)
+  of "awint": Rune(0x02A11)
+  of "rppolint": Rune(0x02A12)
+  of "scpolint": Rune(0x02A13)
+  of "npolint": Rune(0x02A14)
+  of "pointint": Rune(0x02A15)
+  of "quatint": Rune(0x02A16)
+  of "intlarhk": Rune(0x02A17)
+  of "pluscir": Rune(0x02A22)
+  of "plusacir": Rune(0x02A23)
+  of "simplus": Rune(0x02A24)
+  of "plusdu": Rune(0x02A25)
+  of "plussim": Rune(0x02A26)
+  of "plustwo": Rune(0x02A27)
+  of "mcomma": Rune(0x02A29)
+  of "minusdu": Rune(0x02A2A)
+  of "loplus": Rune(0x02A2D)
+  of "roplus": Rune(0x02A2E)
+  of "Cross": Rune(0x02A2F)
+  of "timesd": Rune(0x02A30)
+  of "timesbar": Rune(0x02A31)
+  of "smashp": Rune(0x02A33)
+  of "lotimes": Rune(0x02A34)
+  of "rotimes": Rune(0x02A35)
+  of "otimesas": Rune(0x02A36)
+  of "Otimes": Rune(0x02A37)
+  of "odiv": Rune(0x02A38)
+  of "triplus": Rune(0x02A39)
+  of "triminus": Rune(0x02A3A)
+  of "tritime": Rune(0x02A3B)
+  of "iprod", "intprod": Rune(0x02A3C)
+  of "amalg": Rune(0x02A3F)
+  of "capdot": Rune(0x02A40)
+  of "ncup": Rune(0x02A42)
+  of "ncap": Rune(0x02A43)
+  of "capand": Rune(0x02A44)
+  of "cupor": Rune(0x02A45)
+  of "cupcap": Rune(0x02A46)
+  of "capcup": Rune(0x02A47)
+  of "cupbrcap": Rune(0x02A48)
+  of "capbrcup": Rune(0x02A49)
+  of "cupcup": Rune(0x02A4A)
+  of "capcap": Rune(0x02A4B)
+  of "ccups": Rune(0x02A4C)
+  of "ccaps": Rune(0x02A4D)
+  of "ccupssm": Rune(0x02A50)
+  of "And": Rune(0x02A53)
+  of "Or": Rune(0x02A54)
+  of "andand": Rune(0x02A55)
+  of "oror": Rune(0x02A56)
+  of "orslope": Rune(0x02A57)
+  of "andslope": Rune(0x02A58)
+  of "andv": Rune(0x02A5A)
+  of "orv": Rune(0x02A5B)
+  of "andd": Rune(0x02A5C)
+  of "ord": Rune(0x02A5D)
+  of "wedbar": Rune(0x02A5F)
+  of "sdote": Rune(0x02A66)
+  of "simdot": Rune(0x02A6A)
+  of "congdot": Rune(0x02A6D)
+  of "easter": Rune(0x02A6E)
+  of "apacir": Rune(0x02A6F)
+  of "apE": Rune(0x02A70)
+  of "eplus": Rune(0x02A71)
+  of "pluse": Rune(0x02A72)
+  of "Esim": Rune(0x02A73)
+  of "Colone": Rune(0x02A74)
+  of "Equal": Rune(0x02A75)
+  of "eDDot", "ddotseq": Rune(0x02A77)
+  of "equivDD": Rune(0x02A78)
+  of "ltcir": Rune(0x02A79)
+  of "gtcir": Rune(0x02A7A)
+  of "ltquest": Rune(0x02A7B)
+  of "gtquest": Rune(0x02A7C)
+  of "les", "LessSlantEqual", "leqslant": Rune(0x02A7D)
+  of "ges", "GreaterSlantEqual", "geqslant": Rune(0x02A7E)
+  of "lesdot": Rune(0x02A7F)
+  of "gesdot": Rune(0x02A80)
+  of "lesdoto": Rune(0x02A81)
+  of "gesdoto": Rune(0x02A82)
+  of "lesdotor": Rune(0x02A83)
+  of "gesdotol": Rune(0x02A84)
+  of "lap", "lessapprox": Rune(0x02A85)
+  of "gap", "gtrapprox": Rune(0x02A86)
+  of "lne", "lneq": Rune(0x02A87)
+  of "gne", "gneq": Rune(0x02A88)
+  of "lnap", "lnapprox": Rune(0x02A89)
+  of "gnap", "gnapprox": Rune(0x02A8A)
+  of "lEg", "lesseqqgtr": Rune(0x02A8B)
+  of "gEl", "gtreqqless": Rune(0x02A8C)
+  of "lsime": Rune(0x02A8D)
+  of "gsime": Rune(0x02A8E)
+  of "lsimg": Rune(0x02A8F)
+  of "gsiml": Rune(0x02A90)
+  of "lgE": Rune(0x02A91)
+  of "glE": Rune(0x02A92)
+  of "lesges": Rune(0x02A93)
+  of "gesles": Rune(0x02A94)
+  of "els", "eqslantless": Rune(0x02A95)
+  of "egs", "eqslantgtr": Rune(0x02A96)
+  of "elsdot": Rune(0x02A97)
+  of "egsdot": Rune(0x02A98)
+  of "el": Rune(0x02A99)
+  of "eg": Rune(0x02A9A)
+  of "siml": Rune(0x02A9D)
+  of "simg": Rune(0x02A9E)
+  of "simlE": Rune(0x02A9F)
+  of "simgE": Rune(0x02AA0)
+  of "LessLess": Rune(0x02AA1)
+  of "GreaterGreater": Rune(0x02AA2)
+  of "glj": Rune(0x02AA4)
+  of "gla": Rune(0x02AA5)
+  of "ltcc": Rune(0x02AA6)
+  of "gtcc": Rune(0x02AA7)
+  of "lescc": Rune(0x02AA8)
+  of "gescc": Rune(0x02AA9)
+  of "smt": Rune(0x02AAA)
+  of "lat": Rune(0x02AAB)
+  of "smte": Rune(0x02AAC)
+  of "late": Rune(0x02AAD)
+  of "bumpE": Rune(0x02AAE)
+  of "pre", "preceq", "PrecedesEqual": Rune(0x02AAF)
+  of "sce", "succeq", "SucceedsEqual": Rune(0x02AB0)
+  of "prE": Rune(0x02AB3)
+  of "scE": Rune(0x02AB4)
+  of "prnE", "precneqq": Rune(0x02AB5)
+  of "scnE", "succneqq": Rune(0x02AB6)
+  of "prap", "precapprox": Rune(0x02AB7)
+  of "scap", "succapprox": Rune(0x02AB8)
+  of "prnap", "precnapprox": Rune(0x02AB9)
+  of "scnap", "succnapprox": Rune(0x02ABA)
+  of "Pr": Rune(0x02ABB)
+  of "Sc": Rune(0x02ABC)
+  of "subdot": Rune(0x02ABD)
+  of "supdot": Rune(0x02ABE)
+  of "subplus": Rune(0x02ABF)
+  of "supplus": Rune(0x02AC0)
+  of "submult": Rune(0x02AC1)
+  of "supmult": Rune(0x02AC2)
+  of "subedot": Rune(0x02AC3)
+  of "supedot": Rune(0x02AC4)
+  of "subE", "subseteqq": Rune(0x02AC5)
+  of "supE", "supseteqq": Rune(0x02AC6)
+  of "subsim": Rune(0x02AC7)
+  of "supsim": Rune(0x02AC8)
+  of "subnE", "subsetneqq": Rune(0x02ACB)
+  of "supnE", "supsetneqq": Rune(0x02ACC)
+  of "csub": Rune(0x02ACF)
+  of "csup": Rune(0x02AD0)
+  of "csube": Rune(0x02AD1)
+  of "csupe": Rune(0x02AD2)
+  of "subsup": Rune(0x02AD3)
+  of "supsub": Rune(0x02AD4)
+  of "subsub": Rune(0x02AD5)
+  of "supsup": Rune(0x02AD6)
+  of "suphsub": Rune(0x02AD7)
+  of "supdsub": Rune(0x02AD8)
+  of "forkv": Rune(0x02AD9)
+  of "topfork": Rune(0x02ADA)
+  of "mlcp": Rune(0x02ADB)
+  of "Dashv", "DoubleLeftTee": Rune(0x02AE4)
+  of "Vdashl": Rune(0x02AE6)
+  of "Barv": Rune(0x02AE7)
+  of "vBar": Rune(0x02AE8)
+  of "vBarv": Rune(0x02AE9)
+  of "Vbar": Rune(0x02AEB)
+  of "Not": Rune(0x02AEC)
+  of "bNot": Rune(0x02AED)
+  of "rnmid": Rune(0x02AEE)
+  of "cirmid": Rune(0x02AEF)
+  of "midcir": Rune(0x02AF0)
+  of "topcir": Rune(0x02AF1)
+  of "nhpar": Rune(0x02AF2)
+  of "parsim": Rune(0x02AF3)
+  of "parsl": Rune(0x02AFD)
+  of "fflig": Rune(0x0FB00)
+  of "filig": Rune(0x0FB01)
+  of "fllig": Rune(0x0FB02)
+  of "ffilig": Rune(0x0FB03)
+  of "ffllig": Rune(0x0FB04)
+  of "Ascr": Rune(0x1D49C)
+  of "Cscr": Rune(0x1D49E)
+  of "Dscr": Rune(0x1D49F)
+  of "Gscr": Rune(0x1D4A2)
+  of "Jscr": Rune(0x1D4A5)
+  of "Kscr": Rune(0x1D4A6)
+  of "Nscr": Rune(0x1D4A9)
+  of "Oscr": Rune(0x1D4AA)
+  of "Pscr": Rune(0x1D4AB)
+  of "Qscr": Rune(0x1D4AC)
+  of "Sscr": Rune(0x1D4AE)
+  of "Tscr": Rune(0x1D4AF)
+  of "Uscr": Rune(0x1D4B0)
+  of "Vscr": Rune(0x1D4B1)
+  of "Wscr": Rune(0x1D4B2)
+  of "Xscr": Rune(0x1D4B3)
+  of "Yscr": Rune(0x1D4B4)
+  of "Zscr": Rune(0x1D4B5)
+  of "ascr": Rune(0x1D4B6)
+  of "bscr": Rune(0x1D4B7)
+  of "cscr": Rune(0x1D4B8)
+  of "dscr": Rune(0x1D4B9)
+  of "fscr": Rune(0x1D4BB)
+  of "hscr": Rune(0x1D4BD)
+  of "iscr": Rune(0x1D4BE)
+  of "jscr": Rune(0x1D4BF)
+  of "kscr": Rune(0x1D4C0)
+  of "lscr": Rune(0x1D4C1)
+  of "mscr": Rune(0x1D4C2)
+  of "nscr": Rune(0x1D4C3)
+  of "pscr": Rune(0x1D4C5)
+  of "qscr": Rune(0x1D4C6)
+  of "rscr": Rune(0x1D4C7)
+  of "sscr": Rune(0x1D4C8)
+  of "tscr": Rune(0x1D4C9)
+  of "uscr": Rune(0x1D4CA)
+  of "vscr": Rune(0x1D4CB)
+  of "wscr": Rune(0x1D4CC)
+  of "xscr": Rune(0x1D4CD)
+  of "yscr": Rune(0x1D4CE)
+  of "zscr": Rune(0x1D4CF)
+  of "Afr": Rune(0x1D504)
+  of "Bfr": Rune(0x1D505)
+  of "Dfr": Rune(0x1D507)
+  of "Efr": Rune(0x1D508)
+  of "Ffr": Rune(0x1D509)
+  of "Gfr": Rune(0x1D50A)
+  of "Jfr": Rune(0x1D50D)
+  of "Kfr": Rune(0x1D50E)
+  of "Lfr": Rune(0x1D50F)
+  of "Mfr": Rune(0x1D510)
+  of "Nfr": Rune(0x1D511)
+  of "Ofr": Rune(0x1D512)
+  of "Pfr": Rune(0x1D513)
+  of "Qfr": Rune(0x1D514)
+  of "Sfr": Rune(0x1D516)
+  of "Tfr": Rune(0x1D517)
+  of "Ufr": Rune(0x1D518)
+  of "Vfr": Rune(0x1D519)
+  of "Wfr": Rune(0x1D51A)
+  of "Xfr": Rune(0x1D51B)
+  of "Yfr": Rune(0x1D51C)
+  of "afr": Rune(0x1D51E)
+  of "bfr": Rune(0x1D51F)
+  of "cfr": Rune(0x1D520)
+  of "dfr": Rune(0x1D521)
+  of "efr": Rune(0x1D522)
+  of "ffr": Rune(0x1D523)
+  of "gfr": Rune(0x1D524)
+  of "hfr": Rune(0x1D525)
+  of "ifr": Rune(0x1D526)
+  of "jfr": Rune(0x1D527)
+  of "kfr": Rune(0x1D528)
+  of "lfr": Rune(0x1D529)
+  of "mfr": Rune(0x1D52A)
+  of "nfr": Rune(0x1D52B)
+  of "ofr": Rune(0x1D52C)
+  of "pfr": Rune(0x1D52D)
+  of "qfr": Rune(0x1D52E)
+  of "rfr": Rune(0x1D52F)
+  of "sfr": Rune(0x1D530)
+  of "tfr": Rune(0x1D531)
+  of "ufr": Rune(0x1D532)
+  of "vfr": Rune(0x1D533)
+  of "wfr": Rune(0x1D534)
+  of "xfr": Rune(0x1D535)
+  of "yfr": Rune(0x1D536)
+  of "zfr": Rune(0x1D537)
+  of "Aopf": Rune(0x1D538)
+  of "Bopf": Rune(0x1D539)
+  of "Dopf": Rune(0x1D53B)
+  of "Eopf": Rune(0x1D53C)
+  of "Fopf": Rune(0x1D53D)
+  of "Gopf": Rune(0x1D53E)
+  of "Iopf": Rune(0x1D540)
+  of "Jopf": Rune(0x1D541)
+  of "Kopf": Rune(0x1D542)
+  of "Lopf": Rune(0x1D543)
+  of "Mopf": Rune(0x1D544)
+  of "Oopf": Rune(0x1D546)
+  of "Sopf": Rune(0x1D54A)
+  of "Topf": Rune(0x1D54B)
+  of "Uopf": Rune(0x1D54C)
+  of "Vopf": Rune(0x1D54D)
+  of "Wopf": Rune(0x1D54E)
+  of "Xopf": Rune(0x1D54F)
+  of "Yopf": Rune(0x1D550)
+  of "aopf": Rune(0x1D552)
+  of "bopf": Rune(0x1D553)
+  of "copf": Rune(0x1D554)
+  of "dopf": Rune(0x1D555)
+  of "eopf": Rune(0x1D556)
+  of "fopf": Rune(0x1D557)
+  of "gopf": Rune(0x1D558)
+  of "hopf": Rune(0x1D559)
+  of "iopf": Rune(0x1D55A)
+  of "jopf": Rune(0x1D55B)
+  of "kopf": Rune(0x1D55C)
+  of "lopf": Rune(0x1D55D)
+  of "mopf": Rune(0x1D55E)
+  of "nopf": Rune(0x1D55F)
+  of "oopf": Rune(0x1D560)
+  of "popf": Rune(0x1D561)
+  of "qopf": Rune(0x1D562)
+  of "ropf": Rune(0x1D563)
+  of "sopf": Rune(0x1D564)
+  of "topf": Rune(0x1D565)
+  of "uopf": Rune(0x1D566)
+  of "vopf": Rune(0x1D567)
+  of "wopf": Rune(0x1D568)
+  of "xopf": Rune(0x1D569)
+  of "yopf": Rune(0x1D56A)
+  of "zopf": Rune(0x1D56B)
+  else: Rune(0)
 
 proc entityToUtf8*(entity: string): string =
   ## Converts an HTML entity name like ``&Uuml;`` or values like ``&#220;``
@@ -1869,19 +1872,20 @@ proc entityToUtf8*(entity: string): string =
   ## "" is returned if the entity name is unknown. The HTML parser
   ## already converts entities to UTF-8.
   runnableExamples:
+    const sigma = "Σ"
     doAssert entityToUtf8("") == ""
     doAssert entityToUtf8("a") == ""
     doAssert entityToUtf8("gt") == ">"
     doAssert entityToUtf8("Uuml") == "Ü"
     doAssert entityToUtf8("quest") == "?"
     doAssert entityToUtf8("#63") == "?"
-    doAssert entityToUtf8("Sigma") == "Σ"
-    doAssert entityToUtf8("#931") == "Σ"
-    doAssert entityToUtf8("#0931") == "Σ"
-    doAssert entityToUtf8("#x3A3") == "Σ"
-    doAssert entityToUtf8("#x03A3") == "Σ"
-    doAssert entityToUtf8("#x3a3") == "Σ"
-    doAssert entityToUtf8("#X3a3") == "Σ"
+    doAssert entityToUtf8("Sigma") == sigma
+    doAssert entityToUtf8("#931") == sigma
+    doAssert entityToUtf8("#0931") == sigma
+    doAssert entityToUtf8("#x3A3") == sigma
+    doAssert entityToUtf8("#x03A3") == sigma
+    doAssert entityToUtf8("#x3a3") == sigma
+    doAssert entityToUtf8("#X3a3") == sigma
   let rune = entityToRune(entity)
   if rune.ord <= 0: result = ""
   else: result = toUTF8(rune)
diff --git a/lib/pure/httpclient.nim b/lib/pure/httpclient.nim
index 0192e71e7..139d4bb50 100644
--- a/lib/pure/httpclient.nim
+++ b/lib/pure/httpclient.nim
@@ -185,7 +185,7 @@ proc body*(response: Response): string =
   ## Retrieves the specified response's body.
   ##
   ## The response's body stream is read synchronously.
-  if response.body.isNil():
+  if response.body.len == 0:
     response.body = response.bodyStream.readAll()
   return response.body
 
@@ -198,7 +198,7 @@ proc `body=`*(response: Response, value: string) {.deprecated.} =
 proc body*(response: AsyncResponse): Future[string] {.async.} =
   ## Reads the response's body and caches it. The read is performed only
   ## once.
-  if response.body.isNil:
+  if response.body.len == 0:
     response.body = await readAll(response.bodyStream)
   return response.body
 
diff --git a/lib/pure/json.nim b/lib/pure/json.nim
index 3599667a8..9279fea77 100644
--- a/lib/pure/json.nim
+++ b/lib/pure/json.nim
@@ -545,10 +545,9 @@ proc newIndent(curr, indent: int, ml: bool): int =
 proc nl(s: var string, ml: bool) =
   s.add(if ml: "\n" else: " ")
 
-proc escapeJson*(s: string; result: var string) =
-  ## Converts a string `s` to its JSON representation.
+proc escapeJsonUnquoted*(s: string; result: var string) =
+  ## Converts a string `s` to its JSON representation without quotes.
   ## Appends to ``result``.
-  result.add("\"")
   for c in s:
     case c
     of '\L': result.add("\\n")
@@ -561,10 +560,21 @@ proc escapeJson*(s: string; result: var string) =
     of '\14'..'\31': result.add("\\u00" & $ord(c))
     of '\\': result.add("\\\\")
     else: result.add(c)
+
+proc escapeJsonUnquoted*(s: string): string =
+  ## Converts a string `s` to its JSON representation without quotes.
+  result = newStringOfCap(s.len + s.len shr 3)
+  escapeJsonUnquoted(s, result)
+
+proc escapeJson*(s: string; result: var string) =
+  ## Converts a string `s` to its JSON representation with quotes.
+  ## Appends to ``result``.
+  result.add("\"")
+  escapeJsonUnquoted(s, result)
   result.add("\"")
 
 proc escapeJson*(s: string): string =
-  ## Converts a string `s` to its JSON representation.
+  ## Converts a string `s` to its JSON representation with quotes.
   result = newStringOfCap(s.len + s.len shr 3)
   escapeJson(s, result)
 
@@ -1607,6 +1617,8 @@ when isMainModule:
     var parsed2 = parseFile("tests/testdata/jsontest2.json")
     doAssert(parsed2{"repository", "description"}.str=="IRC Library for Haskell", "Couldn't fetch via multiply nested key using {}")
 
+  doAssert escapeJsonUnquoted("\10Foo🎃barÄ") == "\\nFoo🎃barÄ"
+  doAssert escapeJsonUnquoted("\0\7\20") == "\\u0000\\u0007\\u0020" # for #7887
   doAssert escapeJson("\10Foo🎃barÄ") == "\"\\nFoo🎃barÄ\""
   doAssert escapeJson("\0\7\20") == "\"\\u0000\\u0007\\u0020\"" # for #7887
 
diff --git a/lib/pure/logging.nim b/lib/pure/logging.nim
index cdff1f548..f2f5cac9e 100644
--- a/lib/pure/logging.nim
+++ b/lib/pure/logging.nim
@@ -103,14 +103,9 @@ var
 proc substituteLog*(frmt: string, level: Level, args: varargs[string, `$`]): string =
   ## Format a log message using the ``frmt`` format string, ``level`` and varargs.
   ## See the module documentation for the format string syntax.
-  const nilString = "nil"
-
   var msgLen = 0
   for arg in args:
-    if arg.isNil:
-      msgLen += nilString.len
-    else:
-      msgLen += arg.len
+    msgLen += arg.len
   result = newStringOfCap(frmt.len + msgLen + 20)
   var i = 0
   while i < frmt.len:
@@ -137,10 +132,7 @@ proc substituteLog*(frmt: string, level: Level, args: varargs[string, `$`]): str
       of "levelname": result.add(LevelNames[level])
       else: discard
   for arg in args:
-    if arg.isNil:
-      result.add(nilString)
-    else:
-      result.add(arg)
+    result.add(arg)
 
 method log*(logger: Logger, level: Level, args: varargs[string, `$`]) {.
             raises: [Exception], gcsafe,
@@ -338,7 +330,6 @@ template fatal*(args: varargs[string, `$`]) =
 
 proc addHandler*(handler: Logger) =
   ## Adds ``handler`` to the list of handlers.
-  if handlers.isNil: handlers = @[]
   handlers.add(handler)
 
 proc getHandlers*(): seq[Logger] =
diff --git a/lib/pure/marshal.nim b/lib/pure/marshal.nim
index b90d2899c..b0bcfe535 100644
--- a/lib/pure/marshal.nim
+++ b/lib/pure/marshal.nim
@@ -98,8 +98,7 @@ proc storeAny(s: Stream, a: Any, stored: var IntSet) =
   of akProc, akPointer, akCString: s.write($a.getPointer.ptrToInt)
   of akString:
     var x = getString(a)
-    if isNil(x): s.write("null")
-    elif x.validateUtf8() == -1: s.write(escapeJson(x))
+    if x.validateUtf8() == -1: s.write(escapeJson(x))
     else:
       s.write("[")
       var i = 0
@@ -281,6 +280,17 @@ proc `$$`*[T](x: T): string =
 
 proc to*[T](data: string): T =
   ## reads data and transforms it to a ``T``.
+  runnableExamples:
+    type
+      Foo = object
+        id: int
+        bar: string
+
+    let x = Foo(id: 1, bar: "baz")
+    # serialize
+    let y = ($$x)
+    # deserialize back to type 'Foo':
+    let z = y.to[:Foo]
   var tab = initTable[BiggestInt, pointer]()
   loadAny(newStringStream(data), toAny(result), tab)
 
diff --git a/lib/pure/memfiles.nim b/lib/pure/memfiles.nim
index 0249b7413..9fccd08d4 100644
--- a/lib/pure/memfiles.nim
+++ b/lib/pure/memfiles.nim
@@ -328,7 +328,6 @@ proc `$`*(ms: MemSlice): string {.inline.} =
   ## Return a Nim string built from a MemSlice.
   var buf = newString(ms.size)
   copyMem(addr(buf[0]), ms.data, ms.size)
-  buf[ms.size] = '\0'
   result = buf
 
 iterator memSlices*(mfile: MemFile, delim='\l', eat='\r'): MemSlice {.inline.} =
diff --git a/lib/pure/net.nim b/lib/pure/net.nim
index 0e56100d9..a60137dab 100644
--- a/lib/pure/net.nim
+++ b/lib/pure/net.nim
@@ -58,15 +58,11 @@
 ## You can then begin accepting connections using the ``accept`` procedure.
 ##
 ## .. code-block:: Nim
-##   var client = new Socket
+##   var client: Socket
 ##   var address = ""
 ##   while true:
 ##     socket.acceptAddr(client, address)
 ##     echo("Client connected from: ", address)
-##
-## **Note:** The ``client`` variable is initialised with ``new Socket`` **not**
-## ``newSocket()``. The difference is that the latter creates a new file
-## descriptor.
 
 {.deadCodeElim: on.}  # dce option deprecated
 import nativesockets, os, strutils, parseutils, times, sets, options
@@ -789,16 +785,12 @@ proc acceptAddr*(server: Socket, client: var Socket, address: var string,
   ## The resulting client will inherit any properties of the server socket. For
   ## example: whether the socket is buffered or not.
   ##
-  ## **Note**: ``client`` must be initialised (with ``new``), this function
-  ## makes no effort to initialise the ``client`` variable.
-  ##
   ## The ``accept`` call may result in an error if the connecting socket
   ## disconnects during the duration of the ``accept``. If the ``SafeDisconn``
   ## flag is specified then this error will not be raised and instead
   ## accept will be called again.
-  assert(client != nil)
-  assert client.fd.int <= 0, "Client socket needs to be initialised with " &
-                             "`new`, not `newSocket`."
+  if client.isNil:
+    new(client)
   let ret = accept(server.fd)
   let sock = ret[0]
 
@@ -879,9 +871,6 @@ proc accept*(server: Socket, client: var Socket,
   ## Equivalent to ``acceptAddr`` but doesn't return the address, only the
   ## socket.
   ##
-  ## **Note**: ``client`` must be initialised (with ``new``), this function
-  ## makes no effort to initialise the ``client`` variable.
-  ##
   ## The ``accept`` call may result in an error if the connecting socket
   ## disconnects during the duration of the ``accept``. If the ``SafeDisconn``
   ## flag is specified then this error will not be raised and instead
@@ -1339,6 +1328,7 @@ proc recvFrom*(socket: Socket, data: var string, length: int,
   ## used. Therefore if ``socket`` contains something in its buffer this
   ## function will make no effort to return it.
 
+  assert(socket.protocol != IPPROTO_TCP, "Cannot `recvFrom` on a TCP socket")
   # TODO: Buffered sockets
   data.setLen(length)
   var sockAddress: Sockaddr_in
@@ -1408,22 +1398,25 @@ proc trySend*(socket: Socket, data: string): bool {.tags: [WriteIOEffect].} =
   result = send(socket, cstring(data), data.len) == data.len
 
 proc sendTo*(socket: Socket, address: string, port: Port, data: pointer,
-             size: int, af: Domain = AF_INET, flags = 0'i32): int {.
+             size: int, af: Domain = AF_INET, flags = 0'i32) {.
              tags: [WriteIOEffect].} =
   ## This proc sends ``data`` to the specified ``address``,
   ## which may be an IP address or a hostname, if a hostname is specified
   ## this function will try each IP of that hostname.
   ##
+  ## If an error occurs an OSError exception will be raised.
   ##
   ## **Note:** You may wish to use the high-level version of this function
   ## which is defined below.
   ##
   ## **Note:** This proc is not available for SSL sockets.
+  assert(socket.protocol != IPPROTO_TCP, "Cannot `sendTo` on a TCP socket")
   assert(not socket.isClosed, "Cannot `sendTo` on a closed socket")
   var aiList = getAddrInfo(address, port, af, socket.sockType, socket.protocol)
   # try all possibilities:
   var success = false
   var it = aiList
+  var result = 0
   while it != nil:
     result = sendto(socket.fd, data, size.cint, flags.cint, it.ai_addr,
                     it.ai_addrlen.SockLen)
@@ -1432,16 +1425,22 @@ proc sendTo*(socket: Socket, address: string, port: Port, data: pointer,
       break
     it = it.ai_next
 
+  let osError = osLastError()
   freeAddrInfo(aiList)
 
+  if not success:
+    raiseOSError(osError)
+
 proc sendTo*(socket: Socket, address: string, port: Port,
-             data: string): int {.tags: [WriteIOEffect].} =
+             data: string) {.tags: [WriteIOEffect].} =
   ## This proc sends ``data`` to the specified ``address``,
   ## which may be an IP address or a hostname, if a hostname is specified
   ## this function will try each IP of that hostname.
   ##
+  ## If an error occurs an OSError exception will be raised.
+  ##
   ## This is the high-level version of the above ``sendTo`` function.
-  result = socket.sendTo(address, port, cstring(data), data.len, socket.domain )
+  socket.sendTo(address, port, cstring(data), data.len, socket.domain)
 
 
 proc isSsl*(socket: Socket): bool =
diff --git a/lib/pure/os.nim b/lib/pure/os.nim
index 8fbc20bb5..2b3cf5142 100644
--- a/lib/pure/os.nim
+++ b/lib/pure/os.nim
@@ -233,7 +233,7 @@ proc fileNewer*(a, b: string): bool {.rtl, extern: "nos$1".} =
   ## modification time is later than `b`'s.
   when defined(posix):
     # If we don't have access to nanosecond resolution, use '>='
-    when not StatHasNanoseconds:  
+    when not StatHasNanoseconds:
       result = getLastModificationTime(a) >= getLastModificationTime(b)
     else:
       result = getLastModificationTime(a) > getLastModificationTime(b)
@@ -1343,16 +1343,21 @@ elif defined(windows):
   # is always the same -- independent of the used C compiler.
   var
     ownArgv {.threadvar.}: seq[string]
+    ownParsedArgv {.threadvar.}: bool
 
   proc paramCount*(): int {.rtl, extern: "nos$1", tags: [ReadIOEffect].} =
     # Docstring in nimdoc block.
-    if isNil(ownArgv): ownArgv = parseCmdLine($getCommandLine())
+    if not ownParsedArgv:
+      ownArgv = parseCmdLine($getCommandLine())
+      ownParsedArgv = true
     result = ownArgv.len-1
 
   proc paramStr*(i: int): TaintedString {.rtl, extern: "nos$1",
     tags: [ReadIOEffect].} =
     # Docstring in nimdoc block.
-    if isNil(ownArgv): ownArgv = parseCmdLine($getCommandLine())
+    if not ownParsedArgv:
+      ownArgv = parseCmdLine($getCommandLine())
+      ownParsedArgv = true
     if i < ownArgv.len and i >= 0: return TaintedString(ownArgv[i])
     raise newException(IndexError, "invalid index")
 
diff --git a/lib/pure/ospaths.nim b/lib/pure/ospaths.nim
index 0414eae5d..bc6739dd3 100644
--- a/lib/pure/ospaths.nim
+++ b/lib/pure/ospaths.nim
@@ -449,6 +449,31 @@ proc isAbsolute*(path: string): bool {.rtl, noSideEffect, extern: "nos$1".} =
   elif defined(posix):
     result = path[0] == '/'
 
+
+proc normalizePathEnd(path: var string, trailingSep = false) =
+  ## ensures ``path`` has exactly 0 or 1 trailing `DirSep`, depending on
+  ## ``trailingSep``, and taking care of edge cases: it preservers whether
+  ## a path is absolute or relative, and makes sure trailing sep is `DirSep`,
+  ## not `AltSep`.
+  if path.len == 0: return
+  var i = path.len
+  while i >= 1 and path[i-1] in {DirSep, AltSep}: dec(i)
+  if trailingSep:
+    # foo// => foo
+    path.setLen(i)
+    # foo => foo/
+    path.add DirSep
+  elif i>0:
+    # foo// => foo
+    path.setLen(i)
+  else:
+    # // => / (empty case was already taken care of)
+    path = $DirSep
+
+proc normalizePathEnd(path: string, trailingSep = false): string =
+  result = path
+  result.normalizePathEnd(trailingSep)
+
 proc unixToNativePath*(path: string, drive=""): string {.
   noSideEffect, rtl, extern: "nos$1".} =
   ## Converts an UNIX-like path to a native one.
@@ -530,10 +555,12 @@ proc getConfigDir*(): string {.rtl, extern: "nos$1",
   ## "~/.config/", otherwise.
   ##
   ## An OS-dependent trailing slash is always present at the end of the
-  ## returned string; `\\` on Windows and `/` on all other OSs.
-  when defined(windows): return string(getEnv("APPDATA")) & "\\"
-  elif getEnv("XDG_CONFIG_HOME"): return string(getEnv("XDG_CONFIG_HOME")) & "/"
-  else: return string(getEnv("HOME")) & "/.config/"
+  ## returned string; `\` on Windows and `/` on all other OSs.
+  when defined(windows):
+    result = getEnv("APPDATA").string
+  else:
+    result = getEnv("XDG_CONFIG_HOME", getEnv("HOME").string / ".config").string
+  result.normalizePathEnd(trailingSep = true)
 
 proc getTempDir*(): string {.rtl, extern: "nos$1",
   tags: [ReadEnvEffect, ReadIOEffect].} =
@@ -647,3 +674,24 @@ when isMainModule:
 
   when defined(posix):
     assert quoteShell("") == "''"
+
+  block normalizePathEndTest:
+    # handle edge cases correctly: shouldn't affect whether path is
+    # absolute/relative
+    doAssert "".normalizePathEnd(true) == ""
+    doAssert "".normalizePathEnd(false) == ""
+    doAssert "/".normalizePathEnd(true) == $DirSep
+    doAssert "/".normalizePathEnd(false) == $DirSep
+
+    when defined(posix):
+      doAssert "//".normalizePathEnd(false) == "/"
+      doAssert "foo.bar//".normalizePathEnd == "foo.bar"
+      doAssert "bar//".normalizePathEnd(trailingSep = true) == "bar/"
+    when defined(Windows):
+      doAssert r"C:\foo\\".normalizePathEnd == r"C:\foo"
+      doAssert r"C:\foo".normalizePathEnd(trailingSep = true) == r"C:\foo\"
+      # this one is controversial: we could argue for returning `D:\` instead,
+      # but this is simplest.
+      doAssert r"D:\".normalizePathEnd == r"D:"
+      doAssert r"E:/".normalizePathEnd(trailingSep = true) == r"E:\"
+      doAssert "/".normalizePathEnd == r"\"
diff --git a/lib/pure/osproc.nim b/lib/pure/osproc.nim
index f86acfc49..faeb01407 100644
--- a/lib/pure/osproc.nim
+++ b/lib/pure/osproc.nim
@@ -884,9 +884,11 @@ elif not defined(useNimRtl):
         chck posix_spawn_file_actions_adddup2(fops, data.pStdin[readIdx], readIdx)
         chck posix_spawn_file_actions_addclose(fops, data.pStdout[readIdx])
         chck posix_spawn_file_actions_adddup2(fops, data.pStdout[writeIdx], writeIdx)
-        if (poStdErrToStdOut in data.options):
-          chck posix_spawn_file_actions_addclose(fops, data.pStderr[readIdx])
+        chck posix_spawn_file_actions_addclose(fops, data.pStderr[readIdx])
+        if poStdErrToStdOut in data.options:
           chck posix_spawn_file_actions_adddup2(fops, data.pStdout[writeIdx], 2)
+        else:
+          chck posix_spawn_file_actions_adddup2(fops, data.pStderr[writeIdx], 2)
 
       var res: cint
       if data.workingDir.len > 0:
diff --git a/lib/pure/parsecfg.nim b/lib/pure/parsecfg.nim
index 5fa2d8dc3..b991dd57f 100644
--- a/lib/pure/parsecfg.nim
+++ b/lib/pure/parsecfg.nim
@@ -17,12 +17,37 @@
 ##
 ## .. include:: ../../doc/mytest.cfg
 ##     :literal:
-## The file ``examples/parsecfgex.nim`` demonstrates how to use the
-## configuration file parser:
-##
-## .. code-block:: nim
-##     :file: ../../examples/parsecfgex.nim
 ##
+
+##[ Here is an example of how to use the configuration file parser:
+
+.. code-block:: nim
+
+    import
+      os, parsecfg, strutils, streams
+
+    var f = newFileStream(paramStr(1), fmRead)
+    if f != nil:
+      var p: CfgParser
+      open(p, f, paramStr(1))
+      while true:
+        var e = next(p)
+        case e.kind
+        of cfgEof: break
+        of cfgSectionStart:   ## a ``[section]`` has been parsed
+          echo("new section: " & e.section)
+        of cfgKeyValuePair:
+          echo("key-value-pair: " & e.key & ": " & e.value)
+        of cfgOption:
+          echo("command: " & e.key & ": " & e.value)
+        of cfgError:
+          echo(e.msg)
+      close(p)
+    else:
+      echo("cannot open: " & paramStr(1))
+
+]##
+
 ## Examples
 ## --------
 ##
diff --git a/lib/pure/parseopt.nim b/lib/pure/parseopt.nim
index 58e1be0e4..c91134738 100644
--- a/lib/pure/parseopt.nim
+++ b/lib/pure/parseopt.nim
@@ -49,20 +49,24 @@ type
     inShortState: bool
     shortNoVal: set[char]
     longNoVal: seq[string]
+    cmds: seq[string]
+    idx: int
     kind*: CmdLineKind        ## the dected command line token
     key*, val*: TaintedString ## key and value pair; ``key`` is the option
                               ## or the argument, ``value`` is not "" if
                               ## the option was given a value
 
 proc parseWord(s: string, i: int, w: var string,
-               delim: set[char] = {'\x09', ' '}): int =
+               delim: set[char] = {'\t', ' '}): int =
   result = i
   if result < s.len and s[result] == '\"':
     inc(result)
-    while result < s.len and s[result] != '\"':
+    while result < s.len:
+      if s[result] == '"':
+        inc result
+        break
       add(w, s[result])
       inc(result)
-    if result < s.len and s[result] == '\"': inc(result)
   else:
     while result < s.len and s[result] notin delim:
       add(w, s[result])
@@ -73,7 +77,7 @@ when declared(os.paramCount):
     if find(s, {' ', '\t'}) >= 0 and s.len > 0 and s[0] != '"':
       if s[0] == '-':
         result = newStringOfCap(s.len)
-        var i = parseWord(s, 0, result, {' ', '\x09', ':', '='})
+        var i = parseWord(s, 0, result, {' ', '\t', ':', '='})
         if i < s.len and s[i] in {':','='}:
           result.add s[i]
           inc i
@@ -100,16 +104,21 @@ when declared(os.paramCount):
     ## (though they still need at least a space).  In both cases, ':' or '='
     ## may still be used if desired.  They just become optional.
     result.pos = 0
+    result.idx = 0
     result.inShortState = false
     result.shortNoVal = shortNoVal
     result.longNoVal = longNoVal
     if cmdline != "":
       result.cmd = cmdline
+      result.cmds = parseCmdLine(cmdline)
     else:
       result.cmd = ""
+      result.cmds = newSeq[string](paramCount())
       for i in countup(1, paramCount()):
-        result.cmd.add quote(paramStr(i).string)
+        result.cmds[i-1] = paramStr(i).string
+        result.cmd.add quote(result.cmds[i-1])
         result.cmd.add ' '
+
     result.kind = cmdEnd
     result.key = TaintedString""
     result.val = TaintedString""
@@ -120,80 +129,115 @@ when declared(os.paramCount):
     ## (as provided by the ``OS`` module) is taken. ``shortNoVal`` and
     ## ``longNoVal`` behavior is the same as for ``initOptParser(string,...)``.
     result.pos = 0
+    result.idx = 0
     result.inShortState = false
     result.shortNoVal = shortNoVal
     result.longNoVal = longNoVal
     result.cmd = ""
     if cmdline.len != 0:
+      result.cmds = newSeq[string](cmdline.len)
       for i in 0..<cmdline.len:
+        result.cmds[i] = cmdline[i].string
         result.cmd.add quote(cmdline[i].string)
         result.cmd.add ' '
     else:
+      result.cmds = newSeq[string](paramCount())
       for i in countup(1, paramCount()):
-        result.cmd.add quote(paramStr(i).string)
+        result.cmds[i-1] = paramStr(i).string
+        result.cmd.add quote(result.cmds[i-1])
         result.cmd.add ' '
     result.kind = cmdEnd
     result.key = TaintedString""
     result.val = TaintedString""
 
-proc handleShortOption(p: var OptParser) =
+proc handleShortOption(p: var OptParser; cmd: string) =
   var i = p.pos
   p.kind = cmdShortOption
-  add(p.key.string, p.cmd[i])
+  add(p.key.string, cmd[i])
   inc(i)
   p.inShortState = true
-  while i < p.cmd.len and p.cmd[i] in {'\x09', ' '}:
+  while i < cmd.len and cmd[i] in {'\t', ' '}:
     inc(i)
     p.inShortState = false
-  if i < p.cmd.len and p.cmd[i] in {':', '='} or
+  if i < cmd.len and cmd[i] in {':', '='} or
       card(p.shortNoVal) > 0 and p.key.string[0] notin p.shortNoVal:
-    if i < p.cmd.len and p.cmd[i] in {':', '='}:
+    if i < cmd.len and cmd[i] in {':', '='}:
       inc(i)
     p.inShortState = false
-    while i < p.cmd.len and p.cmd[i] in {'\x09', ' '}: inc(i)
-    i = parseWord(p.cmd, i, p.val.string)
-  if i >= p.cmd.len: p.inShortState = false
-  p.pos = i
+    while i < cmd.len and cmd[i] in {'\t', ' '}: inc(i)
+    p.val = TaintedString substr(cmd, i)
+    p.pos = 0
+    inc p.idx
+  else:
+    p.pos = i
+  if i >= cmd.len:
+    p.inShortState = false
+    p.pos = 0
+    inc p.idx
 
 proc next*(p: var OptParser) {.rtl, extern: "npo$1".} =
   ## parses the first or next option; ``p.kind`` describes what token has been
   ## parsed. ``p.key`` and ``p.val`` are set accordingly.
+  if p.idx >= p.cmds.len:
+    p.kind = cmdEnd
+    return
+
   var i = p.pos
-  while i < p.cmd.len and p.cmd[i] in {'\x09', ' '}: inc(i)
+  while i < p.cmds[p.idx].len and p.cmds[p.idx][i] in {'\t', ' '}: inc(i)
   p.pos = i
   setLen(p.key.string, 0)
   setLen(p.val.string, 0)
   if p.inShortState:
-    handleShortOption(p)
-    return
-  if i >= p.cmd.len:
-    p.kind = cmdEnd
-    return
-  if p.cmd[i] == '-':
+    p.inShortState = false
+    if i >= p.cmds[p.idx].len:
+      inc(p.idx)
+      p.pos = 0
+      if p.idx >= p.cmds.len:
+        p.kind = cmdEnd
+        return
+    else:
+      handleShortOption(p, p.cmds[p.idx])
+      return
+
+  if i < p.cmds[p.idx].len and p.cmds[p.idx][i] == '-':
     inc(i)
-    if i < p.cmd.len and p.cmd[i] == '-':
+    if i < p.cmds[p.idx].len and p.cmds[p.idx][i] == '-':
       p.kind = cmdLongOption
       inc(i)
-      i = parseWord(p.cmd, i, p.key.string, {' ', '\x09', ':', '='})
-      while i < p.cmd.len and p.cmd[i] in {'\x09', ' '}: inc(i)
-      if i < p.cmd.len and p.cmd[i] in {':', '='} or
-          len(p.longNoVal) > 0 and p.key.string notin p.longNoVal:
-        if i < p.cmd.len and p.cmd[i] in {':', '='}:
-          inc(i)
-        while i < p.cmd.len and p.cmd[i] in {'\x09', ' '}: inc(i)
-        p.pos = parseWord(p.cmd, i, p.val.string)
+      i = parseWord(p.cmds[p.idx], i, p.key.string, {' ', '\t', ':', '='})
+      while i < p.cmds[p.idx].len and p.cmds[p.idx][i] in {'\t', ' '}: inc(i)
+      if i < p.cmds[p.idx].len and p.cmds[p.idx][i] in {':', '='}:
+        inc(i)
+        while i < p.cmds[p.idx].len and p.cmds[p.idx][i] in {'\t', ' '}: inc(i)
+        # if we're at the end, use the next command line option:
+        if i >= p.cmds[p.idx].len and p.idx < p.cmds.len:
+          inc p.idx
+          i = 0
+        p.val = TaintedString p.cmds[p.idx].substr(i)
+      elif len(p.longNoVal) > 0 and p.key.string notin p.longNoVal and p.idx+1 < p.cmds.len:
+        p.val = TaintedString p.cmds[p.idx+1]
+        inc p.idx
       else:
-        p.pos = i
+        p.val = TaintedString""
+      inc p.idx
+      p.pos = 0
     else:
       p.pos = i
-      handleShortOption(p)
+      handleShortOption(p, p.cmds[p.idx])
   else:
     p.kind = cmdArgument
-    p.pos = parseWord(p.cmd, i, p.key.string)
+    p.key = TaintedString p.cmds[p.idx]
+    inc p.idx
+    p.pos = 0
 
-proc cmdLineRest*(p: OptParser): TaintedString {.rtl, extern: "npo$1".} =
-  ## retrieves the rest of the command line that has not been parsed yet.
-  result = strip(substr(p.cmd, p.pos, len(p.cmd) - 1)).TaintedString
+when declared(os.paramCount):
+  proc cmdLineRest*(p: OptParser): TaintedString {.rtl, extern: "npo$1".} =
+    ## retrieves the rest of the command line that has not been parsed yet.
+    var res = ""
+    for i in p.idx..<p.cmds.len:
+      if i > p.idx: res.add ' '
+      res.add quote(p.cmds[i])
+    result = res.TaintedString
 
 iterator getopt*(p: var OptParser): tuple[kind: CmdLineKind, key, val: TaintedString] =
   ## This is an convenience iterator for iterating over the given OptParser object.
@@ -214,6 +258,7 @@ iterator getopt*(p: var OptParser): tuple[kind: CmdLineKind, key, val: TaintedSt
   ##     # no filename has been given, so we show the help:
   ##     writeHelp()
   p.pos = 0
+  p.idx = 0
   while true:
     next(p)
     if p.kind == cmdEnd: break
diff --git a/lib/pure/parsesql.nim b/lib/pure/parsesql.nim
index e3bab9a8d..9aef43c1b 100644
--- a/lib/pure/parsesql.nim
+++ b/lib/pure/parsesql.nim
@@ -593,7 +593,6 @@ proc len*(n: SqlNode): int =
 proc `[]`*(n: SqlNode; i: int): SqlNode = n.sons[i]
 
 proc add*(father, n: SqlNode) =
-  if isNil(father.sons): father.sons = @[]
   add(father.sons, n)
 
 proc getTok(p: var SqlParser) =
diff --git a/lib/pure/parsexml.nim b/lib/pure/parsexml.nim
index fe933fb79..d8d5a7a2d 100644
--- a/lib/pure/parsexml.nim
+++ b/lib/pure/parsexml.nim
@@ -26,27 +26,125 @@
 ##   creates.
 ##
 ##
-## Example 1: Retrieve HTML title
-## ==============================
-##
-## The file ``examples/htmltitle.nim`` demonstrates how to use the
-## XML parser to accomplish a simple task: To determine the title of an HTML
-## document.
-##
-## .. code-block:: nim
-##     :file: ../../examples/htmltitle.nim
-##
-##
-## Example 2: Retrieve all HTML links
-## ==================================
-##
-## The file ``examples/htmlrefs.nim`` demonstrates how to use the
-## XML parser to accomplish another simple task: To determine all the links
-## an HTML document contains.
-##
-## .. code-block:: nim
-##     :file: ../../examples/htmlrefs.nim
-##
+
+##[
+
+Example 1: Retrieve HTML title
+==============================
+
+The file ``examples/htmltitle.nim`` demonstrates how to use the
+XML parser to accomplish a simple task: To determine the title of an HTML
+document.
+
+.. code-block:: nim
+
+    # Example program to show the parsexml module
+    # This program reads an HTML file and writes its title to stdout.
+    # Errors and whitespace are ignored.
+
+    import os, streams, parsexml, strutils
+
+    if paramCount() < 1:
+      quit("Usage: htmltitle filename[.html]")
+
+    var filename = addFileExt(paramStr(1), "html")
+    var s = newFileStream(filename, fmRead)
+    if s == nil: quit("cannot open the file " & filename)
+    var x: XmlParser
+    open(x, s, filename)
+    while true:
+      x.next()
+      case x.kind
+      of xmlElementStart:
+        if cmpIgnoreCase(x.elementName, "title") == 0:
+          var title = ""
+          x.next()  # skip "<title>"
+          while x.kind == xmlCharData:
+            title.add(x.charData)
+            x.next()
+          if x.kind == xmlElementEnd and cmpIgnoreCase(x.elementName, "title") == 0:
+            echo("Title: " & title)
+            quit(0) # Success!
+          else:
+            echo(x.errorMsgExpected("/title"))
+
+      of xmlEof: break # end of file reached
+      else: discard # ignore other events
+
+    x.close()
+    quit("Could not determine title!")
+
+]##
+
+##[
+
+Example 2: Retrieve all HTML links
+==================================
+
+The file ``examples/htmlrefs.nim`` demonstrates how to use the
+XML parser to accomplish another simple task: To determine all the links
+an HTML document contains.
+
+.. code-block:: nim
+
+    # Example program to show the new parsexml module
+    # This program reads an HTML file and writes all its used links to stdout.
+    # Errors and whitespace are ignored.
+
+    import os, streams, parsexml, strutils
+
+    proc `=?=` (a, b: string): bool =
+      # little trick: define our own comparator that ignores case
+      return cmpIgnoreCase(a, b) == 0
+
+    if paramCount() < 1:
+      quit("Usage: htmlrefs filename[.html]")
+
+    var links = 0 # count the number of links
+    var filename = addFileExt(paramStr(1), "html")
+    var s = newFileStream(filename, fmRead)
+    if s == nil: quit("cannot open the file " & filename)
+    var x: XmlParser
+    open(x, s, filename)
+    next(x) # get first event
+    block mainLoop:
+      while true:
+        case x.kind
+        of xmlElementOpen:
+          # the <a href = "xyz"> tag we are interested in always has an attribute,
+          # thus we search for ``xmlElementOpen`` and not for ``xmlElementStart``
+          if x.elementName =?= "a":
+            x.next()
+            if x.kind == xmlAttribute:
+              if x.attrKey =?= "href":
+                var link = x.attrValue
+                inc(links)
+                # skip until we have an ``xmlElementClose`` event
+                while true:
+                  x.next()
+                  case x.kind
+                  of xmlEof: break mainLoop
+                  of xmlElementClose: break
+                  else: discard
+                x.next() # skip ``xmlElementClose``
+                # now we have the description for the ``a`` element
+                var desc = ""
+                while x.kind == xmlCharData:
+                  desc.add(x.charData)
+                  x.next()
+                echo(desc & ": " & link)
+          else:
+            x.next()
+        of xmlEof: break # end of file reached
+        of xmlError:
+          echo(errorMsg(x))
+          x.next()
+        else: x.next() # skip other events
+
+    echo($links & " link(s) found!")
+    x.close()
+
+]##
 
 import
   hashes, strutils, lexbase, streams, unicode
diff --git a/lib/pure/pegs.nim b/lib/pure/pegs.nim
index 02a2d6900..3ee82917d 100644
--- a/lib/pure/pegs.nim
+++ b/lib/pure/pegs.nim
@@ -20,11 +20,11 @@ include "system/inclrtl"
 const
   useUnicode = true ## change this to deactivate proper UTF-8 support
 
-import
-  strutils
+import strutils, macros
 
 when useUnicode:
   import unicode
+  export unicode.`==`
 
 const
   InlineThreshold = 5  ## number of leaves; -1 to disable inlining
@@ -74,7 +74,7 @@ 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: Peg                   ## the rule that the symbol refers to
+    rule: Peg                     ## the rule that the symbol refers to
   Peg* {.shallow.} = object ## type that represents a PEG
     case kind: PegKind
     of pkEmpty..pkWhitespace: nil
@@ -86,25 +86,59 @@ type
     else: sons: seq[Peg]
   NonTerminal* = ref NonTerminalObj
 
-proc name*(nt: NonTerminal): string = nt.name
-proc line*(nt: NonTerminal): int = nt.line
-proc col*(nt: NonTerminal): int = nt.col
-proc flags*(nt: NonTerminal): set[NonTerminalFlag] = nt.flags
-proc rule*(nt: NonTerminal): Peg = nt.rule
-
 proc kind*(p: Peg): PegKind = p.kind
+  ## Returns the *PegKind* of a given *Peg* object.
+
 proc term*(p: Peg): string = p.term
+  ## Returns the *string* representation of a given *Peg* variant object 
+  ## where present.
+
 proc ch*(p: Peg): char = p.ch
+  ## Returns the *char* representation of a given *Peg* variant object 
+  ## where present.
+
 proc charChoice*(p: Peg): ref set[char] = p.charChoice
+  ## Returns the *charChoice* field of a given *Peg* variant object 
+  ## where present.
+
 proc nt*(p: Peg): NonTerminal = p.nt
+  ## Returns the *NonTerminal* object of a given *Peg* variant object 
+  ## where present.
+
 proc index*(p: Peg): range[0..MaxSubpatterns] = p.index
+  ## Returns the back-reference index of a captured sub-pattern in the
+  ## *Captures* object for a given *Peg* variant object where present.
+
 iterator items*(p: Peg): Peg {.inline.} =
+  ## Yields the child nodes of a *Peg* variant object where present.
   for s in p.sons:
     yield s
+
 iterator pairs*(p: Peg): (int, Peg) {.inline.} =
+  ## Yields the indices and child nodes of a *Peg* variant object where present.
   for i in 0 ..< p.sons.len:
     yield (i, p.sons[i])
 
+proc name*(nt: NonTerminal): string = nt.name
+  ## Gets the name of the symbol represented by the parent *Peg* object variant
+  ## of a given *NonTerminal*.
+
+proc line*(nt: NonTerminal): int = nt.line
+  ## Gets the line number of the definition of the parent *Peg* object variant
+  ## of a given *NonTerminal*.
+
+proc col*(nt: NonTerminal): int = nt.col
+  ## Gets the column number of the definition of the parent *Peg* object variant
+  ## of a given *NonTerminal*.
+
+proc flags*(nt: NonTerminal): set[NonTerminalFlag] = nt.flags
+  ## Gets the *NonTerminalFlag*-typed flags field of the parent *Peg* variant
+  ## object of a given *NonTerminal*.
+
+proc rule*(nt: NonTerminal): Peg = nt.rule
+  ## Gets the *Peg* object representing the rule definition of the parent *Peg*
+  ## object variant of a given *NonTerminal*. 
+
 proc term*(t: string): Peg {.nosideEffect, rtl, extern: "npegs$1Str".} =
   ## constructs a PEG from a terminal string
   if t.len != 1:
@@ -540,223 +574,497 @@ when not useUnicode:
   proc isTitle(a: char): bool {.inline.} = return false
   proc isWhiteSpace(a: char): bool {.inline.} = return a in {' ', '\9'..'\13'}
 
-proc rawMatch*(s: string, p: Peg, start: int, c: var Captures): int {.
-               nosideEffect, rtl, extern: "npegs$1".} =
-  ## low-level matching proc that implements the PEG interpreter. Use this
-  ## for maximum efficiency (every other PEG operation ends up calling this
-  ## proc).
-  ## Returns -1 if it does not match, else the length of the match
-  case p.kind
-  of pkEmpty: result = 0 # match of length 0
-  of pkAny:
-    if start < s.len: result = 1
-    else: result = -1
-  of pkAnyRune:
-    if start < s.len:
-      result = runeLenAt(s, start)
-    else:
-      result = -1
-  of pkLetter:
-    if start < s.len:
-      var a: Rune
-      result = start
-      fastRuneAt(s, result, a)
-      if isAlpha(a): dec(result, start)
-      else: result = -1
-    else:
-      result = -1
-  of pkLower:
-    if start < s.len:
-      var a: Rune
-      result = start
-      fastRuneAt(s, result, a)
-      if isLower(a): dec(result, start)
-      else: result = -1
-    else:
-      result = -1
-  of pkUpper:
-    if start < s.len:
-      var a: Rune
-      result = start
-      fastRuneAt(s, result, a)
-      if isUpper(a): dec(result, start)
-      else: result = -1
-    else:
-      result = -1
-  of pkTitle:
-    if start < s.len:
-      var a: Rune
-      result = start
-      fastRuneAt(s, result, a)
-      if isTitle(a): dec(result, start)
+template matchOrParse(mopProc: untyped): typed =
+  # Used to make the main matcher proc *rawMatch* as well as event parser
+  # procs. For the former, *enter* and *leave* event handler code generators
+  # are provided which just return *discard*.
+
+  proc mopProc(s: string, p: Peg, start: int, c: var Captures): int =
+    proc matchBackRef(s: string, p: Peg, start: int, c: var Captures): int =
+      # Parse handler code must run in an *of* clause of its own for each
+      # *PegKind*, so we encapsulate the identical clause body for
+      # *pkBackRef..pkBackRefIgnoreStyle* here.
+      if p.index >= c.ml: return -1
+      var (a, b) = c.matches[p.index]
+      var n: Peg
+      n.kind = succ(pkTerminal, ord(p.kind)-ord(pkBackRef))
+      n.term = s.substr(a, b)
+      mopProc(s, n, start, c)
+
+    case p.kind
+    of pkEmpty:
+      enter(pkEmpty, s, p, start)
+      result = 0 # match of length 0
+      leave(pkEmpty, s, p, start, result)
+    of pkAny:
+      enter(pkAny, s, p, start)
+      if start < s.len: result = 1
       else: result = -1
-    else:
-      result = -1
-  of pkWhitespace:
-    if start < s.len:
-      var a: Rune
-      result = start
-      fastRuneAt(s, result, a)
-      if isWhiteSpace(a): dec(result, start)
-      else: result = -1
-    else:
-      result = -1
-  of pkGreedyAny:
-    result = len(s) - start
-  of pkNewLine:
-    if start < s.len and s[start] == '\L': result = 1
-    elif start < s.len and s[start] == '\C':
-      if start+1 < s.len and s[start+1] == '\L': result = 2
-      else: result = 1
-    else: result = -1
-  of pkTerminal:
-    result = len(p.term)
-    for i in 0..result-1:
-      if start+i >= s.len or p.term[i] != s[start+i]:
+      leave(pkAny, s, p, start, result)
+    of pkAnyRune:
+      enter(pkAnyRune, s, p, start)
+      if start < s.len:
+        result = runeLenAt(s, start)
+      else:
         result = -1
-        break
-  of pkTerminalIgnoreCase:
-    var
-      i = 0
-      a, b: Rune
-    result = start
-    while i < len(p.term):
-      if result >= s.len:
+      leave(pkAnyRune, s, p, start, result)
+    of pkLetter:
+      enter(pkLetter, s, p, start)
+      if start < s.len:
+        var a: Rune
+        result = start
+        fastRuneAt(s, result, a)
+        if isAlpha(a): dec(result, start)
+        else: result = -1
+      else:
+        result = -1
+      leave(pkLetter, s, p, start, result)
+    of pkLower:
+      enter(pkLower, s, p, start)
+      if start < s.len:
+        var a: Rune
+        result = start
+        fastRuneAt(s, result, a)
+        if isLower(a): dec(result, start)
+        else: result = -1
+      else:
         result = -1
-        break
-      fastRuneAt(p.term, i, a)
-      fastRuneAt(s, result, b)
-      if toLower(a) != toLower(b):
+      leave(pkLower, s, p, start, result)
+    of pkUpper:
+      enter(pkUpper, s, p, start)
+      if start < s.len:
+        var a: Rune
+        result = start
+        fastRuneAt(s, result, a)
+        if isUpper(a): dec(result, start)
+        else: result = -1
+      else:
         result = -1
-        break
-    dec(result, start)
-  of pkTerminalIgnoreStyle:
-    var
-      i = 0
-      a, b: Rune
-    result = start
-    while i < len(p.term):
+      leave(pkUpper, s, p, start, result)
+    of pkTitle:
+      enter(pkTitle, s, p, start)
+      if start < s.len:
+        var a: Rune
+        result = start
+        fastRuneAt(s, result, a)
+        if isTitle(a): dec(result, start)
+        else: result = -1
+      else:
+        result = -1
+      leave(pkTitle, s, p, start, result)
+    of pkWhitespace:
+      enter(pkWhitespace, s, p, start)
+      if start < s.len:
+        var a: Rune
+        result = start
+        fastRuneAt(s, result, a)
+        if isWhiteSpace(a): dec(result, start)
+        else: result = -1
+      else:
+        result = -1
+      leave(pkWhitespace, s, p, start, result)
+    of pkGreedyAny:
+      enter(pkGreedyAny, s, p, start)
+      result = len(s) - start
+      leave(pkGreedyAny, s, p, start, result)
+    of pkNewLine:
+      enter(pkNewLine, s, p, start)
+      if start < s.len and s[start] == '\L': result = 1
+      elif start < s.len and s[start] == '\C':
+        if start+1 < s.len and s[start+1] == '\L': result = 2
+        else: result = 1
+      else: result = -1
+      leave(pkNewLine, s, p, start, result)
+    of pkTerminal:
+      enter(pkTerminal, s, p, start)
+      result = len(p.term)
+      for i in 0..result-1:
+        if start+i >= s.len or p.term[i] != s[start+i]:
+          result = -1
+          break
+      leave(pkTerminal, s, p, start, result)
+    of pkTerminalIgnoreCase:
+      enter(pkTerminalIgnoreCase, s, p, start)
+      var
+        i = 0
+        a, b: Rune
+      result = start
       while i < len(p.term):
+        if result >= s.len:
+          result = -1
+          break
         fastRuneAt(p.term, i, a)
-        if a != Rune('_'): break
-      while result < s.len:
         fastRuneAt(s, result, b)
-        if b != Rune('_'): break
-      if result >= s.len:
-        if i >= p.term.len: break
-        else:
+        if toLower(a) != toLower(b):
           result = -1
           break
-      elif toLower(a) != toLower(b):
-        result = -1
-        break
-    dec(result, start)
-  of pkChar:
-    if start < s.len and p.ch == s[start]: result = 1
-    else: result = -1
-  of pkCharChoice:
-    if start < s.len and contains(p.charChoice[], s[start]): result = 1
-    else: result = -1
-  of pkNonTerminal:
-    var oldMl = c.ml
-    when false: echo "enter: ", p.nt.name
-    result = rawMatch(s, p.nt.rule, start, c)
-    when false: echo "leave: ", p.nt.name
-    if result < 0: c.ml = oldMl
-  of pkSequence:
-    var oldMl = c.ml
-    result = 0
-    for i in 0..high(p.sons):
-      var x = rawMatch(s, p.sons[i], start+result, c)
-      if x < 0:
+      dec(result, start)
+      leave(pkTerminalIgnoreCase, s, p, start, result)
+    of pkTerminalIgnoreStyle:
+      enter(pkTerminalIgnoreStyle, s, p, start)
+      var
+        i = 0
+        a, b: Rune
+      result = start
+      while i < len(p.term):
+        while i < len(p.term):
+          fastRuneAt(p.term, i, a)
+          if a != Rune('_'): break
+        while result < s.len:
+          fastRuneAt(s, result, b)
+          if b != Rune('_'): break
+        if result >= s.len:
+          if i >= p.term.len: break
+          else:
+            result = -1
+            break
+        elif toLower(a) != toLower(b):
+          result = -1
+          break
+      dec(result, start)
+      leave(pkTerminalIgnoreStyle, s, p, start, result)
+    of pkChar:
+      enter(pkChar, s, p, start)
+      if start < s.len and p.ch == s[start]: result = 1
+      else: result = -1
+      leave(pkChar, s, p, start, result)
+    of pkCharChoice:
+      enter(pkCharChoice, s, p, start)
+      if start < s.len and contains(p.charChoice[], s[start]): result = 1
+      else: result = -1
+      leave(pkCharChoice, s, p, start, result)
+    of pkNonTerminal:
+      enter(pkNonTerminal, s, p, start)
+      var oldMl = c.ml
+      when false: echo "enter: ", p.nt.name
+      result = mopProc(s, p.nt.rule, start, c)
+      when false: echo "leave: ", p.nt.name
+      if result < 0: c.ml = oldMl
+      leave(pkNonTerminal, s, p, start, result)
+    of pkSequence:
+      enter(pkSequence, s, p, start)
+      var oldMl = c.ml
+      result = 0
+      for i in 0..high(p.sons):
+        var x = mopProc(s, p.sons[i], start+result, c)
+        if x < 0:
+          c.ml = oldMl
+          result = -1
+          break
+        else: inc(result, x)
+      leave(pkSequence, s, p, start, result)
+    of pkOrderedChoice:
+      enter(pkOrderedChoice, s, p, start)
+      var oldMl = c.ml
+      for i in 0..high(p.sons):
+        result = mopProc(s, p.sons[i], start, c)
+        if result >= 0: break
         c.ml = oldMl
-        result = -1
-        break
-      else: inc(result, x)
-  of pkOrderedChoice:
-    var oldMl = c.ml
-    for i in 0..high(p.sons):
-      result = rawMatch(s, p.sons[i], start, c)
-      if result >= 0: break
+      leave(pkOrderedChoice, s, p, start, result)
+    of pkSearch:
+      enter(pkSearch, s, p, start)
+      var oldMl = c.ml
+      result = 0
+      while start+result <= s.len:
+        var x = mopProc(s, p.sons[0], start+result, c)
+        if x >= 0:
+          inc(result, x)
+          leave(pkSearch, s, p, start, result)
+          return
+        inc(result)
+      result = -1
       c.ml = oldMl
-  of pkSearch:
-    var oldMl = c.ml
-    result = 0
-    while start+result <= s.len:
-      var x = rawMatch(s, p.sons[0], start+result, c)
-      if x >= 0:
+      leave(pkSearch, s, p, start, result)
+    of pkCapturedSearch:
+      enter(pkCapturedSearch, s, p, start)
+      var idx = c.ml # reserve a slot for the subpattern
+      inc(c.ml)
+      result = 0
+      while start+result <= s.len:
+        var x = mopProc(s, p.sons[0], start+result, c)
+        if x >= 0:
+          if idx < MaxSubpatterns:
+            c.matches[idx] = (start, start+result-1)
+          #else: silently ignore the capture
+          inc(result, x)
+          leave(pkCapturedSearch, s, p, start, result)
+          return
+        inc(result)
+      result = -1
+      c.ml = idx
+      leave(pkCapturedSearch, s, p, start, result)
+    of pkGreedyRep:
+      enter(pkGreedyRep, s, p, start)
+      result = 0
+      while true:
+        var x = mopProc(s, p.sons[0], start+result, c)
+        # if x == 0, we have an endless loop; so the correct behaviour would be
+        # not to break. But endless loops can be easily introduced:
+        # ``(comment / \w*)*`` is such an example. Breaking for x == 0 does the
+        # expected thing in this case.
+        if x <= 0: break
         inc(result, x)
-        return
-      inc(result)
-    result = -1
-    c.ml = oldMl
-  of pkCapturedSearch:
-    var idx = c.ml # reserve a slot for the subpattern
-    inc(c.ml)
-    result = 0
-    while start+result <= s.len:
-      var x = rawMatch(s, p.sons[0], start+result, c)
-      if x >= 0:
+      leave(pkGreedyRep, s, p, start, result)
+    of pkGreedyRepChar:
+      enter(pkGreedyRepChar, s, p, start)
+      result = 0
+      var ch = p.ch
+      while start+result < s.len and ch == s[start+result]: inc(result)
+      leave(pkGreedyRepChar, s, p, start, result)
+    of pkGreedyRepSet:
+      enter(pkGreedyRepSet, s, p, start)
+      result = 0
+      while start+result < s.len and contains(p.charChoice[], s[start+result]): inc(result)
+      leave(pkGreedyRepSet, s, p, start, result)
+    of pkOption:
+      enter(pkOption, s, p, start)
+      result = max(0, mopProc(s, p.sons[0], start, c))
+      leave(pkOption, s, p, start, result)
+    of pkAndPredicate:
+      enter(pkAndPredicate, s, p, start)
+      var oldMl = c.ml
+      result = mopProc(s, p.sons[0], start, c)
+      if result >= 0: result = 0 # do not consume anything
+      else: c.ml = oldMl
+      leave(pkAndPredicate, s, p, start, result)
+    of pkNotPredicate:
+      enter(pkNotPredicate, s, p, start)
+      var oldMl = c.ml
+      result = mopProc(s, p.sons[0], start, c)
+      if result < 0: result = 0
+      else:
+        c.ml = oldMl
+        result = -1
+      leave(pkNotPredicate, s, p, start, result)
+    of pkCapture:
+      enter(pkCapture, s, p, start)
+      var idx = c.ml # reserve a slot for the subpattern
+      inc(c.ml)
+      result = mopProc(s, p.sons[0], start, c)
+      if result >= 0:
         if idx < MaxSubpatterns:
           c.matches[idx] = (start, start+result-1)
         #else: silently ignore the capture
-        inc(result, x)
-        return
-      inc(result)
-    result = -1
-    c.ml = idx
-  of pkGreedyRep:
-    result = 0
-    while true:
-      var x = rawMatch(s, p.sons[0], start+result, c)
-      # if x == 0, we have an endless loop; so the correct behaviour would be
-      # not to break. But endless loops can be easily introduced:
-      # ``(comment / \w*)*`` is such an example. Breaking for x == 0 does the
-      # expected thing in this case.
-      if x <= 0: break
-      inc(result, x)
-  of pkGreedyRepChar:
-    result = 0
-    var ch = p.ch
-    while start+result < s.len and ch == s[start+result]: inc(result)
-  of pkGreedyRepSet:
-    result = 0
-    while start+result < s.len and contains(p.charChoice[], s[start+result]): inc(result)
-  of pkOption:
-    result = max(0, rawMatch(s, p.sons[0], start, c))
-  of pkAndPredicate:
-    var oldMl = c.ml
-    result = rawMatch(s, p.sons[0], start, c)
-    if result >= 0: result = 0 # do not consume anything
-    else: c.ml = oldMl
-  of pkNotPredicate:
-    var oldMl = c.ml
-    result = rawMatch(s, p.sons[0], start, c)
-    if result < 0: result = 0
-    else:
-      c.ml = oldMl
-      result = -1
-  of pkCapture:
-    var idx = c.ml # reserve a slot for the subpattern
-    inc(c.ml)
-    result = rawMatch(s, p.sons[0], start, c)
-    if result >= 0:
-      if idx < MaxSubpatterns:
-        c.matches[idx] = (start, start+result-1)
-      #else: silently ignore the capture
-    else:
-      c.ml = idx
-  of pkBackRef..pkBackRefIgnoreStyle:
-    if p.index >= c.ml: return -1
-    var (a, b) = c.matches[p.index]
-    var n: Peg
-    n.kind = succ(pkTerminal, ord(p.kind)-ord(pkBackRef))
-    n.term = s.substr(a, b)
-    result = rawMatch(s, n, start, c)
-  of pkStartAnchor:
-    if c.origStart == start: result = 0
-    else: result = -1
-  of pkRule, pkList: assert false
+      else:
+        c.ml = idx
+      leave(pkCapture, s, p, start, result)
+    of pkBackRef:
+      enter(pkBackRef, s, p, start)
+      result = matchBackRef(s, p, start, c)
+      leave(pkBackRef, s, p, start, result)
+    of pkBackRefIgnoreCase:
+      enter(pkBackRefIgnoreCase, s, p, start)
+      result = matchBackRef(s, p, start, c)
+      leave(pkBackRefIgnoreCase, s, p, start, result)
+    of pkBackRefIgnoreStyle:
+      enter(pkBackRefIgnoreStyle, s, p, start)
+      result = matchBackRef(s, p, start, c)
+      leave(pkBackRefIgnoreStyle, s, p, start, result)
+    of pkStartAnchor:
+      enter(pkStartAnchor, s, p, start)
+      if c.origStart == start: result = 0
+      else: result = -1
+      leave(pkStartAnchor, s, p, start, result)
+    of pkRule, pkList: assert false
+
+proc rawMatch*(s: string, p: Peg, start: int, c: var Captures): int
+      {.noSideEffect, rtl, extern: "npegs$1".} =
+  ## low-level matching proc that implements the PEG interpreter. Use this
+  ## for maximum efficiency (every other PEG operation ends up calling this
+  ## proc).
+  ## Returns -1 if it does not match, else the length of the match
+
+  # Set the handler generators to produce do-nothing handlers.
+  template enter(pk, s, p, start) =
+    discard
+  template leave(pk, s, p, start, length) =
+    discard
+  matchOrParse(matchIt)
+  result = matchIt(s, p, start, c)
+
+macro mkHandlerTplts(handlers: untyped): untyped =
+  # Transforms the handler spec in *handlers* into handler templates.
+  # The AST structure of *handlers[0]*:
+  # 
+  # .. code-block::
+  # StmtList
+  #   Call
+  #     Ident "pkNonTerminal"
+  #     StmtList
+  #       Call
+  #         Ident "enter"
+  #         StmtList
+  #           <handler code block>
+  #       Call
+  #         Ident "leave"
+  #         StmtList
+  #           <handler code block>
+  #   Call
+  #     Ident "pkChar"
+  #     StmtList
+  #       Call
+  #         Ident "leave"
+  #         StmtList
+  #           <handler code block>
+  #   ...
+  proc mkEnter(hdName, body: NimNode): NimNode =
+    quote do:
+      template `hdName`(s, p, start) =
+        let s {.inject.} = s
+        let p {.inject.} = p
+        let start {.inject.} = start
+        `body`
+
+  template mkLeave(hdPostf, body) {.dirty.} =
+    # this has to be dirty to be able to capture *result* as *length* in
+    # *leaveXX* calls.
+    template `leave hdPostf`(s, p, start, length) =
+      body
+
+  result = newStmtList()
+  for topCall in handlers[0]:
+    if nnkCall != topCall.kind:
+      error("Call syntax expected.", topCall)
+    let pegKind = topCall[0]
+    if nnkIdent != pegKind.kind:
+      error("PegKind expected.", pegKind)
+    if 2 == topCall.len:
+      for hdDef in topCall[1]:
+        if nnkCall != hdDef.kind:
+          error("Call syntax expected.", hdDef)
+        if nnkIdent != hdDef[0].kind:
+          error("Handler identifier expected.", hdDef[0])
+        if 2 == hdDef.len:
+          let hdPostf = substr(pegKind.strVal, 2)
+          case hdDef[0].strVal
+          of "enter":
+            result.add mkEnter(newIdentNode("enter" & hdPostf), hdDef[1])
+          of "leave":
+            result.add getAst(mkLeave(ident(hdPostf), hdDef[1]))
+          else:
+            error(
+              "Unsupported handler identifier, expected 'enter' or 'leave'.",
+              hdDef[0]
+            )
+
+template eventParser*(pegAst, handlers: untyped): (proc(s: string): int) =
+  ## Generates an interpreting event parser *proc* according to the specified
+  ## PEG AST and handler code blocks. The *proc* can be called with a string
+  ## to be parsed and will execute the handler code blocks whenever their
+  ## associated grammar element is matched. It returns -1 if the string does not
+  ## match, else the length of the total match. The following example code
+  ## evaluates an arithmetic expression defined by a simple PEG:
+  ##
+  ## .. code-block:: nim
+  ##  import strutils, pegs
+  ##
+  ##  let
+  ##    pegAst = """
+  ##  Expr    <- Sum
+  ##  Sum     <- Product (('+' / '-')Product)*
+  ##  Product <- Value (('*' / '/')Value)*
+  ##  Value   <- [0-9]+ / '(' Expr ')'
+  ##    """.peg
+  ##    txt = "(5+3)/2-7*22"
+  ##
+  ##  var
+  ##    pStack: seq[string] = @[]
+  ##    valStack: seq[float] = @[]
+  ##    opStack = ""
+  ##  let
+  ##    parseArithExpr = pegAst.eventParser:
+  ##      pkNonTerminal:
+  ##        enter:
+  ##          pStack.add p.nt.name
+  ##        leave:
+  ##          pStack.setLen pStack.high
+  ##          if length > 0:
+  ##            let matchStr = s.substr(start, start+length-1)
+  ##            case p.nt.name
+  ##            of "Value":
+  ##              try:
+  ##                valStack.add matchStr.parseFloat
+  ##                echo valStack
+  ##              except ValueError:
+  ##                discard
+  ##            of "Sum", "Product":
+  ##              try:
+  ##                let val = matchStr.parseFloat
+  ##              except ValueError:
+  ##                if valStack.len > 1 and opStack.len > 0:
+  ##                  valStack[^2] = case opStack[^1]
+  ##                  of '+': valStack[^2] + valStack[^1]
+  ##                  of '-': valStack[^2] - valStack[^1]
+  ##                  of '*': valStack[^2] * valStack[^1]
+  ##                  else: valStack[^2] / valStack[^1]
+  ##                  valStack.setLen valStack.high
+  ##                  echo valStack
+  ##                  opStack.setLen opStack.high
+  ##                  echo opStack
+  ##      pkChar:
+  ##        leave:
+  ##          if length == 1 and "Value" != pStack[^1]:
+  ##            let matchChar = s[start]
+  ##            opStack.add matchChar
+  ##            echo opStack
+  ##
+  ##  let pLen = parseArithExpr(txt)
+  ## 
+  ## The *handlers* parameter consists of code blocks for *PegKinds*,
+  ## which define the grammar elements of interest. Each block can contain
+  ## handler code to be executed when the parser enters and leaves text
+  ## matching the grammar element. An *enter* handler can access the specific
+  ## PEG AST node being matched as *p*, the entire parsed string as *s*
+  ## and the position of the matched text segment in *s* as *start*. A *leave*
+  ## handler can access *p*, *s*, *start* and also the length of the matched
+  ## text segment as *length*. For an unsuccessful match, the *enter* and
+  ## *leave* handlers will be executed, with *length* set to -1.
+  ##
+  ## Symbols  declared in an *enter* handler can be made visible in the
+  ## corresponding *leave* handler by annotating them with an *inject* pragma.
+  proc rawParse(s: string, p: Peg, start: int, c: var Captures): int
+      {.genSym.} =
+
+    # binding from *macros*
+    bind strVal
+
+    mkHandlerTplts:
+      handlers
+
+    macro enter(pegKind, s, pegNode, start: untyped): untyped =
+      # This is called by the matcher code in *matchOrParse* at the
+      # start of the code for a grammar element of kind *pegKind*.
+      # Expands to a call to the handler template if one was generated
+      # by *mkHandlerTplts*.
+      template mkDoEnter(hdPostf, s, pegNode, start) =
+        when declared(`enter hdPostf`):
+          `enter hdPostf`(s, pegNode, start):
+        else:
+          discard
+      let hdPostf = ident(substr(strVal(pegKind), 2))
+      getAst(mkDoEnter(hdPostf, s, pegNode, start))
+
+    macro leave(pegKind, s, pegNode, start, length: untyped): untyped =
+      # Like *enter*, but called at the end of the matcher code for
+      # a grammar element of kind *pegKind*.
+      template mkDoLeave(hdPostf, s, pegNode, start, length) =
+        when declared(`leave hdPostf`):
+          `leave hdPostf`(s, pegNode, start, length):
+        else:
+          discard
+      let hdPostf = ident(substr(strVal(pegKind), 2))
+      getAst(mkDoLeave(hdPostf, s, pegNode, start, length))
+
+    matchOrParse(parseIt)
+    parseIt(s, p, start, c)
+
+  proc parser(s: string): int {.genSym.} =
+    # the proc to be returned
+    var
+      ms: array[MaxSubpatterns, (int, int)]
+      cs = Captures(matches: ms, ml: 0, origStart: 0)
+    rawParse(s, pegAst, 0, cs)
+  parser
 
 template fillMatches(s, caps, c) =
   for k in 0..c.ml-1:
diff --git a/lib/pure/strscans.nim b/lib/pure/strscans.nim
index 11f182495..b17eee6ff 100644
--- a/lib/pure/strscans.nim
+++ b/lib/pure/strscans.nim
@@ -10,7 +10,7 @@
 ##[
 This module contains a `scanf`:idx: macro that can be used for extracting
 substrings from an input string. This is often easier than regular expressions.
-Some examples as an apetizer:
+Some examples as an appetizer:
 
 .. code-block:: nim
   # check if input string matches a triple of integers:
@@ -308,7 +308,7 @@ proc buildUserCall(x: string; args: varargs[NimNode]): NimNode =
     for i in 1..<y.len: result.add y[i]
 
 macro scanf*(input: string; pattern: static[string]; results: varargs[typed]): bool =
-  ## See top level documentation of his module of how ``scanf`` works.
+  ## See top level documentation of this module about how ``scanf`` works.
   template matchBind(parser) {.dirty.} =
     var resLen = genSym(nskLet, "resLen")
     conds.add newLetStmt(resLen, newCall(bindSym(parser), inp, results[i], idx))
@@ -469,7 +469,7 @@ template success*(x: int): bool = x != 0
 template nxt*(input: string; idx, step: int = 1) = inc(idx, step)
 
 macro scanp*(input, idx: typed; pattern: varargs[untyped]): bool =
-  ## See top level documentation of his module of how ``scanf`` works.
+  ## See top level documentation of this module about how ``scanp`` works.
   type StmtTriple = tuple[init, cond, action: NimNode]
 
   template interf(x): untyped = bindSym(x, brForceOpen)
diff --git a/lib/pure/strutils.nim b/lib/pure/strutils.nim
index 33f153587..396f14972 100644
--- a/lib/pure/strutils.nim
+++ b/lib/pure/strutils.nim
@@ -820,7 +820,7 @@ proc toHex*(x: BiggestInt, len: Positive): string {.noSideEffect,
     # handle negative overflow
     if n == 0 and x < 0: n = -1
 
-proc toHex*[T](x: T): string =
+proc toHex*[T: SomeInteger](x: T): string =
   ## Shortcut for ``toHex(x, T.sizeOf * 2)``
   toHex(BiggestInt(x), T.sizeOf * 2)
 
@@ -1692,14 +1692,12 @@ proc insertSep*(s: string, sep = '_', digits = 3): string {.noSideEffect,
     dec(L)
 
 proc escape*(s: string, prefix = "\"", suffix = "\""): string {.noSideEffect,
-  rtl, extern: "nsuEscape", deprecated.} =
+  rtl, extern: "nsuEscape".} =
   ## Escapes a string `s`. See `system.addEscapedChar <system.html#addEscapedChar>`_
   ## for the escaping scheme.
   ##
   ## The resulting string is prefixed with `prefix` and suffixed with `suffix`.
   ## Both may be empty strings.
-  ##
-  ## **Warning:** This procedure is deprecated because it's to easy to missuse.
   result = newStringOfCap(s.len + s.len shr 2)
   result.add(prefix)
   for c in items(s):
@@ -1714,7 +1712,7 @@ proc escape*(s: string, prefix = "\"", suffix = "\""): string {.noSideEffect,
   add(result, suffix)
 
 proc unescape*(s: string, prefix = "\"", suffix = "\""): string {.noSideEffect,
-  rtl, extern: "nsuUnescape", deprecated.} =
+  rtl, extern: "nsuUnescape".} =
   ## Unescapes a string `s`.
   ##
   ## This complements `escape <#escape>`_ as it performs the opposite
@@ -1722,8 +1720,6 @@ proc unescape*(s: string, prefix = "\"", suffix = "\""): string {.noSideEffect,
   ##
   ## If `s` does not begin with ``prefix`` and end with ``suffix`` a
   ## ValueError exception will be raised.
-  ##
-  ## **Warning:** This procedure is deprecated because it's to easy to missuse.
   result = newStringOfCap(s.len)
   var i = prefix.len
   if not s.startsWith(prefix):
diff --git a/lib/pure/times.nim b/lib/pure/times.nim
index 6251c70d9..a7ccbf6ee 100644
--- a/lib/pure/times.nim
+++ b/lib/pure/times.nim
@@ -608,7 +608,6 @@ proc stringifyUnit(value: int | int64, unit: TimeUnit): string =
 
 proc humanizeParts(parts: seq[string]): string =
   ## Make date string parts human-readable
-
   result = ""
   if parts.len == 0:
     result.add "0 nanoseconds"
@@ -617,8 +616,8 @@ proc humanizeParts(parts: seq[string]): string =
   elif parts.len == 2:
     result = parts[0] & " and " & parts[1]
   else:
-    for part in parts[0..high(parts)-1]:
-      result.add part & ", "
+    for i in 0..high(parts)-1:
+      result.add parts[i] & ", "
     result.add "and " & parts[high(parts)]
 
 proc `$`*(dur: Duration): string =
@@ -957,6 +956,17 @@ else:
     result.inc tm.second
 
   proc getLocalOffsetAndDst(unix: int64): tuple[offset: int, dst: bool] =
+    # Windows can't handle unix < 0, so we fall back to unix = 0.
+    # FIXME: This should be improved by falling back to the WinAPI instead.
+    when defined(windows):
+      if unix < 0:
+        var a = 0.CTime
+        let tmPtr = localtime(addr(a))
+        if not tmPtr.isNil:
+          let tm = tmPtr[]
+          return ((0 - tm.toAdjUnix).int, false)
+        return (0, false)
+
     var a = unix.CTime
     let tmPtr = localtime(addr(a))
     if not tmPtr.isNil:
diff --git a/lib/pure/unidecode/gen.py b/lib/pure/unidecode/gen.py
index 8da0136ff..f0647ea6c 100644
--- a/lib/pure/unidecode/gen.py
+++ b/lib/pure/unidecode/gen.py
@@ -1,26 +1,30 @@
-#! usr/bin/env python
+#! usr/bin/env python3
 # -*- coding: utf-8 -*-
 
 # Generates the unidecode.dat module
 # (c) 2010 Andreas Rumpf
 
 from unidecode import unidecode
+try:
+  import warnings
+  warnings.simplefilter("ignore")
+except ImportError:
+  pass
 
-def main2(): 
-  data = []
-  for x in xrange(128, 0xffff + 1):
-    u = eval("u'\u%04x'" % x)
-    
-    val = unidecode(u)
-    data.append(val)
-    
-    
-  f = open("unidecode.dat", "wb+") 
-  for d in data:
-    f.write("%s\n" % d)
-  f.close()
+def main2():
+  f = open("unidecode.dat", "wb+")
+  for x in range(128, 0xffff + 1):
+    u = eval("u'\\u%04x'" % x)
 
+    val = unidecode(u)
 
-main2()
+    # f.write("%x | " % x)
+    if x==0x2028: # U+2028 = LINE SEPARATOR
+      val = ""
+    elif x==0x2029: # U+2028 = PARAGRAPH SEPARATOR
+      val = ""
+    f.write("%s\n" % val)
 
+  f.close()
 
+main2()
\ No newline at end of file
diff --git a/lib/pure/unidecode/unidecode.dat b/lib/pure/unidecode/unidecode.dat
index 9dff0a4a9..5f4c075d8 100644
--- a/lib/pure/unidecode/unidecode.dat
+++ b/lib/pure/unidecode/unidecode.dat
@@ -58,9 +58,9 @@ P
 1
 o
 >>
-1/4
-1/2
-3/4
+ 1/4 
+ 1/2 
+ 3/4 
 ?
 A
 A
@@ -91,7 +91,7 @@ U
 U
 U
 U
-U
+Y
 Th
 ss
 a
@@ -177,7 +177,7 @@ i
 I
 i
 IJ
-
+ij
 J
 j
 K
@@ -368,7 +368,7 @@ ZH
 zh
 j
 DZ
-D
+Dz
 dz
 G
 g
@@ -414,8 +414,8 @@ Y
 y
 H
 h
-[?]
-[?]
+N
+d
 OU
 ou
 Z
@@ -434,34 +434,34 @@ O
 o
 Y
 y
+l
+n
+t
+j
+db
+qp
+A
+C
+c
+L
+T
+s
+z
 [?]
 [?]
-[?]
-[?]
-[?]
-[?]
-[?]
-[?]
-[?]
-[?]
-[?]
-[?]
-[?]
-[?]
-[?]
-[?]
-[?]
-[?]
-[?]
-[?]
-[?]
-[?]
-[?]
-[?]
-[?]
-[?]
-[?]
-[?]
+B
+U
+^
+E
+e
+J
+j
+q
+q
+R
+r
+Y
+y
 a
 a
 a
@@ -503,13 +503,13 @@ o
 OE
 O
 F
-R
-R
-R
-R
 r
 r
-R
+r
+r
+r
+r
+r
 R
 R
 s
@@ -519,12 +519,12 @@ S
 S
 t
 t
-U
+u
 U
 v
 ^
-W
-Y
+w
+y
 Y
 z
 z
@@ -556,9 +556,9 @@ ls
 lz
 WW
 ]]
-[?]
-[?]
-k
+h
+h
+h
 h
 j
 r
@@ -737,19 +737,19 @@ V
 
 
 
-[?]
-[?]
-[?]
-[?]
-[?]
-[?]
-[?]
-[?]
-[?]
-[?]
-[?]
-[?]
-[?]
+a
+e
+i
+o
+u
+c
+d
+h
+m
+r
+t
+v
+x
 [?]
 [?]
 [?]
@@ -1287,7 +1287,7 @@ o
 f
 ew
 [?]
-.
+:
 -
 [?]
 [?]
@@ -1340,9 +1340,9 @@ o
 u
 '
 
+-
 
-
-
+|
 
 
 :
@@ -7402,41 +7402,41 @@ bh
 
 
 
+b
+d
+f
+m
+n
+p
+r
+r
+s
+t
+z
+g
 
 
 
 
 
+p
 
 
+b
+d
+f
+g
+k
+l
+m
+n
+p
+r
+s
 
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+v
+x
+z
 
 
 
@@ -7708,7 +7708,7 @@ a
 S
 [?]
 [?]
-[?]
+Ss
 [?]
 A
 a
@@ -8109,9 +8109,6 @@ _
 
 
 
-
-
-
  
 %0
 %00
@@ -8136,19 +8133,23 @@ _
 /
 -[
 ]-
-[?]
+??
 ?!
 !?
 7
 PP
 (]
 [)
+*
 [?]
 [?]
 [?]
+%
+~
 [?]
 [?]
 [?]
+''''
 [?]
 [?]
 [?]
@@ -8156,12 +8157,8 @@ PP
 [?]
 [?]
 [?]
-[?]
-[?]
-[?]
-[?]
-[?]
-[?]
+ 
+
 [?]
 [?]
 [?]
@@ -8178,7 +8175,7 @@ PP
 
 
 0
-
+i
 
 
 4
@@ -8209,19 +8206,19 @@ n
 (
 )
 [?]
+a
+e
+o
+x
 [?]
-[?]
-[?]
-[?]
-[?]
-[?]
-[?]
-[?]
-[?]
-[?]
-[?]
-[?]
-[?]
+h
+k
+l
+m
+n
+p
+s
+t
 [?]
 [?]
 [?]
@@ -8237,26 +8234,26 @@ Rs
 W
 NS
 D
-EU
+EUR
 K
 T
 Dr
-[?]
-[?]
-[?]
-[?]
-[?]
-[?]
-[?]
-[?]
-[?]
-[?]
-[?]
-[?]
-[?]
-[?]
-[?]
-[?]
+Pf
+P
+G
+A
+UAH
+C|
+L
+Sm
+T
+Rs
+L
+M
+m
+R
+l
+BTC
 [?]
 [?]
 [?]
@@ -8294,6 +8291,7 @@ Dr
 
 
 [?]
+
 [?]
 [?]
 [?]
@@ -8319,63 +8317,67 @@ Dr
 [?]
 [?]
 [?]
-[?]
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
 
+ a/c 
+ a/s 
+C
 
 
+ c/o 
+ c/u 
 
 
 
+g
+H
+H
+H
+h
 
+I
+I
+L
+l
 
+N
+No. 
 
 
+P
+Q
+R
+R
+R
 
 
+(sm)
+TEL
+(tm)
 
+Z
 
 
 
+Z
 
+K
+A
+B
+C
+e
+e
+E
+F
+F
+M
+o
 
 
 
 
+i
 
+FAX
 
 
 
@@ -8385,25 +8387,20 @@ Dr
 [?]
 [?]
 [?]
+D
+d
+e
+i
+j
 [?]
 [?]
 [?]
 [?]
+F
 [?]
-[?]
-[?]
-[?]
-[?]
-[?]
-[?]
-[?]
-[?]
-[?]
-[?]
-[?]
-[?]
-[?]
-[?]
+ 1/7 
+ 1/9 
+ 1/10 
  1/3 
  2/3 
  1/5 
@@ -8458,7 +8455,7 @@ D)
 [?]
 [?]
 [?]
-[?]
+ 0/3 
 [?]
 [?]
 [?]
@@ -8595,8 +8592,12 @@ V
 [?]
 [?]
 [?]
+-
 [?]
 [?]
+/
+\
+*
 [?]
 [?]
 [?]
@@ -8608,6 +8609,7 @@ V
 [?]
 [?]
 [?]
+|
 [?]
 [?]
 [?]
@@ -8626,11 +8628,13 @@ V
 [?]
 [?]
 [?]
+:
 [?]
 [?]
 [?]
 [?]
 [?]
+~
 [?]
 [?]
 [?]
@@ -8670,17 +8674,10 @@ V
 [?]
 [?]
 [?]
-[?]
-[?]
-[?]
-[?]
-[?]
-[?]
-[?]
-[?]
-[?]
-[?]
-[?]
+<=
+>=
+<=
+>=
 [?]
 [?]
 [?]
@@ -8836,6 +8833,7 @@ V
 [?]
 [?]
 [?]
+^
 [?]
 [?]
 [?]
@@ -8873,9 +8871,8 @@ V
 [?]
 [?]
 [?]
-[?]
-[?]
-[?]
+<
+> 
 [?]
 [?]
 [?]
@@ -9185,166 +9182,166 @@ V
 [?]
 [?]
 [?]
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-[?]
-[?]
-[?]
-[?]
-[?]
-[?]
-[?]
-[?]
-[?]
-[?]
-[?]
-[?]
-[?]
-[?]
-[?]
-[?]
-[?]
-[?]
-[?]
-[?]
-
+1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+(1)
+(2)
+(3)
+(4)
+(5)
+(6)
+(7)
+(8)
+(9)
+(10)
+(11)
+(12)
+(13)
+(14)
+(15)
+(16)
+(17)
+(18)
+(19)
+(20)
+1.
+2.
+3.
+4.
+5.
+6.
+7.
+8.
+9.
+10.
+11.
+12.
+13.
+14.
+15.
+16.
+17.
+18.
+19.
+20.
+(a)
+(b)
+(c)
+(d)
+(e)
+(f)
+(g)
+(h)
+(i)
+(j)
+(k)
+(l)
+(m)
+(n)
+(o)
+(p)
+(q)
+(r)
+(s)
+(t)
+(u)
+(v)
+(w)
+(x)
+(y)
+(z)
+A
+B
+C
+D
+E
+F
+G
+H
+I
+J
+K
+L
+M
+N
+O
+P
+Q
+R
+S
+T
+U
+V
+W
+X
+Y
+Z
+a
+b
+c
+d
+e
+f
+g
+h
+i
+j
+k
+l
+m
+n
+o
+p
+q
+r
+s
+t
+u
+v
+w
+x
+y
+z
+0
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+0
 -
 -
 |
@@ -9712,7 +9709,7 @@ O
 
 
 
-
+#
 
 
 [?]
@@ -9906,6 +9903,7 @@ O
 
 
 
+*
 
 
 
@@ -9944,8 +9942,7 @@ O
 
 
 
-
-
+|
 
 
 
@@ -9955,7 +9952,7 @@ O
 [?]
 [?]
 
-
+!
 
 
 
@@ -10087,10 +10084,10 @@ O
 [?]
 [?]
 [?]
+[
 [?]
-[?]
-[?]
-[?]
+<
+> 
 [?]
 [?]
 [?]
@@ -10500,6 +10497,8 @@ y
 
 
 
+{
+} 
 
 
 
@@ -10739,6 +10738,9 @@ y
 
 
 
+::=
+==
+===
 
 
 
@@ -11228,27 +11230,22 @@ y
 
 
 
+L
+l
+L
+P
+R
+a
+t
+H
+h
+K
+k
+Z
+z
 
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+M
+A
 
 
 
@@ -12754,21 +12751,21 @@ H
 [?]
 [?]
 [?]
-[?]
-[?]
-[?]
-[?]
-[?]
-[?]
-[?]
-[?]
-[?]
-[?]
-[?]
-[?]
-[?]
-[?]
-[?]
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
 (g)
 (n)
 (d)
@@ -12850,21 +12847,21 @@ KIS
 (Zi) 
 (Xie) 
 (Ye) 
-[?]
-[?]
-[?]
-[?]
-[?]
-[?]
-[?]
-[?]
-[?]
-[?]
-[?]
-[?]
-[?]
-[?]
-[?]
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
 1M
 2M
 3M
@@ -12877,10 +12874,10 @@ KIS
 10M
 11M
 12M
-[?]
-[?]
-[?]
-[?]
+Hg
+erg
+eV
+LTD
 a
 i
 u
@@ -13042,16 +13039,16 @@ watt
 22h
 23h
 24h
-HPA
+hPa
 da
 AU
 bar
 oV
 pc
-[?]
-[?]
-[?]
-[?]
+dm
+dm^2
+dm^3
+IU
 Heisei
 Syouwa
 Taisyou
@@ -13092,7 +13089,7 @@ mm^2
 cm^2
 m^2
 km^2
-mm^4
+mm^3
 cm^3
 m^3
 km^3
@@ -13184,7 +13181,7 @@ Wb
 29d
 30d
 31d
-
+gal
 
 
 
@@ -19841,7 +19838,7 @@ Wb
 [?]
 [?]
 
-[?] 
+Yi 
 Ding 
 Kao 
 Qi 
diff --git a/lib/pure/unidecode/unidecode.nim b/lib/pure/unidecode/unidecode.nim
index 9d8843f06..e0b8d3946 100644
--- a/lib/pure/unidecode/unidecode.nim
+++ b/lib/pure/unidecode/unidecode.nim
@@ -22,14 +22,14 @@
 ## strictly one-way transformation. However a human reader will probably
 ## still be able to guess what original string was meant from the context.
 ##
-## This module needs the data file "unidecode.dat" to work: You can either
-## ship this file with your application and initialize this module with the
-## `loadUnidecodeTable` proc or you can define the ``embedUnidecodeTable``
-## symbol to embed the file as a resource into your application.
+## This module needs the data file "unidecode.dat" to work: This file is
+## embedded as a resource into your application by default. But you an also
+## define the symbol ``--define:noUnidecodeTable`` during compile time and
+## use the `loadUnidecodeTable` proc to initialize this module.
 
 import unicode
 
-when defined(embedUnidecodeTable):
+when not defined(noUnidecodeTable):
   import strutils
 
   const translationTable = splitLines(slurp"unidecode/unidecode.dat")
@@ -38,11 +38,11 @@ else:
   var translationTable: seq[string]
 
 proc loadUnidecodeTable*(datafile = "unidecode.dat") =
-  ## loads the datafile that `unidecode` to work. Unless this module is
-  ## compiled with the ``embedUnidecodeTable`` symbol defined, this needs
-  ## to be called by the main thread before any thread can make a call
-  ## to `unidecode`.
-  when not defined(embedUnidecodeTable):
+  ## loads the datafile that `unidecode` to work. This is only required if
+  ## the module was compiled with the ``--define:noUnidecodeTable`` switch.
+  ## This needs to be called by the main thread before any thread can make a
+  ## call to `unidecode`.
+  when defined(noUnidecodeTable):
     newSeq(translationTable, 0xffff)
     var i = 0
     for line in lines(datafile):
@@ -61,7 +61,6 @@ proc unidecode*(s: string): string =
   ##
   ## Results in: "Bei Jing"
   ##
-  assert(not isNil(translationTable))
   result = ""
   for r in runes(s):
     var c = int(r)
@@ -69,6 +68,6 @@ proc unidecode*(s: string): string =
     elif c <% translationTable.len: add(result, translationTable[c-128])
 
 when isMainModule:
-  loadUnidecodeTable("lib/pure/unidecode/unidecode.dat")
-  assert unidecode("Äußerst") == "Ausserst"
-
+  #loadUnidecodeTable("lib/pure/unidecode/unidecode.dat")
+  doAssert unidecode("Äußerst") == "Ausserst"
+  doAssert unidecode("北京") == "Bei Jing "
diff --git a/lib/pure/xmldom.nim b/lib/pure/xmldom.nim
index 1a9e4ae26..82f88a996 100644
--- a/lib/pure/xmldom.nim
+++ b/lib/pure/xmldom.nim
@@ -172,34 +172,30 @@ proc documentElement*(doc: PDocument): PElement =
 proc findNodes(nl: PNode, name: string): seq[PNode] =
   # Made for getElementsByTagName
   var r: seq[PNode] = @[]
-  if isNil(nl.childNodes): return @[]
-  if nl.childNodes.len() == 0: return @[]
+  if nl.childNodes.len == 0: return @[]
 
   for i in items(nl.childNodes):
     if i.fNodeType == ElementNode:
       if i.fNodeName == name or name == "*":
         r.add(i)
 
-      if not isNil(i.childNodes):
-        if i.childNodes.len() != 0:
-          r.add(findNodes(i, name))
+      if i.childNodes.len() != 0:
+        r.add(findNodes(i, name))
 
   return r
 
 proc findNodesNS(nl: PNode, namespaceURI: string, localName: string): seq[PNode] =
   # Made for getElementsByTagNameNS
   var r: seq[PNode] = @[]
-  if isNil(nl.childNodes): return @[]
-  if nl.childNodes.len() == 0: return @[]
+  if nl.childNodes.len == 0: return @[]
 
   for i in items(nl.childNodes):
     if i.fNodeType == ElementNode:
       if (i.fNamespaceURI == namespaceURI or namespaceURI == "*") and (i.fLocalName == localName or localName == "*"):
         r.add(i)
 
-      if not isNil(i.childNodes):
-        if i.childNodes.len() != 0:
-          r.add(findNodesNS(i, namespaceURI, localName))
+      if i.childNodes.len != 0:
+        r.add(findNodesNS(i, namespaceURI, localName))
 
   return r
 
@@ -233,8 +229,8 @@ proc createAttributeNS*(doc: PDocument, namespaceURI: string, qualifiedName: str
   # Exceptions
   if qualifiedName.contains(':'):
     let qfnamespaces = qualifiedName.toLowerAscii().split(':')
-    if isNil(namespaceURI):
-      raise newException(ENamespaceErr, "When qualifiedName contains a prefix namespaceURI cannot be nil")
+    if namespaceURI.len == 0:
+      raise newException(ENamespaceErr, "When qualifiedName contains a prefix namespaceURI cannot be empty")
     elif qfnamespaces[0] == "xml" and
         namespaceURI != "http://www.w3.org/XML/1998/namespace" and
         qfnamespaces[1] notin stdattrnames:
@@ -312,8 +308,8 @@ proc createElementNS*(doc: PDocument, namespaceURI: string, qualifiedName: strin
   ## Creates an element of the given qualified name and namespace URI.
   if qualifiedName.contains(':'):
     let qfnamespaces = qualifiedName.toLowerAscii().split(':')
-    if isNil(namespaceURI):
-      raise newException(ENamespaceErr, "When qualifiedName contains a prefix namespaceURI cannot be nil")
+    if namespaceURI.len == 0:
+      raise newException(ENamespaceErr, "When qualifiedName contains a prefix namespaceURI cannot be empty")
     elif qfnamespaces[0] == "xml" and
         namespaceURI != "http://www.w3.org/XML/1998/namespace" and
         qfnamespaces[1] notin stdattrnames:
@@ -453,7 +449,7 @@ proc importNode*(doc: PDocument, importedNode: PNode, deep: bool): PNode =
 proc firstChild*(n: PNode): PNode =
   ## Returns this node's first child
 
-  if not isNil(n.childNodes) and n.childNodes.len() > 0:
+  if n.childNodes.len > 0:
     return n.childNodes[0]
   else:
     return nil
@@ -461,8 +457,8 @@ proc firstChild*(n: PNode): PNode =
 proc lastChild*(n: PNode): PNode =
   ## Returns this node's last child
 
-  if not isNil(n.childNodes) and n.childNodes.len() > 0:
-    return n.childNodes[n.childNodes.len() - 1]
+  if n.childNodes.len > 0:
+    return n.childNodes[n.childNodes.len - 1]
   else:
     return nil
 
@@ -482,7 +478,7 @@ proc `namespaceURI=`*(n: PNode, value: string) =
 proc nextSibling*(n: PNode): PNode =
   ## Returns the next sibling of this node
 
-  if isNil(n.fParentNode) or isNil(n.fParentNode.childNodes):
+  if isNil(n.fParentNode):
     return nil
   var nLow: int = low(n.fParentNode.childNodes)
   var nHigh: int = high(n.fParentNode.childNodes)
@@ -514,7 +510,7 @@ proc parentNode*(n: PNode): PNode =
 proc previousSibling*(n: PNode): PNode =
   ## Returns the previous sibling of this node
 
-  if isNil(n.fParentNode) or isNil(n.fParentNode.childNodes):
+  if isNil(n.fParentNode):
     return nil
   var nLow: int = low(n.fParentNode.childNodes)
   var nHigh: int = high(n.fParentNode.childNodes)
@@ -531,8 +527,8 @@ proc `prefix=`*(n: PNode, value: string) =
   if illegalChars in value:
     raise newException(EInvalidCharacterErr, "Invalid character")
 
-  if isNil(n.fNamespaceURI):
-    raise newException(ENamespaceErr, "namespaceURI cannot be nil")
+  if n.fNamespaceURI.len == 0:
+    raise newException(ENamespaceErr, "namespaceURI cannot be empty")
   elif value.toLowerAscii() == "xml" and n.fNamespaceURI != "http://www.w3.org/XML/1998/namespace":
     raise newException(ENamespaceErr,
       "When the namespace prefix is \"xml\" namespaceURI has to be \"http://www.w3.org/XML/1998/namespace\"")
@@ -557,10 +553,9 @@ proc appendChild*(n: PNode, newChild: PNode) =
   ## If the newChild is already in the tree, it is first removed.
 
   # Check if n contains newChild
-  if not isNil(n.childNodes):
-    for i in low(n.childNodes)..high(n.childNodes):
-      if n.childNodes[i] == newChild:
-        raise newException(EHierarchyRequestErr, "The node to append is already in this nodes children.")
+  for i in low(n.childNodes)..high(n.childNodes):
+    if n.childNodes[i] == newChild:
+      raise newException(EHierarchyRequestErr, "The node to append is already in this nodes children.")
 
   # Check if newChild is from this nodes document
   if n.fOwnerDocument != newChild.fOwnerDocument:
@@ -572,7 +567,8 @@ proc appendChild*(n: PNode, newChild: PNode) =
   if n.nodeType in childlessObjects:
     raise newException(ENoModificationAllowedErr, "Cannot append children to a childless node")
 
-  if isNil(n.childNodes): n.childNodes = @[]
+  when not defined(nimNoNilSeqs):
+    if isNil(n.childNodes): n.childNodes = @[]
 
   newChild.fParentNode = n
   for i in low(n.childNodes)..high(n.childNodes):
@@ -597,10 +593,10 @@ proc cloneNode*(n: PNode, deep: bool): PNode =
     newNode = PElement(n)
     # Import the childNodes
     var tmp: seq[PNode] = n.childNodes
-    n.childNodes = @[]
-    if deep and not isNil(tmp):
-      for i in low(tmp.len())..high(tmp.len()):
-        n.childNodes.add(cloneNode(tmp[i], deep))
+    newNode.childNodes = @[]
+    if deep:
+      for i in low(n.childNodes)..high(n.childNodes):
+        newNode.childNodes.add(cloneNode(n.childNodes[i], deep))
     return newNode
   else:
     var newNode: PNode
@@ -610,11 +606,11 @@ proc cloneNode*(n: PNode, deep: bool): PNode =
 
 proc hasAttributes*(n: PNode): bool =
   ## Returns whether this node (if it is an element) has any attributes.
-  return not isNil(n.attributes) and n.attributes.len() > 0
+  return n.attributes.len > 0
 
 proc hasChildNodes*(n: PNode): bool =
   ## Returns whether this node has any children.
-  return not isNil(n.childNodes) and n.childNodes.len() > 0
+  return n.childNodes.len > 0
 
 proc insertBefore*(n: PNode, newChild: PNode, refChild: PNode): PNode =
   ## Inserts the node ``newChild`` before the existing child node ``refChild``.
@@ -624,9 +620,6 @@ proc insertBefore*(n: PNode, newChild: PNode, refChild: PNode): PNode =
   if n.fOwnerDocument != newChild.fOwnerDocument:
     raise newException(EWrongDocumentErr, "This node belongs to a different document, use importNode.")
 
-  if isNil(n.childNodes):
-    n.childNodes = @[]
-
   for i in low(n.childNodes)..high(n.childNodes):
     if n.childNodes[i] == refChild:
       n.childNodes.insert(newChild, i - 1)
@@ -641,7 +634,7 @@ proc isSupported*(n: PNode, feature: string, version: string): bool =
 
 proc isEmpty(s: string): bool =
 
-  if isNil(s) or s == "":
+  if s == "":
     return true
   for i in items(s):
     if i != ' ':
@@ -655,7 +648,7 @@ proc normalize*(n: PNode) =
 
   var newChildNodes: seq[PNode] = @[]
   while true:
-    if isNil(n.childNodes) or i >= n.childNodes.len:
+    if i >= n.childNodes.len:
       break
     if n.childNodes[i].nodeType == TextNode:
 
@@ -679,12 +672,11 @@ proc normalize*(n: PNode) =
 
 proc removeChild*(n: PNode, oldChild: PNode): PNode =
   ## Removes the child node indicated by ``oldChild`` from the list of children, and returns it.
-  if not isNil(n.childNodes):
-    for i in low(n.childNodes)..high(n.childNodes):
-      if n.childNodes[i] == oldChild:
-        result = n.childNodes[i]
-        n.childNodes.delete(i)
-        return
+  for i in low(n.childNodes)..high(n.childNodes):
+    if n.childNodes[i] == oldChild:
+      result = n.childNodes[i]
+      n.childNodes.delete(i)
+      return
 
   raise newException(ENotFoundErr, "Node not found")
 
@@ -695,12 +687,11 @@ proc replaceChild*(n: PNode, newChild: PNode, oldChild: PNode): PNode =
   if n.fOwnerDocument != newChild.fOwnerDocument:
     raise newException(EWrongDocumentErr, "This node belongs to a different document, use importNode.")
 
-  if not isNil(n.childNodes):
-    for i in low(n.childNodes)..high(n.childNodes):
-      if n.childNodes[i] == oldChild:
-        result = n.childNodes[i]
-        n.childNodes[i] = newChild
-        return
+  for i in low(n.childNodes)..high(n.childNodes):
+    if n.childNodes[i] == oldChild:
+      result = n.childNodes[i]
+      n.childNodes[i] = newChild
+      return
 
   raise newException(ENotFoundErr, "Node not found")
 
@@ -764,11 +755,10 @@ proc removeNamedItemNS*(nList: var seq[PNode], namespaceURI: string, localName:
 proc setNamedItem*(nList: var seq[PNode], arg: PNode): PNode =
   ## Adds ``arg`` as a ``Node`` to the ``NList``
   ## If a node with the same name is already present in this map, it is replaced by the new one.
-  if not isNil(nList):
-    if nList.len() > 0:
-      #Check if newChild is from this nodes document
-      if nList[0].fOwnerDocument != arg.fOwnerDocument:
-        raise newException(EWrongDocumentErr, "This node belongs to a different document, use importNode.")
+  if nList.len > 0:
+    #Check if newChild is from this nodes document
+    if nList[0].fOwnerDocument != arg.fOwnerDocument:
+      raise newException(EWrongDocumentErr, "This node belongs to a different document, use importNode.")
   #Exceptions End
 
   var item: PNode = nList.getNamedItem(arg.nodeName())
@@ -788,11 +778,10 @@ proc setNamedItem*(nList: var seq[PNode], arg: PNode): PNode =
 proc setNamedItem*(nList: var seq[PAttr], arg: PAttr): PAttr =
   ## Adds ``arg`` as a ``Node`` to the ``NList``
   ## If a node with the same name is already present in this map, it is replaced by the new one.
-  if not isNil(nList):
-    if nList.len() > 0:
-      # Check if newChild is from this nodes document
-      if nList[0].fOwnerDocument != arg.fOwnerDocument:
-        raise newException(EWrongDocumentErr, "This node belongs to a different document, use importNode.")
+  if nList.len > 0:
+    # Check if newChild is from this nodes document
+    if nList[0].fOwnerDocument != arg.fOwnerDocument:
+      raise newException(EWrongDocumentErr, "This node belongs to a different document, use importNode.")
 
   if not isNil(arg.fOwnerElement):
     raise newException(EInuseAttributeErr, "This attribute is in use by another element, use cloneNode")
@@ -814,11 +803,10 @@ proc setNamedItem*(nList: var seq[PAttr], arg: PAttr): PAttr =
 
 proc setNamedItemNS*(nList: var seq[PNode], arg: PNode): PNode =
   ## Adds a node using its ``namespaceURI`` and ``localName``
-  if not isNil(nList):
-    if nList.len() > 0:
-      # Check if newChild is from this nodes document
-      if nList[0].fOwnerDocument != arg.fOwnerDocument:
-        raise newException(EWrongDocumentErr, "This node belongs to a different document, use importNode.")
+  if nList.len > 0:
+    # Check if newChild is from this nodes document
+    if nList[0].fOwnerDocument != arg.fOwnerDocument:
+      raise newException(EWrongDocumentErr, "This node belongs to a different document, use importNode.")
   #Exceptions end
 
   var item: PNode = nList.getNamedItemNS(arg.namespaceURI(), arg.localName())
@@ -837,11 +825,10 @@ proc setNamedItemNS*(nList: var seq[PNode], arg: PNode): PNode =
 
 proc setNamedItemNS*(nList: var seq[PAttr], arg: PAttr): PAttr =
   ## Adds a node using its ``namespaceURI`` and ``localName``
-  if not isNil(nList):
-    if nList.len() > 0:
-      # Check if newChild is from this nodes document
-      if nList[0].fOwnerDocument != arg.fOwnerDocument:
-        raise newException(EWrongDocumentErr, "This node belongs to a different document, use importNode.")
+  if nList.len > 0:
+    # Check if newChild is from this nodes document
+    if nList[0].fOwnerDocument != arg.fOwnerDocument:
+      raise newException(EWrongDocumentErr, "This node belongs to a different document, use importNode.")
 
   if not isNil(arg.fOwnerElement):
     raise newException(EInuseAttributeErr, "This attribute is in use by another element, use cloneNode")
@@ -868,17 +855,14 @@ proc setNamedItemNS*(nList: var seq[PAttr], arg: PAttr): PAttr =
 # Attributes
 proc name*(a: PAttr): string =
   ## Returns the name of the Attribute
-
   return a.fName
 
 proc specified*(a: PAttr): bool =
   ## Specifies whether this attribute was specified in the original document
-
   return a.fSpecified
 
 proc ownerElement*(a: PAttr): PElement =
   ## Returns this Attributes owner element
-
   return a.fOwnerElement
 
 # Element
@@ -886,14 +870,11 @@ proc ownerElement*(a: PAttr): PElement =
 
 proc tagName*(el: PElement): string =
   ## Returns the Element Tag Name
-
   return el.fTagName
 
 # Procedures
 proc getAttribute*(el: PNode, name: string): string =
   ## Retrieves an attribute value by ``name``
-  if isNil(el.attributes):
-    return ""
   var attribute = el.attributes.getNamedItem(name)
   if not isNil(attribute):
     return attribute.value
@@ -902,8 +883,6 @@ proc getAttribute*(el: PNode, name: string): string =
 
 proc getAttributeNS*(el: PNode, namespaceURI: string, localName: string): string =
   ## Retrieves an attribute value by ``localName`` and ``namespaceURI``
-  if isNil(el.attributes):
-    return ""
   var attribute = el.attributes.getNamedItemNS(namespaceURI, localName)
   if not isNil(attribute):
     return attribute.value
@@ -913,14 +892,10 @@ proc getAttributeNS*(el: PNode, namespaceURI: string, localName: string): string
 proc getAttributeNode*(el: PElement, name: string): PAttr =
   ## Retrieves an attribute node by ``name``
   ## To retrieve an attribute node by qualified name and namespace URI, use the `getAttributeNodeNS` method
-  if isNil(el.attributes):
-    return nil
   return el.attributes.getNamedItem(name)
 
 proc getAttributeNodeNS*(el: PElement, namespaceURI: string, localName: string): PAttr =
   ## Retrieves an `Attr` node by ``localName`` and ``namespaceURI``
-  if isNil(el.attributes):
-    return nil
   return el.attributes.getNamedItemNS(namespaceURI, localName)
 
 proc getElementsByTagName*(el: PElement, name: string): seq[PNode] =
@@ -938,41 +913,34 @@ proc getElementsByTagNameNS*(el: PElement, namespaceURI: string, localName: stri
 proc hasAttribute*(el: PElement, name: string): bool =
   ## Returns ``true`` when an attribute with a given ``name`` is specified
   ## on this element , ``false`` otherwise.
-  if isNil(el.attributes):
-    return false
   return not isNil(el.attributes.getNamedItem(name))
 
 proc hasAttributeNS*(el: PElement, namespaceURI: string, localName: string): bool =
   ## Returns ``true`` when an attribute with a given ``localName`` and
   ## ``namespaceURI`` is specified on this element , ``false`` otherwise
-  if isNil(el.attributes):
-    return false
   return not isNil(el.attributes.getNamedItemNS(namespaceURI, localName))
 
 proc removeAttribute*(el: PElement, name: string) =
   ## Removes an attribute by ``name``
-  if not isNil(el.attributes):
-    for i in low(el.attributes)..high(el.attributes):
-      if el.attributes[i].fName == name:
-        el.attributes.delete(i)
+  for i in low(el.attributes)..high(el.attributes):
+    if el.attributes[i].fName == name:
+      el.attributes.delete(i)
 
 proc removeAttributeNS*(el: PElement, namespaceURI: string, localName: string) =
   ## Removes an attribute by ``localName`` and ``namespaceURI``
-  if not isNil(el.attributes):
-    for i in low(el.attributes)..high(el.attributes):
-      if el.attributes[i].fNamespaceURI == namespaceURI and
-          el.attributes[i].fLocalName == localName:
-        el.attributes.delete(i)
+  for i in low(el.attributes)..high(el.attributes):
+    if el.attributes[i].fNamespaceURI == namespaceURI and
+        el.attributes[i].fLocalName == localName:
+      el.attributes.delete(i)
 
 proc removeAttributeNode*(el: PElement, oldAttr: PAttr): PAttr =
   ## Removes the specified attribute node
   ## If the attribute node cannot be found raises ``ENotFoundErr``
-  if not isNil(el.attributes):
-    for i in low(el.attributes)..high(el.attributes):
-      if el.attributes[i] == oldAttr:
-        result = el.attributes[i]
-        el.attributes.delete(i)
-        return
+  for i in low(el.attributes)..high(el.attributes):
+    if el.attributes[i] == oldAttr:
+      result = el.attributes[i]
+      el.attributes.delete(i)
+      return
 
   raise newException(ENotFoundErr, "oldAttr is not a member of el's Attributes")
 
@@ -991,7 +959,6 @@ proc setAttributeNode*(el: PElement, newAttr: PAttr): PAttr =
       "This attribute is in use by another element, use cloneNode")
   # Exceptions end
 
-  if isNil(el.attributes): el.attributes = @[]
   return el.attributes.setNamedItem(newAttr)
 
 proc setAttributeNodeNS*(el: PElement, newAttr: PAttr): PAttr =
@@ -1009,7 +976,6 @@ proc setAttributeNodeNS*(el: PElement, newAttr: PAttr): PAttr =
       "This attribute is in use by another element, use cloneNode")
   # Exceptions end
 
-  if isNil(el.attributes): el.attributes = @[]
   return el.attributes.setNamedItemNS(newAttr)
 
 proc setAttribute*(el: PElement, name: string, value: string) =
@@ -1057,9 +1023,9 @@ proc splitData*(textNode: PText, offset: int): PText =
 
   var left: string = textNode.data.substr(0, offset)
   textNode.data = left
-  var right: string = textNode.data.substr(offset, textNode.data.len())
+  var right: string = textNode.data.substr(offset, textNode.data.len)
 
-  if not isNil(textNode.fParentNode) and not isNil(textNode.fParentNode.childNodes):
+  if not isNil(textNode.fParentNode) and textNode.fParentNode.childNodes.len > 0:
     for i in low(textNode.fParentNode.childNodes)..high(textNode.fParentNode.childNodes):
       if textNode.fParentNode.childNodes[i] == textNode:
         var newNode: PText = textNode.fOwnerDocument.createTextNode(right)
@@ -1098,11 +1064,10 @@ proc escapeXml*(s: string): string =
 
 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 & "=\"" & escapeXml(i.value) & "\"")
+  for i in items(n.attributes):
+    result.add(" " & i.name & "=\"" & escapeXml(i.value) & "\"")
 
-  if isNil(n.childNodes) or n.childNodes.len() == 0:
+  if n.childNodes.len == 0:
     result.add("/>") # No idea why this doesn't need a \n :O
   else:
     # End the beginning of this tag
@@ -1134,3 +1099,4 @@ proc `$`*(doc: PDocument): string =
   ## Converts a PDocument object into a string representation of it's XML
   result = "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n"
   result.add(nodeToXml(doc.documentElement))
+  
\ No newline at end of file
diff --git a/lib/system.nim b/lib/system.nim
index d61924a5b..ef6138ad1 100644
--- a/lib/system.nim
+++ b/lib/system.nim
@@ -211,6 +211,7 @@ proc new*(T: typedesc): auto =
   new(r)
   return r
 
+const ThisIsSystem = true
 
 proc internalNew*[T](a: var ref T) {.magic: "New", noSideEffect.}
   ## leaked implementation detail. Do not use.
@@ -229,6 +230,17 @@ proc reset*[T](obj: var T) {.magic: "Reset", noSideEffect.}
   ## resets an object `obj` to its initial (binary zero) value. This needs to
   ## be called before any possible `object branch transition`:idx:.
 
+when defined(nimNewRuntime):
+  proc wasMoved*[T](obj: var T) {.magic: "WasMoved", noSideEffect.} =
+    ## resets an object `obj` to its initial (binary zero) value to signify
+    ## it was "moved" and to signify its destructor should do nothing and
+    ## ideally be optimized away.
+    discard
+
+  proc move*[T](x: var T): T {.magic: "Move", noSideEffect.} =
+    result = x
+    wasMoved(x)
+
 type
   range*{.magic: "Range".}[T] ## Generic type to construct range types.
   array*{.magic: "Array".}[I, T]  ## Generic type to construct
@@ -301,6 +313,12 @@ when defined(nimArrIdx):
   proc `[]=`*[I: Ordinal;T,S](a: T; i: I;
     x: S) {.noSideEffect, magic: "ArrPut".}
   proc `=`*[T](dest: var T; src: T) {.noSideEffect, magic: "Asgn".}
+
+  proc arrGet[I: Ordinal;T](a: T; i: I): T {.
+    noSideEffect, magic: "ArrGet".}
+  proc arrPut[I: Ordinal;T,S](a: T; i: I;
+    x: S) {.noSideEffect, magic: "ArrPut".}
+
   when defined(nimNewRuntime):
     proc `=destroy`*[T](x: var T) {.inline, magic: "Asgn".} =
       ## generic `destructor`:idx: implementation that can be overriden.
@@ -413,7 +431,7 @@ include "system/inclrtl"
 const NoFakeVars* = defined(nimscript) ## true if the backend doesn't support \
   ## "fake variables" like 'var EBADF {.importc.}: cint'.
 
-when not defined(JS):
+when not defined(JS) and not defined(gcDestructors):
   type
     TGenericSeq {.compilerproc, pure, inheritable.} = object
       len, reserved: int
@@ -426,8 +444,9 @@ when not defined(JS):
     NimString = ptr NimStringDesc
 
 when not defined(JS) and not defined(nimscript):
-  template space(s: PGenericSeq): int {.dirty.} =
-    s.reserved and not (seqShallowFlag or strlitFlag)
+  when not defined(gcDestructors):
+    template space(s: PGenericSeq): int {.dirty.} =
+      s.reserved and not (seqShallowFlag or strlitFlag)
   include "system/hti"
 
 type
@@ -692,7 +711,8 @@ proc newSeqOfCap*[T](cap: Natural): seq[T] {.
   ## ``cap``.
   discard
 
-when not defined(JS):
+when not defined(JS) and not defined(gcDestructors):
+  # XXX enable this for --gc:destructors
   proc newSeqUninitialized*[T: SomeNumber](len: Natural): seq[T] =
     ## creates a new sequence of type ``seq[T]`` with length ``len``.
     ##
@@ -1481,11 +1501,17 @@ const hasAlloc = (hostOS != "standalone" or not defined(nogc)) and not defined(n
 
 when not defined(JS) and not defined(nimscript) and hostOS != "standalone":
   include "system/cgprocs"
-when not defined(JS) and not defined(nimscript) and hasAlloc:
+when not defined(JS) and not defined(nimscript) and hasAlloc and not defined(gcDestructors):
   proc addChar(s: NimString, c: char): NimString {.compilerProc, benign.}
 
-proc add *[T](x: var seq[T], y: T) {.magic: "AppendSeqElem", noSideEffect.}
-proc add *[T](x: var seq[T], y: openArray[T]) {.noSideEffect.} =
+when defined(gcDestructors):
+  proc add*[T](x: var seq[T], y: sink T) {.magic: "AppendSeqElem", noSideEffect.} =
+    let xl = x.len
+    setLen(x, xl + 1)
+    x[xl] = y
+else:
+  proc add*[T](x: var seq[T], y: T) {.magic: "AppendSeqElem", noSideEffect.}
+proc add*[T](x: var seq[T], y: openArray[T]) {.noSideEffect.} =
   ## Generic proc for adding a data item `y` to a container `x`.
   ## For containers that have an order, `add` means *append*. New generic
   ## containers should also call their adding proc `add` for consistency.
@@ -1526,7 +1552,7 @@ proc delete*[T](x: var seq[T], i: Natural) {.noSideEffect.} =
     defaultImpl()
   else:
     when defined(js):
-      {.emit: "`x`[`x`_Idx].splice(`i`, 1);".}
+      {.emit: "`x`.splice(`i`, 1);".}
     else:
       defaultImpl()
 
@@ -1548,7 +1574,7 @@ proc insert*[T](x: var seq[T], item: T, i = 0.Natural) {.noSideEffect.} =
   else:
     when defined(js):
       var it : T
-      {.emit: "`x`[`x`_Idx].splice(`i`, 0, `it`);".}
+      {.emit: "`x`.splice(`i`, 0, `it`);".}
     else:
       defaultImpl()
   x[i] = item
@@ -1681,17 +1707,6 @@ proc addQuitProc*(QuitProc: proc() {.noconv.}) {.
 # In case of an unhandled exeption the exit handlers should
 # not be called explicitly! The user may decide to do this manually though.
 
-proc substr*(s: string, first = 0): string {.
-  magic: "CopyStr", importc: "copyStr", noSideEffect.}
-proc substr*(s: string, first, last: int): string {.
-  magic: "CopyStrLast", importc: "copyStrLast", noSideEffect.}
-  ## copies a slice of `s` into a new string and returns this new
-  ## string. The bounds `first` and `last` denote the indices of
-  ## the first and last characters that shall be copied. If ``last``
-  ## is omitted, it is treated as ``high(s)``. If ``last >= s.len``, ``s.len``
-  ## is used instead: This means ``substr`` can also be used to `cut`:idx:
-  ## or `limit`:idx: a string's length.
-
 when not defined(nimscript) and not defined(JS):
   proc zeroMem*(p: pointer, size: Natural) {.inline, benign.}
     ## overwrites the contents of the memory at ``p`` with the value 0.
@@ -2180,10 +2195,17 @@ iterator items*[T](a: set[T]): T {.inline.} =
 
 iterator items*(a: cstring): char {.inline.} =
   ## iterates over each item of `a`.
-  var i = 0
-  while a[i] != '\0':
-    yield a[i]
-    inc(i)
+  when defined(js):
+    var i = 0
+    var L = len(a)
+    while i < L:
+      yield a[i]
+      inc(i)
+  else:
+    var i = 0
+    while a[i] != '\0':
+      yield a[i]
+      inc(i)
 
 iterator mitems*(a: var cstring): var char {.inline.} =
   ## iterates over each item of `a` so that you can modify the yielded value.
@@ -2283,9 +2305,18 @@ iterator mpairs*(a: var cstring): tuple[key: int, val: var char] {.inline.} =
     inc(i)
 
 
-proc isNil*[T](x: seq[T]): bool {.noSideEffect, magic: "IsNil", deprecated.}
+when defined(nimNoNilSeqs2):
+  when not compileOption("nilseqs"):
+    {.pragma: nilError, error.}
+  else:
+    {.pragma: nilError.}
+else:
+  {.pragma: nilError.}
+
+proc isNil*[T](x: seq[T]): bool {.noSideEffect, magic: "IsNil", nilError.}
 proc isNil*[T](x: ref T): bool {.noSideEffect, magic: "IsNil".}
-proc isNil*(x: string): bool {.noSideEffect, magic: "IsNil", deprecated.}
+proc isNil*(x: string): bool {.noSideEffect, magic: "IsNil", nilError.}
+
 proc isNil*[T](x: ptr T): bool {.noSideEffect, magic: "IsNil".}
 proc isNil*(x: pointer): bool {.noSideEffect, magic: "IsNil".}
 proc isNil*(x: cstring): bool {.noSideEffect, magic: "IsNil".}
@@ -2710,12 +2741,12 @@ type
 when defined(JS):
   proc add*(x: var string, y: cstring) {.asmNoStackFrame.} =
     asm """
-      var len = `x`[0].length-1;
+      if (`x` === null) { `x` = []; }
+      var off = `x`.length;
+      `x`.length += `y`.length;
       for (var i = 0; i < `y`.length; ++i) {
-        `x`[0][len] = `y`.charCodeAt(i);
-        ++len;
+        `x`[off+i] = `y`.charCodeAt(i);
       }
-      `x`[0][len] = 0
     """
   proc add*(x: var cstring, y: cstring) {.magic: "AppendStrStr".}
 
@@ -2820,6 +2851,58 @@ else:
     if x < 0: -x else: x
 {.pop.}
 
+when not defined(JS):
+  proc likely_proc(val: bool): bool {.importc: "likely", nodecl, nosideeffect.}
+  proc unlikely_proc(val: bool): bool {.importc: "unlikely", nodecl, nosideeffect.}
+
+template likely*(val: bool): bool =
+  ## Hints the optimizer that `val` is likely going to be true.
+  ##
+  ## You can use this template to decorate a branch condition. On certain
+  ## platforms this can help the processor predict better which branch is
+  ## going to be run. Example:
+  ##
+  ## .. code-block:: nim
+  ##   for value in inputValues:
+  ##     if likely(value <= 100):
+  ##       process(value)
+  ##     else:
+  ##       echo "Value too big!"
+  ##
+  ## On backends without branch prediction (JS and the nimscript VM), this
+  ## template will not affect code execution.
+  when nimvm:
+    val
+  else:
+    when defined(JS):
+      val
+    else:
+      likely_proc(val)
+
+template unlikely*(val: bool): bool =
+  ## Hints the optimizer that `val` is likely going to be false.
+  ##
+  ## You can use this proc to decorate a branch condition. On certain
+  ## platforms this can help the processor predict better which branch is
+  ## going to be run. Example:
+  ##
+  ## .. code-block:: nim
+  ##   for value in inputValues:
+  ##     if unlikely(value > 100):
+  ##       echo "Value too big!"
+  ##     else:
+  ##       process(value)
+  ##
+  ## On backends without branch prediction (JS and the nimscript VM), this
+  ## template will not affect code execution.
+  when nimvm:
+    val
+  else:
+    when defined(JS):
+      val
+    else:
+      unlikely_proc(val)
+
 type
   FileSeekPos* = enum ## Position relative to which seek should happen
                       # The values are ordered so that they match with stdio
@@ -2853,10 +2936,11 @@ when not defined(JS): #and not defined(nimscript):
       when declared(nimGC_setStackBottom):
         nimGC_setStackBottom(locals)
 
-    {.push profiler: off.}
-    var
-      strDesc = TNimType(size: sizeof(string), kind: tyString, flags: {ntfAcyclic})
-    {.pop.}
+    when not defined(gcDestructors):
+      {.push profiler: off.}
+      var
+        strDesc = TNimType(size: sizeof(string), kind: tyString, flags: {ntfAcyclic})
+      {.pop.}
 
 
   # ----------------- IO Part ------------------------------------------------
@@ -3043,8 +3127,8 @@ when not defined(JS): #and not defined(nimscript):
 
     proc readLine*(f: File, line: var TaintedString): bool {.tags: [ReadIOEffect],
                   benign.}
-      ## reads a line of text from the file `f` into `line`. `line` must not be
-      ## ``nil``! May throw an IO exception.
+      ## reads a line of text from the file `f` into `line`. May throw an IO
+      ## exception.
       ## A line of text may be delimited by ``LF`` or ``CRLF``. The newline
       ## character(s) are not part of the returned string. Returns ``false``
       ## if the end of the file has been reached, ``true`` otherwise. If
@@ -3242,8 +3326,14 @@ when not defined(JS): #and not defined(nimscript):
     when hasAlloc: include "system/mmdisp"
     {.pop.}
     {.push stack_trace: off, profiler:off.}
-    when hasAlloc: include "system/sysstr"
+    when hasAlloc:
+      when defined(gcDestructors):
+        include "core/strs"
+        include "core/seqs"
+      else:
+        include "system/sysstr"
     {.pop.}
+    when hasAlloc: include "system/strmantle"
 
     when hostOS != "standalone": include "system/sysio"
     when hasThreadSupport:
@@ -3288,8 +3378,9 @@ when not defined(JS): #and not defined(nimscript):
       while f.readLine(res): yield res
 
   when not defined(nimscript) and hasAlloc:
-    include "system/assign"
-    include "system/repr"
+    when not defined(gcDestructors):
+      include "system/assign"
+      include "system/repr"
 
   when hostOS != "standalone" and not defined(nimscript):
     proc getCurrentException*(): ref Exception {.compilerRtl, inl, benign.} =
@@ -3302,12 +3393,15 @@ when not defined(JS): #and not defined(nimscript):
       var e = getCurrentException()
       return if e == nil: "" else: e.msg
 
-    proc onRaise*(action: proc(e: ref Exception): bool{.closure.}) =
+    proc onRaise*(action: proc(e: ref Exception): bool{.closure.}) {.deprecated.} =
       ## can be used in a ``try`` statement to setup a Lisp-like
       ## `condition system`:idx:\: This prevents the 'raise' statement to
       ## raise an exception but instead calls ``action``.
       ## If ``action`` returns false, the exception has been handled and
       ## does not propagate further through the call stack.
+      ##
+      ## *Deprecated since version 0.18.1*: No good usages of this
+      ## feature are known.
       if not isNil(excHandler):
         excHandler.hasRaiseAction = true
         excHandler.raiseAction = action
@@ -3396,58 +3490,6 @@ proc quit*(errormsg: string, errorcode = QuitFailure) {.noReturn.} =
 {.pop.} # checks
 {.pop.} # hints
 
-when not defined(JS):
-  proc likely_proc(val: bool): bool {.importc: "likely", nodecl, nosideeffect.}
-  proc unlikely_proc(val: bool): bool {.importc: "unlikely", nodecl, nosideeffect.}
-
-template likely*(val: bool): bool =
-  ## Hints the optimizer that `val` is likely going to be true.
-  ##
-  ## You can use this template to decorate a branch condition. On certain
-  ## platforms this can help the processor predict better which branch is
-  ## going to be run. Example:
-  ##
-  ## .. code-block:: nim
-  ##   for value in inputValues:
-  ##     if likely(value <= 100):
-  ##       process(value)
-  ##     else:
-  ##       echo "Value too big!"
-  ##
-  ## On backends without branch prediction (JS and the nimscript VM), this
-  ## template will not affect code execution.
-  when nimvm:
-    val
-  else:
-    when defined(JS):
-      val
-    else:
-      likely_proc(val)
-
-template unlikely*(val: bool): bool =
-  ## Hints the optimizer that `val` is likely going to be false.
-  ##
-  ## You can use this proc to decorate a branch condition. On certain
-  ## platforms this can help the processor predict better which branch is
-  ## going to be run. Example:
-  ##
-  ## .. code-block:: nim
-  ##   for value in inputValues:
-  ##     if unlikely(value > 100):
-  ##       echo "Value too big!"
-  ##     else:
-  ##       process(value)
-  ##
-  ## On backends without branch prediction (JS and the nimscript VM), this
-  ## template will not affect code execution.
-  when nimvm:
-    val
-  else:
-    when defined(JS):
-      val
-    else:
-      unlikely_proc(val)
-
 proc `/`*(x, y: int): float {.inline, noSideEffect.} =
   ## integer division that results in a float.
   result = toFloat(x) / toFloat(y)
@@ -3500,6 +3542,9 @@ template spliceImpl(s, a, L, b: untyped): untyped =
 template `^^`(s, i: untyped): untyped =
   (when i is BackwardsIndex: s.len - int(i) else: int(i))
 
+template `[]`*(s: string; i: int): char = arrGet(s, i)
+template `[]=`*(s: string; i: int; val: char) = arrPut(s, i, val)
+
 when hasAlloc or defined(nimscript):
   proc `[]`*[T, U](s: string, x: HSlice[T, U]): string {.inline.} =
     ## slice operation for strings.
@@ -3732,6 +3777,19 @@ proc failedAssertImpl*(msg: string) {.raises: [], tags: [].} =
                                     tags: [].}
   Hide(raiseAssert)(msg)
 
+include "system/helpers" # for `lineInfoToString`
+
+template assertImpl(cond: bool, msg = "", enabled: static[bool]) =
+  const loc = $instantiationInfo(-1, true)
+  bind instantiationInfo
+  mixin failedAssertImpl
+  when enabled:
+    # for stacktrace; fixes #8928 ; Note: `fullPaths = true` is correct
+    # here, regardless of --excessiveStackTrace
+    {.line: instantiationInfo(fullPaths = true).}:
+      if not cond:
+        failedAssertImpl(loc & " `" & astToStr(cond) & "` " & msg)
+
 template assert*(cond: bool, msg = "") =
   ## Raises ``AssertionError`` with `msg` if `cond` is false. Note
   ## that ``AssertionError`` is hidden from the effect system, so it doesn't
@@ -3741,23 +3799,11 @@ template assert*(cond: bool, msg = "") =
   ## The compiler may not generate any code at all for ``assert`` if it is
   ## advised to do so through the ``-d:release`` or ``--assertions:off``
   ## `command line switches <nimc.html#command-line-switches>`_.
-  bind instantiationInfo
-  mixin failedAssertImpl
-  when compileOption("assertions"):
-    {.line.}:
-      if not cond: failedAssertImpl(astToStr(cond) & ' ' & msg)
+  assertImpl(cond, msg, compileOption("assertions"))
 
 template doAssert*(cond: bool, msg = "") =
-  ## same as `assert` but is always turned on and not affected by the
-  ## ``--assertions`` command line switch.
-  bind instantiationInfo
-  # NOTE: `true` is correct here; --excessiveStackTrace:on will control whether
-  # or not to output full paths.
-  {.line: instantiationInfo(-1, true).}:
-    if not cond:
-      raiseAssert(astToStr(cond) & ' ' &
-                  instantiationInfo(-1, false).fileName & '(' &
-                  $instantiationInfo(-1, false).line & ") " & msg)
+  ## same as ``assert`` but is always turned on regardless of ``--assertions``
+  assertImpl(cond, msg, true)
 
 iterator items*[T](a: seq[T]): T {.inline.} =
   ## iterates over each item of `a`.
@@ -3827,7 +3873,7 @@ proc shallow*(s: var string) {.noSideEffect, inline.} =
   ## marks a string `s` as `shallow`:idx:. Subsequent assignments will not
   ## perform deep copies of `s`. This is only useful for optimization
   ## purposes.
-  when not defined(JS) and not defined(nimscript):
+  when not defined(JS) and not defined(nimscript) and not defined(gcDestructors):
     var s = cast[PGenericSeq](s)
     # string literals cannot become 'shallow':
     if (s.reserved and strlitFlag) == 0:
@@ -3939,7 +3985,7 @@ proc addQuoted*[T](s: var string, x: T) =
   ##   tmp.add(", ")
   ##   tmp.addQuoted('c')
   ##   assert(tmp == """1, "string", 'c'""")
-  when T is string:
+  when T is string or T is cstring:
     s.add("\"")
     for c in x:
       # Only ASCII chars are escaped to avoid butchering
@@ -4011,7 +4057,9 @@ proc locals*(): RootObj {.magic: "Plugin", noSideEffect.} =
   ##   # -> B is 1
   discard
 
-when hasAlloc and not defined(nimscript) and not defined(JS):
+when hasAlloc and not defined(nimscript) and not defined(JS) and
+    not defined(gcDestructors):
+  # XXX how to implement 'deepCopy' is an open problem.
   proc deepCopy*[T](x: var T, y: T) {.noSideEffect, magic: "DeepCopy".} =
     ## performs a deep copy of `y` and copies it into `x`.
     ## This is also used by the code generator
@@ -4029,10 +4077,15 @@ proc procCall*(x: untyped) {.magic: "ProcCall", compileTime.} =
   ##   procCall someMethod(a, b)
   discard
 
-proc xlen*(x: string): int {.magic: "XLenStr", noSideEffect.} = discard
-proc xlen*[T](x: seq[T]): int {.magic: "XLenSeq", noSideEffect.} =
+proc xlen*(x: string): int {.magic: "XLenStr", noSideEffect,
+                             deprecated: "use len() instead".} =
+  ## **Deprecated since version 0.18.1**. Use len() instead.
+  discard
+proc xlen*[T](x: seq[T]): int {.magic: "XLenSeq", noSideEffect,
+                                deprecated: "use len() instead".} =
   ## returns the length of a sequence or a string without testing for 'nil'.
   ## This is an optimization that rarely makes sense.
+  ## **Deprecated since version 0.18.1**. Use len() instead.
   discard
 
 
@@ -4077,13 +4130,13 @@ template once*(body: untyped): untyped =
   ## re-executed on each module reload.
   ##
   ## .. code-block:: nim
-  ## proc draw(t: Triangle) =
-  ##   once:
-  ##     graphicsInit()
   ##
-  ##   line(t.p1, t.p2)
-  ##   line(t.p2, t.p3)
-  ##   line(t.p3, t.p1)
+  ##  proc draw(t: Triangle) =
+  ##    once:
+  ##      graphicsInit()
+  ##    line(t.p1, t.p2)
+  ##    line(t.p2, t.p3)
+  ##    line(t.p3, t.p1)
   ##
   var alreadyExecuted {.global.} = false
   if not alreadyExecuted:
@@ -4092,6 +4145,22 @@ template once*(body: untyped): untyped =
 
 {.pop.} #{.push warning[GcMem]: off, warning[Uninit]: off.}
 
+proc substr*(s: string, first, last: int): string =
+  let first = max(first, 0)
+  let L = max(min(last, high(s)) - first + 1, 0)
+  result = newString(L)
+  for i in 0 .. L-1:
+    result[i] = s[i+first]
+
+proc substr*(s: string, first = 0): string =
+  ## copies a slice of `s` into a new string and returns this new
+  ## string. The bounds `first` and `last` denote the indices of
+  ## the first and last characters that shall be copied. If ``last``
+  ## is omitted, it is treated as ``high(s)``. If ``last >= s.len``, ``s.len``
+  ## is used instead: This means ``substr`` can also be used to `cut`:idx:
+  ## or `limit`:idx: a string's length.
+  result = substr(s, first, high(s))
+
 when defined(nimconfig):
   include "system/nimscript"
 
diff --git a/lib/system/assign.nim b/lib/system/assign.nim
index 16b56aba7..2b74e6682 100644
--- a/lib/system/assign.nim
+++ b/lib/system/assign.nim
@@ -202,11 +202,6 @@ proc objectInit(dest: pointer, typ: PNimType) =
 
 # ---------------------- assign zero -----------------------------------------
 
-proc nimDestroyRange[T](r: T) {.compilerProc.} =
-  # internal proc used for destroying sequences and arrays
-  mixin `=destroy`
-  for i in countup(0, r.len - 1): `=destroy`(r[i])
-
 proc genericReset(dest: pointer, mt: PNimType) {.compilerProc, benign.}
 proc genericResetAux(dest: pointer, n: ptr TNimNode) =
   var d = cast[ByteAddress](dest)
diff --git a/lib/system/cgprocs.nim b/lib/system/cgprocs.nim
index 660c68116..72219c2b7 100644
--- a/lib/system/cgprocs.nim
+++ b/lib/system/cgprocs.nim
@@ -12,7 +12,6 @@
 type
   LibHandle = pointer       # private type
   ProcAddr = pointer        # library loading and loading of procs:
-{.deprecated: [TLibHandle: LibHandle, TProcAddr: ProcAddr].}
 
 proc nimLoadLibrary(path: string): LibHandle {.compilerproc.}
 proc nimUnloadLibrary(lib: LibHandle) {.compilerproc.}
diff --git a/lib/system/excpt.nim b/lib/system/excpt.nim
index f25da0ad8..7d5f5af7f 100644
--- a/lib/system/excpt.nim
+++ b/lib/system/excpt.nim
@@ -213,7 +213,7 @@ proc auxWriteStackTrace(f: PFrame; s: var seq[StackTraceEntry]) =
     inc(i)
     it = it.prev
   var last = i-1
-  if s.isNil:
+  if s.len == 0:
     s = newSeq[StackTraceEntry](i)
   else:
     last = s.len + i - 1
@@ -307,7 +307,7 @@ when hasSomeStackTrace:
     when NimStackTrace:
       auxWriteStackTrace(framePtr, s)
     else:
-      s = nil
+      s = @[]
 
   proc stackTraceAvailable(): bool =
     when NimStackTrace:
@@ -361,10 +361,10 @@ proc raiseExceptionAux(e: ref Exception) =
     else:
       when hasSomeStackTrace:
         var buf = newStringOfCap(2000)
-        if isNil(e.trace): rawWriteStackTrace(buf)
+        if e.trace.len == 0: rawWriteStackTrace(buf)
         else: add(buf, $e.trace)
         add(buf, "Error: unhandled exception: ")
-        if not isNil(e.msg): add(buf, e.msg)
+        add(buf, e.msg)
         add(buf, " [")
         add(buf, $e.name)
         add(buf, "]\n")
@@ -382,7 +382,7 @@ proc raiseExceptionAux(e: ref Exception) =
         var buf: array[0..2000, char]
         var L = 0
         add(buf, "Error: unhandled exception: ")
-        if not isNil(e.msg): add(buf, e.msg)
+        add(buf, e.msg)
         add(buf, " [")
         xadd(buf, e.name, e.name.len)
         add(buf, "]\n")
@@ -397,7 +397,7 @@ proc raiseExceptionAux(e: ref Exception) =
 proc raiseException(e: ref Exception, ename: cstring) {.compilerRtl.} =
   if e.name.isNil: e.name = ename
   when hasSomeStackTrace:
-    if e.trace.isNil:
+    if e.trace.len == 0:
       rawWriteStackTrace(e.trace)
     elif framePtr != nil:
       e.trace.add reraisedFrom(reraisedFromBegin)
@@ -427,15 +427,16 @@ proc getStackTrace(): string =
     result = "No stack traceback available\n"
 
 proc getStackTrace(e: ref Exception): string =
-  if not isNil(e) and not isNil(e.trace):
+  if not isNil(e):
     result = $e.trace
   else:
     result = ""
 
-proc getStackTraceEntries*(e: ref Exception): seq[StackTraceEntry] =
-  ## Returns the attached stack trace to the exception ``e`` as
-  ## a ``seq``. This is not yet available for the JS backend.
-  shallowCopy(result, e.trace)
+when not defined(gcDestructors):
+  proc getStackTraceEntries*(e: ref Exception): seq[StackTraceEntry] =
+    ## Returns the attached stack trace to the exception ``e`` as
+    ## a ``seq``. This is not yet available for the JS backend.
+    shallowCopy(result, e.trace)
 
 when defined(nimRequiresNimFrame):
   proc stackOverflow() {.noinline.} =
diff --git a/lib/system/gc_ms.nim b/lib/system/gc_ms.nim
index 75f9c6749..96221b175 100644
--- a/lib/system/gc_ms.nim
+++ b/lib/system/gc_ms.nim
@@ -264,12 +264,13 @@ proc forAllChildren(cell: PCell, op: WalkOp) =
     of tyRef, tyOptAsRef: # common case
       forAllChildrenAux(cellToUsr(cell), cell.typ.base, op)
     of tySequence:
-      var d = cast[ByteAddress](cellToUsr(cell))
-      var s = cast[PGenericSeq](d)
-      if s != nil:
-        for i in 0..s.len-1:
-          forAllChildrenAux(cast[pointer](d +% i *% cell.typ.base.size +%
-            GenericSeqSize), cell.typ.base, op)
+      when not defined(gcDestructors):
+        var d = cast[ByteAddress](cellToUsr(cell))
+        var s = cast[PGenericSeq](d)
+        if s != nil:
+          for i in 0..s.len-1:
+            forAllChildrenAux(cast[pointer](d +% i *% cell.typ.base.size +%
+              GenericSeqSize), cell.typ.base, op)
     else: discard
 
 proc rawNewObj(typ: PNimType, size: int, gch: var GcHeap): pointer =
@@ -310,53 +311,54 @@ proc newObjNoInit(typ: PNimType, size: int): pointer {.compilerRtl.} =
   result = rawNewObj(typ, size, gch)
   when defined(memProfiler): nimProfile(size)
 
-proc newSeq(typ: PNimType, len: int): pointer {.compilerRtl.} =
-  # `newObj` already uses locks, so no need for them here.
-  let size = addInt(mulInt(len, typ.base.size), GenericSeqSize)
-  result = newObj(typ, size)
-  cast[PGenericSeq](result).len = len
-  cast[PGenericSeq](result).reserved = len
-  when defined(memProfiler): nimProfile(size)
-
 proc newObjRC1(typ: PNimType, size: int): pointer {.compilerRtl.} =
   result = rawNewObj(typ, size, gch)
   zeroMem(result, size)
   when defined(memProfiler): nimProfile(size)
 
-proc newSeqRC1(typ: PNimType, len: int): pointer {.compilerRtl.} =
-  let size = addInt(mulInt(len, typ.base.size), GenericSeqSize)
-  result = newObj(typ, size)
-  cast[PGenericSeq](result).len = len
-  cast[PGenericSeq](result).reserved = len
-  when defined(memProfiler): nimProfile(size)
-
-proc growObj(old: pointer, newsize: int, gch: var GcHeap): pointer =
-  acquire(gch)
-  collectCT(gch, newsize + sizeof(Cell))
-  var ol = usrToCell(old)
-  sysAssert(ol.typ != nil, "growObj: 1")
-  gcAssert(ol.typ.kind in {tyString, tySequence}, "growObj: 2")
-
-  var res = cast[PCell](rawAlloc(gch.region, newsize + sizeof(Cell)))
-  var elemSize = 1
-  if ol.typ.kind != tyString: elemSize = ol.typ.base.size
-  incTypeSize ol.typ, newsize
-
-  var oldsize = cast[PGenericSeq](old).len*elemSize + GenericSeqSize
-  copyMem(res, ol, oldsize + sizeof(Cell))
-  zeroMem(cast[pointer](cast[ByteAddress](res)+% oldsize +% sizeof(Cell)),
-          newsize-oldsize)
-  sysAssert((cast[ByteAddress](res) and (MemAlign-1)) == 0, "growObj: 3")
-  when withBitvectors: incl(gch.allocated, res)
-  when useCellIds:
-    inc gch.idGenerator
-    res.id = gch.idGenerator
-  release(gch)
-  result = cellToUsr(res)
-  when defined(memProfiler): nimProfile(newsize-oldsize)
+when not defined(gcDestructors):
+  proc newSeq(typ: PNimType, len: int): pointer {.compilerRtl.} =
+    # `newObj` already uses locks, so no need for them here.
+    let size = addInt(mulInt(len, typ.base.size), GenericSeqSize)
+    result = newObj(typ, size)
+    cast[PGenericSeq](result).len = len
+    cast[PGenericSeq](result).reserved = len
+    when defined(memProfiler): nimProfile(size)
+
+  proc newSeqRC1(typ: PNimType, len: int): pointer {.compilerRtl.} =
+    let size = addInt(mulInt(len, typ.base.size), GenericSeqSize)
+    result = newObj(typ, size)
+    cast[PGenericSeq](result).len = len
+    cast[PGenericSeq](result).reserved = len
+    when defined(memProfiler): nimProfile(size)
+
+  proc growObj(old: pointer, newsize: int, gch: var GcHeap): pointer =
+    acquire(gch)
+    collectCT(gch, newsize + sizeof(Cell))
+    var ol = usrToCell(old)
+    sysAssert(ol.typ != nil, "growObj: 1")
+    gcAssert(ol.typ.kind in {tyString, tySequence}, "growObj: 2")
+
+    var res = cast[PCell](rawAlloc(gch.region, newsize + sizeof(Cell)))
+    var elemSize = 1
+    if ol.typ.kind != tyString: elemSize = ol.typ.base.size
+    incTypeSize ol.typ, newsize
+
+    var oldsize = cast[PGenericSeq](old).len*elemSize + GenericSeqSize
+    copyMem(res, ol, oldsize + sizeof(Cell))
+    zeroMem(cast[pointer](cast[ByteAddress](res)+% oldsize +% sizeof(Cell)),
+            newsize-oldsize)
+    sysAssert((cast[ByteAddress](res) and (MemAlign-1)) == 0, "growObj: 3")
+    when withBitvectors: incl(gch.allocated, res)
+    when useCellIds:
+      inc gch.idGenerator
+      res.id = gch.idGenerator
+    release(gch)
+    result = cellToUsr(res)
+    when defined(memProfiler): nimProfile(newsize-oldsize)
 
-proc growObj(old: pointer, newsize: int): pointer {.rtl.} =
-  result = growObj(old, newsize, gch)
+  proc growObj(old: pointer, newsize: int): pointer {.rtl.} =
+    result = growObj(old, newsize, gch)
 
 {.push profiler:off.}
 
diff --git a/lib/system/helpers.nim b/lib/system/helpers.nim
new file mode 100644
index 000000000..fb1218684
--- /dev/null
+++ b/lib/system/helpers.nim
@@ -0,0 +1,11 @@
+## helpers used system.nim and other modules, avoids code duplication while
+## also minimizing symbols exposed in system.nim
+#
+# TODO: move other things here that should not be exposed in system.nim
+
+proc lineInfoToString(file: string, line, column: int): string =
+  file & "(" & $line & ", " & $column & ")"
+
+proc `$`(info: type(instantiationInfo(0))): string =
+  # The +1 is needed here
+  lineInfoToString(info.fileName, info.line, info.column+1)
diff --git a/lib/system/hti.nim b/lib/system/hti.nim
index 45b1d1cd3..c7b52bbdf 100644
--- a/lib/system/hti.nim
+++ b/lib/system/hti.nim
@@ -7,12 +7,6 @@
 #    distribution, for details about the copyright.
 #
 
-when declared(NimString):
-  # we are in system module:
-  {.pragma: codegenType, compilerproc.}
-else:
-  {.pragma: codegenType, importc.}
-
 type
   # This should be the same as ast.TTypeKind
   # many enum fields are not used at runtime
@@ -79,7 +73,7 @@ type
     tyVoidHidden
 
   TNimNodeKind = enum nkNone, nkSlot, nkList, nkCase
-  TNimNode {.codegenType.} = object
+  TNimNode {.compilerProc.} = object
     kind: TNimNodeKind
     offset: int
     typ: ptr TNimType
@@ -92,7 +86,7 @@ type
     ntfAcyclic = 1,    # type cannot form a cycle
     ntfEnumHole = 2    # enum has holes and thus `$` for them needs the slow
                        # version
-  TNimType {.codegenType.} = object
+  TNimType {.compilerProc.} = object
     size: int
     kind: TNimKind
     flags: set[TNimTypeFlag]
@@ -109,6 +103,6 @@ type
   PNimType = ptr TNimType
 
 when defined(nimTypeNames):
-  var nimTypeRoot {.codegenType.}: PNimType
+  var nimTypeRoot {.compilerProc.}: PNimType
 
 # node.len may be the ``first`` element of a set
diff --git a/lib/system/jssys.nim b/lib/system/jssys.nim
index 8d4a2e482..836ac198d 100644
--- a/lib/system/jssys.nim
+++ b/lib/system/jssys.nim
@@ -31,8 +31,6 @@ type
 
   JSRef = ref RootObj # Fake type.
 
-{.deprecated: [TSafePoint: SafePoint, TCallFrame: CallFrame].}
-
 var
   framePtr {.importc, nodecl, volatile.}: PCallFrame
   excHandler {.importc, nodecl, volatile.}: int = 0
@@ -184,12 +182,10 @@ proc setConstr() {.varargs, asmNoStackFrame, compilerproc.} =
 proc makeNimstrLit(c: cstring): string {.asmNoStackFrame, compilerproc.} =
   {.emit: """
   var ln = `c`.length;
-  var result = new Array(ln + 1);
-  var i = 0;
-  for (; i < ln; ++i) {
+  var result = new Array(ln);
+  for (var i = 0; i < ln; ++i) {
     result[i] = `c`.charCodeAt(i);
   }
-  result[i] = 0; // terminating zero
   return result;
   """.}
 
@@ -227,13 +223,12 @@ proc cstrToNimstr(c: cstring): string {.asmNoStackFrame, compilerproc.} =
     }
     ++r;
   }
-  result[r] = 0; // terminating zero
   return result;
   """.}
 
 proc toJSStr(s: string): cstring {.asmNoStackFrame, compilerproc.} =
   asm """
-  var len = `s`.length-1;
+  var len = `s`.length;
   var asciiPart = new Array(len);
   var fcc = String.fromCharCode;
   var nonAsciiPart = null;
@@ -264,10 +259,7 @@ proc toJSStr(s: string): cstring {.asmNoStackFrame, compilerproc.} =
 
 proc mnewString(len: int): string {.asmNoStackFrame, compilerproc.} =
   asm """
-    var result = new Array(`len`+1);
-    result[0] = 0;
-    result[`len`] = 0;
-    return result;
+    return new Array(`len`);
   """
 
 proc SetCard(a: int): int {.compilerproc, asmNoStackFrame.} =
@@ -325,7 +317,7 @@ proc cmpStrings(a, b: string): int {.asmNoStackFrame, compilerProc.} =
     if (`a` == `b`) return 0;
     if (!`a`) return -1;
     if (!`b`) return 1;
-    for (var i = 0; i < `a`.length - 1 && i < `b`.length - 1; i++) {
+    for (var i = 0; i < `a`.length && i < `b`.length; i++) {
       var result = `a`[i] - `b`[i];
       if (result != 0) return result;
     }
@@ -506,7 +498,6 @@ proc chckNilDisp(p: pointer) {.compilerproc.} =
   if p == nil:
     sysFatal(NilAccessError, "cannot dispatch; dispatcher is nil")
 
-type NimString = string # hack for hti.nim
 include "system/hti"
 
 proc isFatPointer(ti: PNimType): bool =
@@ -654,9 +645,7 @@ proc isObj(obj, subclass: PNimType): bool {.compilerproc.} =
   return true
 
 proc addChar(x: string, c: char) {.compilerproc, asmNoStackFrame.} =
-  asm """
-    `x`[`x`.length-1] = `c`; `x`.push(0);
-  """
+  asm "`x`.push(`c`);"
 
 {.pop.}
 
diff --git a/lib/system/mmdisp.nim b/lib/system/mmdisp.nim
index b33ca93f2..e7e14b948 100644
--- a/lib/system/mmdisp.nim
+++ b/lib/system/mmdisp.nim
@@ -175,8 +175,7 @@ when defined(boehmgc):
     dest[] = src
 
   type
-    MemRegion = object {.final, pure.}
-  {.deprecated: [TMemRegion: MemRegion].}
+    MemRegion = object
 
   proc alloc(r: var MemRegion, size: int): pointer =
     result = boehmAlloc(size)
@@ -215,60 +214,58 @@ elif defined(gogc):
     goNumSizeClasses = 67
 
   type
-    cbool {.importc: "_Bool", nodecl.} = bool
-
     goMStats_inner_struct = object
-        size: uint32
-        nmalloc: uint64
-        nfree: uint64
+      size: uint32
+      nmalloc: uint64
+      nfree: uint64
 
     goMStats = object
-        # General statistics.
-        alloc: uint64            # bytes allocated and still in use
-        total_alloc: uint64      # bytes allocated (even if freed)
-        sys: uint64              # bytes obtained from system (should be sum of xxx_sys below, no locking, approximate)
-        nlookup: uint64          # number of pointer lookups
-        nmalloc: uint64          # number of mallocs
-        nfree: uint64            # number of frees
-        # Statistics about malloc heap.
-        # protected by mheap.Lock
-        heap_alloc: uint64       # bytes allocated and still in use
-        heap_sys: uint64         # bytes obtained from system
-        heap_idle: uint64        # bytes in idle spans
-        heap_inuse: uint64       # bytes in non-idle spans
-        heap_released: uint64    # bytes released to the OS
-        heap_objects: uint64 # total number of allocated objects
-        # Statistics about allocation of low-level fixed-size structures.
-        # Protected by FixAlloc locks.
-        stacks_inuse: uint64     # bootstrap stacks
-        stacks_sys: uint64
-        mspan_inuse: uint64      # MSpan structures
-        mspan_sys: uint64
-        mcache_inuse: uint64     # MCache structures
-        mcache_sys: uint64
-        buckhash_sys: uint64     # profiling bucket hash table
-        gc_sys: uint64
-        other_sys: uint64
-        # Statistics about garbage collector.
-        # Protected by mheap or stopping the world during GC.
-        next_gc: uint64          # next GC (in heap_alloc time)
-        last_gc: uint64          # last GC (in absolute time)
-        pause_total_ns: uint64
-        pause_ns: array[256, uint64] # circular buffer of recent gc pause lengths
-        pause_end: array[256, uint64] # circular buffer of recent gc end times (nanoseconds since 1970)
-        numgc: uint32
-        numforcedgc: uint32      # number of user-forced GCs
-        gc_cpu_fraction: float64 # fraction of CPU time used by GC
-        enablegc: cbool
-        debuggc: cbool
-        # Statistics about allocation size classes.
-        by_size: array[goNumSizeClasses, goMStats_inner_struct]
-        # Statistics below here are not exported to MemStats directly.
-        tinyallocs: uint64       # number of tiny allocations that didn't cause actual allocation; not exported to go directly
-        gc_trigger: uint64
-        heap_live: uint64
-        heap_scan: uint64
-        heap_marked: uint64
+      # General statistics.
+      alloc: uint64            # bytes allocated and still in use
+      total_alloc: uint64      # bytes allocated (even if freed)
+      sys: uint64              # bytes obtained from system (should be sum of xxx_sys below, no locking, approximate)
+      nlookup: uint64          # number of pointer lookups
+      nmalloc: uint64          # number of mallocs
+      nfree: uint64            # number of frees
+      # Statistics about malloc heap.
+      # protected by mheap.Lock
+      heap_alloc: uint64       # bytes allocated and still in use
+      heap_sys: uint64         # bytes obtained from system
+      heap_idle: uint64        # bytes in idle spans
+      heap_inuse: uint64       # bytes in non-idle spans
+      heap_released: uint64    # bytes released to the OS
+      heap_objects: uint64 # total number of allocated objects
+      # Statistics about allocation of low-level fixed-size structures.
+      # Protected by FixAlloc locks.
+      stacks_inuse: uint64     # bootstrap stacks
+      stacks_sys: uint64
+      mspan_inuse: uint64      # MSpan structures
+      mspan_sys: uint64
+      mcache_inuse: uint64     # MCache structures
+      mcache_sys: uint64
+      buckhash_sys: uint64     # profiling bucket hash table
+      gc_sys: uint64
+      other_sys: uint64
+      # Statistics about garbage collector.
+      # Protected by mheap or stopping the world during GC.
+      next_gc: uint64          # next GC (in heap_alloc time)
+      last_gc: uint64          # last GC (in absolute time)
+      pause_total_ns: uint64
+      pause_ns: array[256, uint64] # circular buffer of recent gc pause lengths
+      pause_end: array[256, uint64] # circular buffer of recent gc end times (nanoseconds since 1970)
+      numgc: uint32
+      numforcedgc: uint32      # number of user-forced GCs
+      gc_cpu_fraction: float64 # fraction of CPU time used by GC
+      enablegc: bool
+      debuggc: bool
+      # Statistics about allocation size classes.
+      by_size: array[goNumSizeClasses, goMStats_inner_struct]
+      # Statistics below here are not exported to MemStats directly.
+      tinyallocs: uint64       # number of tiny allocations that didn't cause actual allocation; not exported to go directly
+      gc_trigger: uint64
+      heap_live: uint64
+      heap_scan: uint64
+      heap_marked: uint64
 
   proc goRuntime_ReadMemStats(a2: ptr goMStats) {.cdecl,
     importc: "runtime_ReadMemStats",
@@ -341,9 +338,12 @@ elif defined(gogc):
     proc getOccupiedSharedMem(): int = discard
 
   const goFlagNoZero: uint32 = 1 shl 3
-  proc goRuntimeMallocGC(size: uint, typ: uint, flag: uint32): pointer {.importc: "runtime_mallocgc", dynlib: goLib.}
+  proc goRuntimeMallocGC(size: uint, typ: uint, flag: uint32): pointer {.
+    importc: "runtime_mallocgc", dynlib: goLib.}
 
-  proc goSetFinalizer(obj: pointer, f: pointer) {.importc: "set_finalizer", codegenDecl:"$1 $2$3 __asm__ (\"main.Set_finalizer\");\n$1 $2$3", dynlib: goLib.}
+  proc goSetFinalizer(obj: pointer, f: pointer) {.
+    importc: "set_finalizer", codegenDecl: "$1 $2$3 __asm__ (\"main.Set_finalizer\");\n$1 $2$3",
+    dynlib: goLib.}
 
   proc newObj(typ: PNimType, size: int): pointer {.compilerproc.} =
     result = goRuntimeMallocGC(roundup(size, sizeof(pointer)).uint, 0.uint, 0.uint32)
@@ -369,8 +369,7 @@ elif defined(gogc):
 
   proc growObj(old: pointer, newsize: int): pointer =
     # the Go GC doesn't have a realloc
-    var
-      oldsize = cast[PGenericSeq](old).len * cast[PGenericSeq](old).elemSize + GenericSeqSize
+    let oldsize = cast[PGenericSeq](old).len * cast[PGenericSeq](old).elemSize + GenericSeqSize
     result = goRuntimeMallocGC(roundup(newsize, sizeof(pointer)).uint, 0.uint, goFlagNoZero)
     copyMem(result, old, oldsize)
     zeroMem(cast[pointer](cast[ByteAddress](result) +% oldsize), newsize - oldsize)
@@ -386,8 +385,7 @@ elif defined(gogc):
     dest[] = src
 
   type
-    MemRegion = object {.final, pure.}
-  {.deprecated: [TMemRegion: MemRegion].}
+    MemRegion = object
 
   proc alloc(r: var MemRegion, size: int): pointer =
     result = alloc(size)
@@ -477,8 +475,7 @@ elif defined(nogc) and defined(useMalloc):
     dest[] = src
 
   type
-    MemRegion = object {.final, pure.}
-  {.deprecated: [TMemRegion: MemRegion].}
+    MemRegion = object
 
   proc alloc(r: var MemRegion, size: int): pointer =
     result = alloc(size)
@@ -551,15 +548,13 @@ else:
   elif defined(gcRegions):
     # XXX due to bootstrapping reasons, we cannot use  compileOption("gc", "stack") here
     include "system/gc_regions"
-  elif defined(gcMarkAndSweep):
+  elif defined(gcMarkAndSweep) or defined(gcDestructors):
     # XXX use 'compileOption' here
     include "system/gc_ms"
-  elif defined(gcGenerational):
-    include "system/gc"
   else:
     include "system/gc"
 
-when not declared(nimNewSeqOfCap):
+when not declared(nimNewSeqOfCap) and not defined(gcDestructors):
   proc nimNewSeqOfCap(typ: PNimType, cap: int): pointer {.compilerproc.} =
     when defined(gcRegions):
       let s = mulInt(cap, typ.base.size)  # newStr already adds GenericSeqSize
diff --git a/lib/system/nimscript.nim b/lib/system/nimscript.nim
index 5bf69dd94..64d6255da 100644
--- a/lib/system/nimscript.nim
+++ b/lib/system/nimscript.nim
@@ -73,12 +73,12 @@ proc switch*(key: string, val="") =
 proc warning*(name: string; val: bool) =
   ## Disables or enables a specific warning.
   let v = if val: "on" else: "off"
-  warningImpl(name & "]:" & v, "warning[" & name & "]:" & v)
+  warningImpl(name & ":" & v, "warning:" & name & ":" & v)
 
 proc hint*(name: string; val: bool) =
   ## Disables or enables a specific hint.
   let v = if val: "on" else: "off"
-  hintImpl(name & "]:" & v, "hint[" & name & "]:" & v)
+  hintImpl(name & ":" & v, "hint:" & name & ":" & v)
 
 proc patchFile*(package, filename, replacement: string) =
   ## Overrides the location of a given file belonging to the
@@ -305,7 +305,6 @@ template withDir*(dir: string; body: untyped): untyped =
   finally:
     cd(curDir)
 
-template `==?`(a, b: string): bool = cmpIgnoreStyle(a, b) == 0
 
 proc writeTask(name, desc: string) =
   if desc.len > 0:
@@ -313,29 +312,30 @@ proc writeTask(name, desc: string) =
     for i in 0 ..< 20 - name.len: spaces.add ' '
     echo name, spaces, desc
 
-template task*(name: untyped; description: string; body: untyped): untyped =
-  ## Defines a task. Hidden tasks are supported via an empty description.
-  ## Example:
-  ##
-  ## .. code-block:: nim
-  ##  task build, "default build is via the C backend":
-  ##    setCommand "c"
-  proc `name Task`*() = body
-
-  let cmd = getCommand()
-  if cmd.len == 0 or cmd ==? "help":
-    setCommand "help"
-    writeTask(astToStr(name), description)
-  elif cmd ==? astToStr(name):
-    setCommand "nop"
-    `name Task`()
-
 proc cppDefine*(define: string) =
   ## tell Nim that ``define`` is a C preprocessor ``#define`` and so always
   ## needs to be mangled.
   builtin
 
 when not defined(nimble):
+  template `==?`(a, b: string): bool = cmpIgnoreStyle(a, b) == 0
+  template task*(name: untyped; description: string; body: untyped): untyped =
+    ## Defines a task. Hidden tasks are supported via an empty description.
+    ## Example:
+    ##
+    ## .. code-block:: nim
+    ##  task build, "default build is via the C backend":
+    ##    setCommand "c"
+    proc `name Task`*() = body
+
+    let cmd = getCommand()
+    if cmd.len == 0 or cmd ==? "help":
+      setCommand "help"
+      writeTask(astToStr(name), description)
+    elif cmd ==? astToStr(name):
+      setCommand "nop"
+      `name Task`()
+
   # nimble has its own implementation for these things.
   var
     packageName* = ""    ## Nimble support: Set this to the package name. It
diff --git a/lib/system/repr.nim b/lib/system/repr.nim
index 982b07467..85701c28f 100644
--- a/lib/system/repr.nim
+++ b/lib/system/repr.nim
@@ -25,29 +25,13 @@ proc reprPointer(x: pointer): string {.compilerproc.} =
     discard c_sprintf(buf, "%p", x)
     return $buf
 
-proc `$`(x: uint64): string =
-  if x == 0:
-    result = "0"
-  else:
-    result = newString(60)
-    var i = 0
-    var n = x
-    while n != 0:
-      let nn = n div 10'u64
-      result[i] = char(n - 10'u64 * nn + ord('0'))
-      inc i
-      n = nn
-    result.setLen i
-
-    let half = i div 2
-    # Reverse
-    for t in 0 .. half-1: swap(result[t], result[i-t-1])
-
 proc reprStrAux(result: var string, s: cstring; len: int) =
   if cast[pointer](s) == nil:
     add result, "nil"
     return
-  add result, reprPointer(cast[pointer](s)) & "\""
+  if len > 0:
+    add result, reprPointer(cast[pointer](s))
+  add result, "\""
   for i in 0 .. pred(len):
     let c = s[i]
     case c
@@ -180,9 +164,10 @@ when not defined(useNimRtl):
   proc reprSequence(result: var string, p: pointer, typ: PNimType,
                     cl: var ReprClosure) =
     if p == nil:
-      add result, "nil"
+      add result, "[]"
       return
-    result.add(reprPointer(p) & "[")
+    result.add(reprPointer(p))
+    result.add '['
     var bs = typ.base.size
     for i in 0..cast[PGenericSeq](p).len-1:
       if i > 0: add result, ", "
@@ -284,7 +269,7 @@ when not defined(useNimRtl):
     of tyChar: add result, reprChar(cast[ptr char](p)[])
     of tyString:
       let sp = cast[ptr string](p)
-      reprStrAux(result, if sp[].isNil: nil else: sp[].cstring, sp[].len)
+      reprStrAux(result, sp[].cstring, sp[].len)
     of tyCString:
       let cs = cast[ptr cstring](p)[]
       if cs.isNil: add result, "nil"
diff --git a/lib/system/reprjs.nim b/lib/system/reprjs.nim
index d04d6e12b..7cb25a252 100644
--- a/lib/system/reprjs.nim
+++ b/lib/system/reprjs.nim
@@ -232,10 +232,7 @@ proc reprAux(result: var string, p: pointer, typ: PNimType,
   of tyString:
     var fp: int
     {. emit: "`fp` = `p`;\n" .}
-    if cast[string](fp).isNil:
-      add(result, "nil")
-    else:
-      add( result, reprStr(cast[string](p)) )
+    add( result, reprStr(cast[string](p)) )
   of tyCString:
     var fp: cstring
     {. emit: "`fp` = `p`;\n" .}
diff --git a/lib/system/strmantle.nim b/lib/system/strmantle.nim
new file mode 100644
index 000000000..ceaecb4f9
--- /dev/null
+++ b/lib/system/strmantle.nim
@@ -0,0 +1,298 @@
+#
+#
+#            Nim's Runtime Library
+#        (c) Copyright 2018 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+## Compilerprocs for strings that do not depend on the string implementation.
+
+proc cmpStrings(a, b: string): int {.inline, compilerProc.} =
+  let alen = a.len
+  let blen = b.len
+  let minlen = min(alen, blen)
+  if minlen > 0:
+    result = c_memcmp(unsafeAddr a[0], unsafeAddr b[0], minlen.csize)
+    if result == 0:
+      result = alen - blen
+  else:
+    result = alen - blen
+
+proc eqStrings(a, b: string): bool {.inline, compilerProc.} =
+  let alen = a.len
+  let blen = b.len
+  if alen == blen:
+    if alen == 0: return true
+    return equalMem(unsafeAddr(a[0]), unsafeAddr(b[0]), alen)
+
+proc hashString(s: string): int {.compilerproc.} =
+  # the compiler needs exactly the same hash function!
+  # this used to be used for efficient generation of string case statements
+  var h = 0
+  for i in 0..len(s)-1:
+    h = h +% ord(s[i])
+    h = h +% h shl 10
+    h = h xor (h shr 6)
+  h = h +% h shl 3
+  h = h xor (h shr 11)
+  h = h +% h shl 15
+  result = h
+
+proc add*(result: var string; x: int64) =
+  let base = result.len
+  setLen(result, base + sizeof(x)*4)
+  var i = 0
+  var y = x
+  while true:
+    var d = y div 10
+    result[base+i] = chr(abs(int(y - d*10)) + ord('0'))
+    inc(i)
+    y = d
+    if y == 0: break
+  if x < 0:
+    result[base+i] = '-'
+    inc(i)
+  setLen(result, base+i)
+  # mirror the string:
+  for j in 0..i div 2 - 1:
+    swap(result[base+j], result[base+i-j-1])
+
+proc nimIntToStr(x: int): string {.compilerRtl.} =
+  result = newStringOfCap(sizeof(x)*4)
+  result.add x
+
+proc add*(result: var string; x: float) =
+  when nimvm:
+    result.add $x
+  else:
+    var buf: array[0..64, char]
+    when defined(nimNoArrayToCstringConversion):
+      var n: int = c_sprintf(addr buf, "%.16g", x)
+    else:
+      var n: int = c_sprintf(buf, "%.16g", x)
+    var hasDot = false
+    for i in 0..n-1:
+      if buf[i] == ',':
+        buf[i] = '.'
+        hasDot = true
+      elif buf[i] in {'a'..'z', 'A'..'Z', '.'}:
+        hasDot = true
+    if not hasDot:
+      buf[n] = '.'
+      buf[n+1] = '0'
+      buf[n+2] = '\0'
+    # On Windows nice numbers like '1.#INF', '-1.#INF' or '1.#NAN'
+    # of '-1.#IND' are produced.
+    # We want to get rid of these here:
+    if buf[n-1] in {'n', 'N', 'D', 'd'}:
+      result.add "nan"
+    elif buf[n-1] == 'F':
+      if buf[0] == '-':
+        result.add "-inf"
+      else:
+        result.add "inf"
+    else:
+      var i = 0
+      while buf[i] != '\0':
+        result.add buf[i]
+        inc i
+
+proc nimFloatToStr(f: float): string {.compilerproc.} =
+  result = newStringOfCap(8)
+  result.add f
+
+proc c_strtod(buf: cstring, endptr: ptr cstring): float64 {.
+  importc: "strtod", header: "<stdlib.h>", noSideEffect.}
+
+const
+  IdentChars = {'a'..'z', 'A'..'Z', '0'..'9', '_'}
+  powtens =  [1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9,
+              1e10, 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19,
+              1e20, 1e21, 1e22]
+
+proc nimParseBiggestFloat(s: string, number: var BiggestFloat,
+                          start = 0): int {.compilerProc.} =
+  # This routine attempt to parse float that can parsed quickly.
+  # ie whose integer part can fit inside a 53bits integer.
+  # their real exponent must also be <= 22. If the float doesn't follow
+  # these restrictions, transform the float into this form:
+  #  INTEGER * 10 ^ exponent and leave the work to standard `strtod()`.
+  # This avoid the problems of decimal character portability.
+  # see: http://www.exploringbinary.com/fast-path-decimal-to-floating-point-conversion/
+  var
+    i = start
+    sign = 1.0
+    kdigits, fdigits = 0
+    exponent: int
+    integer: uint64
+    frac_exponent = 0
+    exp_sign = 1
+    first_digit = -1
+    has_sign = false
+
+  # Sign?
+  if s[i] == '+' or s[i] == '-':
+    has_sign = true
+    if s[i] == '-':
+      sign = -1.0
+    inc(i)
+
+  # NaN?
+  if s[i] == 'N' or s[i] == 'n':
+    if s[i+1] == 'A' or s[i+1] == 'a':
+      if s[i+2] == 'N' or s[i+2] == 'n':
+        if s[i+3] notin IdentChars:
+          number = NaN
+          return i+3 - start
+    return 0
+
+  # Inf?
+  if s[i] == 'I' or s[i] == 'i':
+    if s[i+1] == 'N' or s[i+1] == 'n':
+      if s[i+2] == 'F' or s[i+2] == 'f':
+        if s[i+3] notin IdentChars:
+          number = Inf*sign
+          return i+3 - start
+    return 0
+
+  if s[i] in {'0'..'9'}:
+    first_digit = (s[i].ord - '0'.ord)
+  # Integer part?
+  while s[i] in {'0'..'9'}:
+    inc(kdigits)
+    integer = integer * 10'u64 + (s[i].ord - '0'.ord).uint64
+    inc(i)
+    while s[i] == '_': inc(i)
+
+  # Fractional part?
+  if s[i] == '.':
+    inc(i)
+    # if no integer part, Skip leading zeros
+    if kdigits <= 0:
+      while s[i] == '0':
+        inc(frac_exponent)
+        inc(i)
+        while s[i] == '_': inc(i)
+
+    if first_digit == -1 and s[i] in {'0'..'9'}:
+      first_digit = (s[i].ord - '0'.ord)
+    # get fractional part
+    while s[i] in {'0'..'9'}:
+      inc(fdigits)
+      inc(frac_exponent)
+      integer = integer * 10'u64 + (s[i].ord - '0'.ord).uint64
+      inc(i)
+      while s[i] == '_': inc(i)
+
+  # if has no digits: return error
+  if kdigits + fdigits <= 0 and
+     (i == start or # no char consumed (empty string).
+     (i == start + 1 and has_sign)): # or only '+' or '-
+    return 0
+
+  if s[i] in {'e', 'E'}:
+    inc(i)
+    if s[i] == '+' or s[i] == '-':
+      if s[i] == '-':
+        exp_sign = -1
+
+      inc(i)
+    if s[i] notin {'0'..'9'}:
+      return 0
+    while s[i] in {'0'..'9'}:
+      exponent = exponent * 10 + (ord(s[i]) - ord('0'))
+      inc(i)
+      while s[i] == '_': inc(i) # underscores are allowed and ignored
+
+  var real_exponent = exp_sign*exponent - frac_exponent
+  let exp_negative = real_exponent < 0
+  var abs_exponent = abs(real_exponent)
+
+  # if exponent greater than can be represented: +/- zero or infinity
+  if abs_exponent > 999:
+    if exp_negative:
+      number = 0.0*sign
+    else:
+      number = Inf*sign
+    return i - start
+
+  # if integer is representable in 53 bits:  fast path
+  # max fast path integer is  1<<53 - 1 or  8999999999999999 (16 digits)
+  let digits = kdigits + fdigits
+  if digits <= 15 or (digits <= 16 and first_digit <= 8):
+    # max float power of ten with set bits above the 53th bit is 10^22
+    if abs_exponent <= 22:
+      if exp_negative:
+        number = sign * integer.float / powtens[abs_exponent]
+      else:
+        number = sign * integer.float * powtens[abs_exponent]
+      return i - start
+
+    # if exponent is greater try to fit extra exponent above 22 by multiplying
+    # integer part is there is space left.
+    let slop = 15 - kdigits - fdigits
+    if  abs_exponent <= 22 + slop and not exp_negative:
+      number = sign * integer.float * powtens[slop] * powtens[abs_exponent-slop]
+      return i - start
+
+  # if failed: slow path with strtod.
+  var t: array[500, char] # flaviu says: 325 is the longest reasonable literal
+  var ti = 0
+  let maxlen = t.high - "e+000".len # reserve enough space for exponent
+
+  result = i - start
+  i = start
+  # re-parse without error checking, any error should be handled by the code above.
+  if s[i] == '.': i.inc
+  while s[i] in {'0'..'9','+','-'}:
+    if ti < maxlen:
+      t[ti] = s[i]; inc(ti)
+    inc(i)
+    while s[i] in {'.', '_'}: # skip underscore and decimal point
+      inc(i)
+
+  # insert exponent
+  t[ti] = 'E'; inc(ti)
+  t[ti] = (if exp_negative: '-' else: '+'); inc(ti)
+  inc(ti, 3)
+
+  # insert adjusted exponent
+  t[ti-1] = ('0'.ord + abs_exponent mod 10).char; abs_exponent = abs_exponent div 10
+  t[ti-2] = ('0'.ord + abs_exponent mod 10).char; abs_exponent = abs_exponent div 10
+  t[ti-3] = ('0'.ord + abs_exponent mod 10).char
+
+  when defined(nimNoArrayToCstringConversion):
+    number = c_strtod(addr t, nil)
+  else:
+    number = c_strtod(t, nil)
+
+proc nimInt64ToStr(x: int64): string {.compilerRtl.} =
+  result = newStringOfCap(sizeof(x)*4)
+  result.add x
+
+proc nimBoolToStr(x: bool): string {.compilerRtl.} =
+  return if x: "true" else: "false"
+
+proc nimCharToStr(x: char): string {.compilerRtl.} =
+  result = newString(1)
+  result[0] = x
+
+proc `$`(x: uint64): string =
+  if x == 0:
+    result = "0"
+  else:
+    result = newString(60)
+    var i = 0
+    var n = x
+    while n != 0:
+      let nn = n div 10'u64
+      result[i] = char(n - 10'u64 * nn + ord('0'))
+      inc i
+      n = nn
+    result.setLen i
+
+    let half = i div 2
+    # Reverse
+    for t in 0 .. half-1: swap(result[t], result[i-t-1])
diff --git a/lib/system/sysio.nim b/lib/system/sysio.nim
index 7a10849dd..df13ab628 100644
--- a/lib/system/sysio.nim
+++ b/lib/system/sysio.nim
@@ -143,19 +143,17 @@ proc getFileHandle*(f: File): FileHandle = c_fileno(f)
 
 proc readLine(f: File, line: var TaintedString): bool =
   var pos = 0
-  var sp: cint = 80
+
   # Use the currently reserved space for a first try
-  if line.string.isNil:
-    line = TaintedString(newStringOfCap(80))
-  else:
-    when not defined(nimscript):
-      sp = cint(cast[PGenericSeq](line.string).space)
+  var sp = line.string.len
+  if sp == 0:
+    sp = 80
     line.string.setLen(sp)
   while true:
     # memset to \L so that we can tell how far fgets wrote, even on EOF, where
     # fgets doesn't append an \L
     nimSetMem(addr line.string[pos], '\L'.ord, sp)
-    var fgetsSuccess = c_fgets(addr line.string[pos], sp, f) != nil
+    var fgetsSuccess = c_fgets(addr line.string[pos], sp.cint, f) != nil
     if not fgetsSuccess: checkErr(f)
     let m = c_memchr(addr line.string[pos], '\L'.ord, sp)
     if m != nil:
@@ -163,7 +161,7 @@ proc readLine(f: File, line: var TaintedString): bool =
       var last = cast[ByteAddress](m) - cast[ByteAddress](addr line.string[0])
       if last > 0 and line.string[last-1] == '\c':
         line.string.setLen(last-1)
-        return fgetsSuccess
+        return last > 1 or fgetsSuccess
         # We have to distinguish between two possible cases:
         # \0\l\0 => line ending in a null character.
         # \0\l\l => last line without newline, null was put there by fgets.
@@ -171,7 +169,7 @@ proc readLine(f: File, line: var TaintedString): bool =
         if last < pos + sp - 1 and line.string[last+1] != '\0':
           dec last
       line.string.setLen(last)
-      return fgetsSuccess
+      return last > 0 or fgetsSuccess
     else:
       # fgets will have inserted a null byte at the end of the string.
       dec sp
diff --git a/lib/system/sysstr.nim b/lib/system/sysstr.nim
index 0e690d832..6438a0541 100644
--- a/lib/system/sysstr.nim
+++ b/lib/system/sysstr.nim
@@ -20,37 +20,6 @@ proc resize(old: int): int {.inline.} =
   elif old < 65536: result = old * 2
   else: result = old * 3 div 2 # for large arrays * 3/2 is better
 
-proc cmpStrings(a, b: NimString): int {.inline, compilerProc.} =
-  if a == b: return 0
-  when defined(nimNoNil):
-    let alen = if a == nil: 0 else: a.len
-    let blen = if b == nil: 0 else: b.len
-  else:
-    if a == nil: return -1
-    if b == nil: return 1
-    let alen = a.len
-    let blen = b.len
-  let minlen = min(alen, blen)
-  if minlen > 0:
-    result = nimCmpMem(addr a.data, addr b.data, minlen.csize)
-    if result == 0:
-      result = alen - blen
-  else:
-    result = alen - blen
-
-proc eqStrings(a, b: NimString): bool {.inline, compilerProc.} =
-  if a == b: return true
-  when defined(nimNoNil):
-    let alen = if a == nil: 0 else: a.len
-    let blen = if b == nil: 0 else: b.len
-  else:
-    if a == nil or b == nil: return false
-    let alen = a.len
-    let blen = b.len
-  if alen == blen:
-    if alen == 0: return true
-    return equalMem(addr(a.data), addr(b.data), alen)
-
 when declared(allocAtomic):
   template allocStr(size: untyped): untyped =
     cast[NimString](allocAtomic(size))
@@ -94,6 +63,8 @@ proc mnewString(len: int): NimString {.compilerProc.} =
   result.len = len
 
 proc copyStrLast(s: NimString, start, last: int): NimString {.compilerProc.} =
+  # This is not used by most recent versions of the compiler anymore, but
+  # required for bootstrapping purposes.
   let start = max(start, 0)
   if s == nil: return nil
   let len = min(last, s.len-1) - start + 1
@@ -105,14 +76,16 @@ proc copyStrLast(s: NimString, start, last: int): NimString {.compilerProc.} =
   else:
     result = rawNewString(len)
 
-proc nimToCStringConv(s: NimString): cstring {.compilerProc, inline.} =
-  if s == nil or s.len == 0: result = cstring""
-  else: result = cstring(addr s.data)
-
 proc copyStr(s: NimString, start: int): NimString {.compilerProc.} =
+  # This is not used by most recent versions of the compiler anymore, but
+  # required for bootstrapping purposes.
   if s == nil: return nil
   result = copyStrLast(s, start, s.len-1)
 
+proc nimToCStringConv(s: NimString): cstring {.compilerProc, inline.} =
+  if s == nil or s.len == 0: result = cstring""
+  else: result = cstring(addr s.data)
+
 proc toNimStr(str: cstring, len: int): NimString {.compilerProc.} =
   result = rawNewStringNoInit(len)
   result.len = len
@@ -164,19 +137,6 @@ proc copyDeepString(src: NimString): NimString {.inline.} =
     result.len = src.len
     copyMem(addr(result.data), addr(src.data), src.len + 1)
 
-proc hashString(s: string): int {.compilerproc.} =
-  # the compiler needs exactly the same hash function!
-  # this used to be used for efficient generation of string case statements
-  var h = 0
-  for i in 0..len(s)-1:
-    h = h +% ord(s[i])
-    h = h +% h shl 10
-    h = h xor (h shr 6)
-  h = h +% h shl 3
-  h = h xor (h shr 11)
-  h = h +% h shl 15
-  result = h
-
 proc addChar(s: NimString, c: char): NimString =
   # is compilerproc!
   if s == nil:
@@ -403,243 +363,3 @@ proc setLengthSeqV2(s: PGenericSeq, typ: PNimType, newLen: int): PGenericSeq {.
       result.len = newLen
     else:
       result = setLengthSeq(s, typ.base.size, newLen)
-
-# --------------- other string routines ----------------------------------
-proc add*(result: var string; x: int64) =
-  let base = result.len
-  setLen(result, base + sizeof(x)*4)
-  var i = 0
-  var y = x
-  while true:
-    var d = y div 10
-    result[base+i] = chr(abs(int(y - d*10)) + ord('0'))
-    inc(i)
-    y = d
-    if y == 0: break
-  if x < 0:
-    result[base+i] = '-'
-    inc(i)
-  setLen(result, base+i)
-  # mirror the string:
-  for j in 0..i div 2 - 1:
-    swap(result[base+j], result[base+i-j-1])
-
-proc nimIntToStr(x: int): string {.compilerRtl.} =
-  result = newStringOfCap(sizeof(x)*4)
-  result.add x
-
-proc add*(result: var string; x: float) =
-  when nimvm:
-    result.add $x
-  else:
-    var buf: array[0..64, char]
-    when defined(nimNoArrayToCstringConversion):
-      var n: int = c_sprintf(addr buf, "%.16g", x)
-    else:
-      var n: int = c_sprintf(buf, "%.16g", x)
-    var hasDot = false
-    for i in 0..n-1:
-      if buf[i] == ',':
-        buf[i] = '.'
-        hasDot = true
-      elif buf[i] in {'a'..'z', 'A'..'Z', '.'}:
-        hasDot = true
-    if not hasDot:
-      buf[n] = '.'
-      buf[n+1] = '0'
-      buf[n+2] = '\0'
-    # On Windows nice numbers like '1.#INF', '-1.#INF' or '1.#NAN'
-    # of '-1.#IND' are produced.
-    # We want to get rid of these here:
-    if buf[n-1] in {'n', 'N', 'D', 'd'}:
-      result.add "nan"
-    elif buf[n-1] == 'F':
-      if buf[0] == '-':
-        result.add "-inf"
-      else:
-        result.add "inf"
-    else:
-      var i = 0
-      while buf[i] != '\0':
-        result.add buf[i]
-        inc i
-
-proc nimFloatToStr(f: float): string {.compilerproc.} =
-  result = newStringOfCap(8)
-  result.add f
-
-proc c_strtod(buf: cstring, endptr: ptr cstring): float64 {.
-  importc: "strtod", header: "<stdlib.h>", noSideEffect.}
-
-const
-  IdentChars = {'a'..'z', 'A'..'Z', '0'..'9', '_'}
-  powtens =  [1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9,
-              1e10, 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19,
-              1e20, 1e21, 1e22]
-
-proc nimParseBiggestFloat(s: string, number: var BiggestFloat,
-                          start = 0): int {.compilerProc.} =
-  # This routine attempt to parse float that can parsed quickly.
-  # ie whose integer part can fit inside a 53bits integer.
-  # their real exponent must also be <= 22. If the float doesn't follow
-  # these restrictions, transform the float into this form:
-  #  INTEGER * 10 ^ exponent and leave the work to standard `strtod()`.
-  # This avoid the problems of decimal character portability.
-  # see: http://www.exploringbinary.com/fast-path-decimal-to-floating-point-conversion/
-  var
-    i = start
-    sign = 1.0
-    kdigits, fdigits = 0
-    exponent: int
-    integer: uint64
-    frac_exponent = 0
-    exp_sign = 1
-    first_digit = -1
-    has_sign = false
-
-  # Sign?
-  if s[i] == '+' or s[i] == '-':
-    has_sign = true
-    if s[i] == '-':
-      sign = -1.0
-    inc(i)
-
-  # NaN?
-  if s[i] == 'N' or s[i] == 'n':
-    if s[i+1] == 'A' or s[i+1] == 'a':
-      if s[i+2] == 'N' or s[i+2] == 'n':
-        if s[i+3] notin IdentChars:
-          number = NaN
-          return i+3 - start
-    return 0
-
-  # Inf?
-  if s[i] == 'I' or s[i] == 'i':
-    if s[i+1] == 'N' or s[i+1] == 'n':
-      if s[i+2] == 'F' or s[i+2] == 'f':
-        if s[i+3] notin IdentChars:
-          number = Inf*sign
-          return i+3 - start
-    return 0
-
-  if s[i] in {'0'..'9'}:
-    first_digit = (s[i].ord - '0'.ord)
-  # Integer part?
-  while s[i] in {'0'..'9'}:
-    inc(kdigits)
-    integer = integer * 10'u64 + (s[i].ord - '0'.ord).uint64
-    inc(i)
-    while s[i] == '_': inc(i)
-
-  # Fractional part?
-  if s[i] == '.':
-    inc(i)
-    # if no integer part, Skip leading zeros
-    if kdigits <= 0:
-      while s[i] == '0':
-        inc(frac_exponent)
-        inc(i)
-        while s[i] == '_': inc(i)
-
-    if first_digit == -1 and s[i] in {'0'..'9'}:
-      first_digit = (s[i].ord - '0'.ord)
-    # get fractional part
-    while s[i] in {'0'..'9'}:
-      inc(fdigits)
-      inc(frac_exponent)
-      integer = integer * 10'u64 + (s[i].ord - '0'.ord).uint64
-      inc(i)
-      while s[i] == '_': inc(i)
-
-  # if has no digits: return error
-  if kdigits + fdigits <= 0 and
-     (i == start or # no char consumed (empty string).
-     (i == start + 1 and has_sign)): # or only '+' or '-
-    return 0
-
-  if s[i] in {'e', 'E'}:
-    inc(i)
-    if s[i] == '+' or s[i] == '-':
-      if s[i] == '-':
-        exp_sign = -1
-
-      inc(i)
-    if s[i] notin {'0'..'9'}:
-      return 0
-    while s[i] in {'0'..'9'}:
-      exponent = exponent * 10 + (ord(s[i]) - ord('0'))
-      inc(i)
-      while s[i] == '_': inc(i) # underscores are allowed and ignored
-
-  var real_exponent = exp_sign*exponent - frac_exponent
-  let exp_negative = real_exponent < 0
-  var abs_exponent = abs(real_exponent)
-
-  # if exponent greater than can be represented: +/- zero or infinity
-  if abs_exponent > 999:
-    if exp_negative:
-      number = 0.0*sign
-    else:
-      number = Inf*sign
-    return i - start
-
-  # if integer is representable in 53 bits:  fast path
-  # max fast path integer is  1<<53 - 1 or  8999999999999999 (16 digits)
-  let digits = kdigits + fdigits
-  if digits <= 15 or (digits <= 16 and first_digit <= 8):
-    # max float power of ten with set bits above the 53th bit is 10^22
-    if abs_exponent <= 22:
-      if exp_negative:
-        number = sign * integer.float / powtens[abs_exponent]
-      else:
-        number = sign * integer.float * powtens[abs_exponent]
-      return i - start
-
-    # if exponent is greater try to fit extra exponent above 22 by multiplying
-    # integer part is there is space left.
-    let slop = 15 - kdigits - fdigits
-    if  abs_exponent <= 22 + slop and not exp_negative:
-      number = sign * integer.float * powtens[slop] * powtens[abs_exponent-slop]
-      return i - start
-
-  # if failed: slow path with strtod.
-  var t: array[500, char] # flaviu says: 325 is the longest reasonable literal
-  var ti = 0
-  let maxlen = t.high - "e+000".len # reserve enough space for exponent
-
-  result = i - start
-  i = start
-  # re-parse without error checking, any error should be handled by the code above.
-  if s[i] == '.': i.inc
-  while s[i] in {'0'..'9','+','-'}:
-    if ti < maxlen:
-      t[ti] = s[i]; inc(ti)
-    inc(i)
-    while s[i] in {'.', '_'}: # skip underscore and decimal point
-      inc(i)
-
-  # insert exponent
-  t[ti] = 'E'; inc(ti)
-  t[ti] = (if exp_negative: '-' else: '+'); inc(ti)
-  inc(ti, 3)
-
-  # insert adjusted exponent
-  t[ti-1] = ('0'.ord + abs_exponent mod 10).char; abs_exponent = abs_exponent div 10
-  t[ti-2] = ('0'.ord + abs_exponent mod 10).char; abs_exponent = abs_exponent div 10
-  t[ti-3] = ('0'.ord + abs_exponent mod 10).char
-
-  when defined(nimNoArrayToCstringConversion):
-    number = c_strtod(addr t, nil)
-  else:
-    number = c_strtod(t, nil)
-
-proc nimInt64ToStr(x: int64): string {.compilerRtl.} =
-  result = newStringOfCap(sizeof(x)*4)
-  result.add x
-
-proc nimBoolToStr(x: bool): string {.compilerRtl.} =
-  return if x: "true" else: "false"
-
-proc nimCharToStr(x: char): string {.compilerRtl.} =
-  result = newString(1)
-  result[0] = x
diff --git a/lib/system/threads.nim b/lib/system/threads.nim
index 2434ea21e..aaf0164fd 100644
--- a/lib/system/threads.nim
+++ b/lib/system/threads.nim
@@ -393,8 +393,9 @@ proc onThreadDestruction*(handler: proc () {.closure, gcsafe.}) =
   ## A thread is destructed when the ``.thread`` proc returns
   ## normally or when it raises an exception. Note that unhandled exceptions
   ## in a thread nevertheless cause the whole process to die.
-  if threadDestructionHandlers.isNil:
-    threadDestructionHandlers = @[]
+  when not defined(nimNoNilSeqs):
+    if threadDestructionHandlers.isNil:
+      threadDestructionHandlers = @[]
   threadDestructionHandlers.add handler
 
 template afterThreadRuns() =
diff --git a/lib/system/widestrs.nim b/lib/system/widestrs.nim
index a8b28c279..85e5e1462 100644
--- a/lib/system/widestrs.nim
+++ b/lib/system/widestrs.nim
@@ -10,13 +10,12 @@
 # Nim support for C/C++'s `wide strings`:idx:. This is part of the system
 # module! Do not import it directly!
 
-when not declared(NimString):
+when not declared(ThisIsSystem):
   {.error: "You must not import this module explicitly".}
 
 type
   Utf16Char* = distinct int16
   WideCString* = ref UncheckedArray[Utf16Char]
-{.deprecated: [TUtf16Char: Utf16Char].}
 
 proc len*(w: WideCString): int =
   ## returns the length of a widestring. This traverses the whole string to