summary refs log tree commit diff stats
path: root/lib/core
diff options
context:
space:
mode:
Diffstat (limited to 'lib/core')
-rw-r--r--lib/core/hotcodereloading.nim41
-rw-r--r--lib/core/locks.nim214
-rw-r--r--lib/core/macrocache.nim246
-rw-r--r--[-rwxr-xr-x]lib/core/macros.nim1854
-rw-r--r--lib/core/rlocks.nim57
-rw-r--r--[-rwxr-xr-x]lib/core/typeinfo.nim850
-rw-r--r--lib/core/unsigned.nim59
7 files changed, 2516 insertions, 805 deletions
diff --git a/lib/core/hotcodereloading.nim b/lib/core/hotcodereloading.nim
new file mode 100644
index 000000000..3a876885c
--- /dev/null
+++ b/lib/core/hotcodereloading.nim
@@ -0,0 +1,41 @@
+#
+#
+#            Nim's Runtime Library
+#        (c) Copyright 2019 Nim contributors
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+## Unstable API.
+
+when defined(hotcodereloading):
+  import
+    std/macros
+
+  template beforeCodeReload*(body: untyped) =
+    hcrAddEventHandler(true, proc = body) {.executeOnReload.}
+
+  template afterCodeReload*(body: untyped) =
+    hcrAddEventHandler(false, proc = body) {.executeOnReload.}
+
+  macro hasModuleChanged*(module: typed): untyped =
+    if module.kind != nnkSym or module.symKind != nskModule:
+      error "hasModuleChanged expects a module symbol", module
+    return newCall(bindSym"hcrHasModuleChanged", newLit(module.signatureHash))
+
+  proc hasAnyModuleChanged*(): bool = hcrReloadNeeded()
+
+  when not defined(js):
+    template performCodeReload* =
+      when isMainModule:
+        {.warning: "Code residing in the main module will not be changed from calling a code-reload".}
+      hcrPerformCodeReload()
+  else:
+    template performCodeReload* = discard
+else:
+  template beforeCodeReload*(body: untyped) = discard
+  template afterCodeReload*(body: untyped) = discard
+  template hasModuleChanged*(module: typed): bool = false
+  proc hasAnyModuleChanged*(): bool = false
+  template performCodeReload*() = discard
diff --git a/lib/core/locks.nim b/lib/core/locks.nim
index 071bde93a..523727479 100644
--- a/lib/core/locks.nim
+++ b/lib/core/locks.nim
@@ -1,166 +1,90 @@
 #
 #
-#            Nimrod's Runtime Library
-#        (c) Copyright 2012 Andreas Rumpf
+#            Nim's Runtime Library
+#        (c) Copyright 2015 Andreas Rumpf
 #
 #    See the file "copying.txt", included in this
 #    distribution, for details about the copyright.
 #
 
-## This module contains Nimrod's support for locks and condition vars.
-## If the symbol ``preventDeadlocks`` is defined
-## (compiled with ``-d:preventDeadlocks``) special logic is added to
-## every ``acquire``, ``tryAcquire`` and ``release`` action that ensures at
-## runtime that no deadlock can occur. This is achieved by forcing a thread
-## to release its locks should it be part of a deadlock. This thread then
-## re-acquires its locks and proceeds.
+## This module contains Nim's support for locks and condition vars.
 
-include "system/syslocks"
+#[
+for js, for now we treat locks as noop's to avoid pushing `when defined(js)`
+in client code that uses locks.
+]#
+
+when not compileOption("threads") and not defined(nimdoc):
+  when false: # fix #12330
+    {.error: "Locks requires --threads:on option.".}
+
+import std/private/syslocks
 
 type
-  TLock* = TSysLock ## Nimrod lock; whether this is re-entrant
-                    ## or not is unspecified! However, compilation
-                    ## in preventDeadlocks-mode guarantees re-entrancy.
-  TCond* = TSysCond ## Nimrod condition variable
-  
-  FLock* = object of TEffect ## effect that denotes that some lock operation
-                             ## is performed
-  FAquireLock* = object of FLock  ## effect that denotes that some lock is
-                                  ## aquired
-  FReleaseLock* = object of FLock ## effect that denotes that some lock is
-                                  ## released
-  
-const
-  noDeadlocks = defined(preventDeadlocks)
-  maxLocksPerThread* = 10 ## max number of locks a thread can hold
-                          ## at the same time; this limit is only relevant
-                          ## when compiled with ``-d:preventDeadlocks``.
-
-var
-  deadlocksPrevented*: int ## counts the number of times a 
-                           ## deadlock has been prevented
-
-when noDeadlocks:
-  var
-    locksLen {.threadvar.}: int
-    locks {.threadvar.}: array [0..MaxLocksPerThread-1, pointer]
-
-  proc OrderedLocks(): bool = 
-    for i in 0 .. locksLen-2:
-      if locks[i] >= locks[i+1]: return false
-    result = true
-
-proc InitLock*(lock: var TLock) {.inline.} =
+  Lock* = SysLock ## Nim lock; whether this is re-entrant
+                  ## or not is unspecified!
+  Cond* = SysCond ## Nim condition variable
+
+{.push stackTrace: off.}
+
+
+proc `$`*(lock: Lock): string =
+  # workaround bug #14873
+  result = "()"
+
+proc initLock*(lock: var Lock) {.inline.} =
   ## Initializes the given lock.
-  InitSysLock(lock)
+  when not defined(js):
+    initSysLock(lock)
 
-proc DeinitLock*(lock: var TLock) {.inline.} =
+proc deinitLock*(lock: Lock) {.inline.} =
   ## Frees the resources associated with the lock.
-  DeinitSys(lock)
+  deinitSys(lock)
 
-proc TryAcquire*(lock: var TLock): bool {.tags: [FAquireLock].} = 
+proc tryAcquire*(lock: var Lock): bool {.inline.} =
   ## Tries to acquire the given lock. Returns `true` on success.
-  result = TryAcquireSys(lock)
-  when noDeadlocks:
-    if not result: return
-    # we have to add it to the ordered list. Oh, and we might fail if
-    # there is no space in the array left ...
-    if locksLen >= len(locks):
-      ReleaseSys(lock)
-      raise newException(EResourceExhausted, "cannot acquire additional lock")
-    # find the position to add:
-    var p = addr(lock)
-    var L = locksLen-1
-    var i = 0
-    while i <= L:
-      assert locks[i] != nil
-      if locks[i] < p: inc(i) # in correct order
-      elif locks[i] == p: return # thread already holds lock
-      else:
-        # do the crazy stuff here:
-        while L >= i:
-          locks[L+1] = locks[L]
-          dec L
-        locks[i] = p
-        inc(locksLen)
-        assert OrderedLocks()
-        return
-    # simply add to the end:
-    locks[locksLen] = p
-    inc(locksLen)
-    assert OrderedLocks()
-
-proc Acquire*(lock: var TLock) {.tags: [FAquireLock].} =
+  result = tryAcquireSys(lock)
+
+proc acquire*(lock: var Lock) {.inline.} =
   ## Acquires the given lock.
-  when nodeadlocks:
-    var p = addr(lock)
-    var L = locksLen-1
-    var i = 0
-    while i <= L:
-      assert locks[i] != nil
-      if locks[i] < p: inc(i) # in correct order
-      elif locks[i] == p: return # thread already holds lock
-      else:
-        # do the crazy stuff here:
-        if locksLen >= len(locks):
-          raise newException(EResourceExhausted, 
-              "cannot acquire additional lock")
-        while L >= i:
-          ReleaseSys(cast[ptr TSysLock](locks[L])[])
-          locks[L+1] = locks[L]
-          dec L
-        # acquire the current lock:
-        AcquireSys(lock)
-        locks[i] = p
-        inc(locksLen)
-        # acquire old locks in proper order again:
-        L = locksLen-1
-        inc i
-        while i <= L:
-          AcquireSys(cast[ptr TSysLock](locks[i])[])
-          inc(i)
-        # DANGER: We can only modify this global var if we gained every lock!
-        # NO! We need an atomic increment. Crap.
-        discard system.atomicInc(deadlocksPrevented, 1)
-        assert OrderedLocks()
-        return
-        
-    # simply add to the end:
-    if locksLen >= len(locks):
-      raise newException(EResourceExhausted, "cannot acquire additional lock")
-    AcquireSys(lock)
-    locks[locksLen] = p
-    inc(locksLen)
-    assert OrderedLocks()
-  else:
-    AcquireSys(lock)
-  
-proc Release*(lock: var TLock) {.tags: [FReleaseLock].} =
+  when not defined(js):
+    acquireSys(lock)
+
+proc release*(lock: var Lock) {.inline.} =
   ## Releases the given lock.
-  when nodeadlocks:
-    var p = addr(lock)
-    var L = locksLen
-    for i in countdown(L-1, 0):
-      if locks[i] == p: 
-        for j in i..L-2: locks[j] = locks[j+1]
-        dec locksLen
-        break
-  ReleaseSys(lock)
-
-
-proc InitCond*(cond: var TCond) {.inline.} =
+  when not defined(js):
+    releaseSys(lock)
+
+
+proc initCond*(cond: var Cond) {.inline.} =
   ## Initializes the given condition variable.
-  InitSysCond(cond)
+  initSysCond(cond)
 
-proc DeinitCond*(cond: var TCond) {.inline.} =
-  ## Frees the resources associated with the lock.
-  DeinitSysCond(cond)
-
-proc wait*(cond: var TCond, lock: var TLock) {.inline.} =
-  ## waits on the condition variable `cond`. 
-  WaitSysCond(cond, lock)
-  
-proc signal*(cond: var TCond) {.inline.} =
-  ## sends a signal to the condition variable `cond`. 
+proc deinitCond*(cond: Cond) {.inline.} =
+  ## Frees the resources associated with the condition variable.
+  deinitSysCond(cond)
+
+proc wait*(cond: var Cond, lock: var Lock) {.inline.} =
+  ## Waits on the condition variable `cond`.
+  waitSysCond(cond, lock)
+
+proc signal*(cond: var Cond) {.inline.} =
+  ## Sends a signal to the condition variable `cond`.
   signalSysCond(cond)
 
+proc broadcast*(cond: var Cond) {.inline.} =
+  ## Unblocks all threads currently blocked on the
+  ## specified condition variable `cond`.
+  broadcastSysCond(cond)
+
+template withLock*(a: Lock, body: untyped) =
+  ## Acquires the given lock, executes the statements in body and
+  ## releases the lock after the statements finish executing.
+  acquire(a)
+  {.locks: [a].}:
+    try:
+      body
+    finally:
+      release(a)
+
+{.pop.}
diff --git a/lib/core/macrocache.nim b/lib/core/macrocache.nim
new file mode 100644
index 000000000..39999fa11
--- /dev/null
+++ b/lib/core/macrocache.nim
@@ -0,0 +1,246 @@
+#
+#
+#            Nim's Runtime Library
+#        (c) Copyright 2018 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+## This module provides an API for macros to collect compile-time information
+## across module boundaries. It should be used instead of global `{.compileTime.}`
+## variables as those break incremental compilation.
+##
+## The main feature of this module is that if you create `CacheTable`s or
+## any other `Cache` types with the same name in different modules, their
+## content will be shared, meaning that you can fill a `CacheTable` in
+## one module, and iterate over its contents in another.
+
+runnableExamples:
+  import std/macros
+
+  const mcTable = CacheTable"myTable"
+  const mcSeq = CacheSeq"mySeq"
+  const mcCounter = CacheCounter"myCounter"
+
+  static:
+    # add new key "val" with the value `myval`
+    let myval = newLit("hello ic")
+    mcTable["val"] = myval
+    assert mcTable["val"].kind == nnkStrLit
+
+  # Can access the same cache from different static contexts
+  # All the information is retained
+  static:
+    # get value from `mcTable` and add it to `mcSeq`
+    mcSeq.add(mcTable["val"])
+    assert mcSeq.len == 1
+
+  static:
+    assert mcSeq[0].strVal == "hello ic"
+
+    # increase `mcCounter` by 3
+    mcCounter.inc(3)
+    assert mcCounter.value == 3
+
+
+type
+  CacheSeq* = distinct string
+    ## Compile-time sequence of `NimNode`s.
+  CacheTable* = distinct string
+    ## Compile-time table of key-value pairs.
+    ##
+    ## Keys are `string`s and values are `NimNode`s.
+  CacheCounter* = distinct string
+    ## Compile-time counter, uses `int` for storing the count.
+
+proc value*(c: CacheCounter): int {.magic: "NccValue".} =
+  ## Returns the value of a counter `c`.
+  runnableExamples:
+    static:
+      let counter = CacheCounter"valTest"
+      # default value is 0
+      assert counter.value == 0
+
+      inc counter
+      assert counter.value == 1
+
+proc inc*(c: CacheCounter; by = 1) {.magic: "NccInc".} =
+  ## Increments the counter `c` with the value `by`.
+  runnableExamples:
+    static:
+      let counter = CacheCounter"incTest"
+      inc counter
+      inc counter, 5
+
+      assert counter.value == 6
+
+proc add*(s: CacheSeq; value: NimNode) {.magic: "NcsAdd".} =
+  ## Adds `value` to `s`.
+  runnableExamples:
+    import std/macros
+    const mySeq = CacheSeq"addTest"
+
+    static:
+      mySeq.add(newLit(5))
+      mySeq.add(newLit("hello ic"))
+
+      assert mySeq.len == 2
+      assert mySeq[1].strVal == "hello ic"
+
+proc incl*(s: CacheSeq; value: NimNode) {.magic: "NcsIncl".} =
+  ## Adds `value` to `s`.
+  ##
+  ## .. hint:: This doesn't do anything if `value` is already in `s`.
+  runnableExamples:
+    import std/macros
+    const mySeq = CacheSeq"inclTest"
+
+    static:
+      mySeq.incl(newLit(5))
+      mySeq.incl(newLit(5))
+
+      # still one element
+      assert mySeq.len == 1
+
+proc len*(s: CacheSeq): int {.magic: "NcsLen".} =
+  ## Returns the length of `s`.
+  runnableExamples:
+    import std/macros
+
+    const mySeq = CacheSeq"lenTest"
+    static:
+      let val = newLit("helper")
+      mySeq.add(val)
+      assert mySeq.len == 1
+
+      mySeq.add(val)
+      assert mySeq.len == 2
+
+proc `[]`*(s: CacheSeq; i: int): NimNode {.magic: "NcsAt".} =
+  ## Returns the `i`th value from `s`.
+  runnableExamples:
+    import std/macros
+
+    const mySeq = CacheSeq"subTest"
+    static:
+      mySeq.add(newLit(42))
+      assert mySeq[0].intVal == 42
+
+proc `[]`*(s: CacheSeq; i: BackwardsIndex): NimNode =
+  ## Returns the `i`th last value from `s`.
+  runnableExamples:
+    import std/macros
+
+    const mySeq = CacheSeq"backTest"
+    static:
+      mySeq &= newLit(42)
+      mySeq &= newLit(7)
+      assert mySeq[^1].intVal == 7  # Last item
+      assert mySeq[^2].intVal == 42 # Second last item
+  s[s.len - int(i)]
+
+iterator items*(s: CacheSeq): NimNode =
+  ## Iterates over each item in `s`.
+  runnableExamples:
+    import std/macros
+    const myseq = CacheSeq"itemsTest"
+
+    static:
+      myseq.add(newLit(5))
+      myseq.add(newLit(42))
+
+      for val in myseq:
+        # check that all values in `myseq` are int literals
+        assert val.kind == nnkIntLit
+
+  for i in 0 ..< len(s): yield s[i]
+
+proc `[]=`*(t: CacheTable; key: string, value: NimNode) {.magic: "NctPut".} =
+  ## Inserts a `(key, value)` pair into `t`.
+  ##
+  ## .. warning:: `key` has to be unique! Assigning `value` to a `key` that is already
+  ##   in the table will result in a compiler error.
+  runnableExamples:
+    import std/macros
+
+    const mcTable = CacheTable"subTest"
+    static:
+      # assign newLit(5) to the key "value"
+      mcTable["value"] = newLit(5)
+
+      # check that we can get the value back
+      assert mcTable["value"].kind == nnkIntLit
+
+proc len*(t: CacheTable): int {.magic: "NctLen".} =
+  ## Returns the number of elements in `t`.
+  runnableExamples:
+    import std/macros
+
+    const dataTable = CacheTable"lenTest"
+    static:
+      dataTable["key"] = newLit(5)
+      assert dataTable.len == 1
+
+proc `[]`*(t: CacheTable; key: string): NimNode {.magic: "NctGet".} =
+  ## Retrieves the `NimNode` value at `t[key]`.
+  runnableExamples:
+    import std/macros
+
+    const mcTable = CacheTable"subTest"
+    static:
+      mcTable["toAdd"] = newStmtList()
+
+      # get the NimNode back
+      assert mcTable["toAdd"].kind == nnkStmtList
+
+proc hasKey*(t: CacheTable; key: string): bool =
+  ## Returns true if `key` is in the table `t`.
+  ##
+  ## See also:
+  ## * [contains proc][contains(CacheTable, string)] for use with the `in` operator
+  runnableExamples:
+    import std/macros
+    const mcTable = CacheTable"hasKeyEx"
+    static:
+      assert not mcTable.hasKey("foo")
+      mcTable["foo"] = newEmptyNode()
+      # Will now be true since we inserted a value
+      assert mcTable.hasKey("foo")
+  discard "Implemented in vmops"
+
+proc contains*(t: CacheTable; key: string): bool {.inline.} =
+  ## Alias of [hasKey][hasKey(CacheTable, string)] for use with the `in` operator.
+  runnableExamples:
+    import std/macros
+    const mcTable = CacheTable"containsEx"
+    static:
+      mcTable["foo"] = newEmptyNode()
+      # Will be true since we gave it a value before
+      assert "foo" in mcTable
+  t.hasKey(key)
+
+proc hasNext(t: CacheTable; iter: int): bool {.magic: "NctHasNext".}
+proc next(t: CacheTable; iter: int): (string, NimNode, int) {.magic: "NctNext".}
+
+iterator pairs*(t: CacheTable): (string, NimNode) =
+  ## Iterates over all `(key, value)` pairs in `t`.
+  runnableExamples:
+    import std/macros
+    const mytabl = CacheTable"values"
+
+    static:
+      mytabl["intVal"] = newLit(5)
+      mytabl["otherVal"] = newLit(6)
+      for key, val in mytabl:
+        # make sure that we actually get the same keys
+        assert key in ["intVal", "otherVal"]
+
+        # all vals are int literals
+        assert val.kind == nnkIntLit
+
+  var h = 0
+  while hasNext(t, h):
+    let (a, b, h2) = next(t, h)
+    yield (a, b)
+    h = h2
diff --git a/lib/core/macros.nim b/lib/core/macros.nim
index 8ed9be2f4..7646b165c 100755..100644
--- a/lib/core/macros.nim
+++ b/lib/core/macros.nim
@@ -1,30 +1,45 @@
 #
 #
-#            Nimrod's Runtime Library
-#        (c) Copyright 2013 Andreas Rumpf
+#            Nim's Runtime Library
+#        (c) Copyright 2015 Andreas Rumpf
 #
 #    See the file "copying.txt", included in this
 #    distribution, for details about the copyright.
 #
 
+include "system/inclrtl"
+import std/private/since
+
+when defined(nimPreviewSlimSystem):
+  import std/[assertions, formatfloat]
+
 
 ## This module contains the interface to the compiler's abstract syntax
 ## tree (`AST`:idx:). Macros operate on this tree.
+##
+## See also:
+## * `macros tutorial <tut3.html>`_
+## * `macros section in Nim manual <manual.html#macros>`_
+
+## .. include:: ../../doc/astspec.txt
 
-## .. include:: ../doc/astspec.txt
+## .. importdoc:: system.nim
+
+# If you look for the implementation of the magic symbol
+# ``{.magic: "Foo".}``, search for `mFoo` and `opcFoo`.
 
 type
-  TNimrodNodeKind* = enum
+  NimNodeKind* = enum
     nnkNone, nnkEmpty, nnkIdent, nnkSym,
     nnkType, nnkCharLit, nnkIntLit, nnkInt8Lit,
     nnkInt16Lit, nnkInt32Lit, nnkInt64Lit, nnkUIntLit, nnkUInt8Lit,
     nnkUInt16Lit, nnkUInt32Lit, nnkUInt64Lit, nnkFloatLit,
     nnkFloat32Lit, nnkFloat64Lit, nnkFloat128Lit, nnkStrLit, nnkRStrLit,
-    nnkTripleStrLit, nnkNilLit, nnkMetaNode, nnkDotCall,
+    nnkTripleStrLit, nnkNilLit, nnkComesFrom, nnkDotCall,
     nnkCommand, nnkCall, nnkCallStrLit, nnkInfix,
-    nnkPrefix, nnkPostfix, nnkHiddenCallConv, 
+    nnkPrefix, nnkPostfix, nnkHiddenCallConv,
     nnkExprEqExpr,
-    nnkExprColonExpr, nnkIdentDefs, nnkVarTuple, 
+    nnkExprColonExpr, nnkIdentDefs, nnkVarTuple,
     nnkPar, nnkObjConstr, nnkCurly, nnkCurlyExpr,
     nnkBracket, nnkBracketExpr, nnkPragmaExpr, nnkRange,
     nnkDotExpr, nnkCheckedFieldExpr, nnkDerefExpr, nnkIfExpr,
@@ -38,365 +53,1760 @@ type
     nnkObjUpConv, nnkChckRangeF, nnkChckRange64, nnkChckRange,
     nnkStringToCString, nnkCStringToString, nnkAsgn,
     nnkFastAsgn, nnkGenericParams, nnkFormalParams, nnkOfInherit,
-    nnkModule, nnkProcDef, nnkMethodDef, nnkConverterDef,
+    nnkImportAs, nnkProcDef, nnkMethodDef, nnkConverterDef,
     nnkMacroDef, nnkTemplateDef, nnkIteratorDef, nnkOfBranch,
     nnkElifBranch, nnkExceptBranch, nnkElse,
     nnkAsmStmt, nnkPragma, nnkPragmaBlock, nnkIfStmt, nnkWhenStmt,
     nnkForStmt, nnkParForStmt, nnkWhileStmt, nnkCaseStmt,
     nnkTypeSection, nnkVarSection, nnkLetSection, nnkConstSection,
     nnkConstDef, nnkTypeDef,
-    nnkYieldStmt, nnkTryStmt, nnkFinally, nnkRaiseStmt,
+    nnkYieldStmt, nnkDefer, nnkTryStmt, nnkFinally, nnkRaiseStmt,
     nnkReturnStmt, nnkBreakStmt, nnkContinueStmt, nnkBlockStmt, nnkStaticStmt,
-    nnkDiscardStmt, nnkStmtList, 
-    
+    nnkDiscardStmt, nnkStmtList,
     nnkImportStmt,
     nnkImportExceptStmt,
     nnkExportStmt,
     nnkExportExceptStmt,
     nnkFromStmt,
     nnkIncludeStmt,
-    
-    nnkBindStmt, nnkMixinStmt,
+    nnkBindStmt, nnkMixinStmt, nnkUsingStmt,
     nnkCommentStmt, nnkStmtListExpr, nnkBlockExpr,
-    nnkStmtListType, nnkBlockType, nnkTypeOfExpr, nnkObjectTy,
-    nnkTupleTy, nnkRecList, nnkRecCase, nnkRecWhen,
+    nnkStmtListType, nnkBlockType,
+    nnkWith, nnkWithout,
+    nnkTypeOfExpr, nnkObjectTy,
+    nnkTupleTy, nnkTupleClassTy, nnkTypeClassTy, nnkStaticTy,
+    nnkRecList, nnkRecCase, nnkRecWhen,
     nnkRefTy, nnkPtrTy, nnkVarTy,
-    nnkConstTy, nnkMutableTy,
+    nnkConstTy, nnkOutTy,
     nnkDistinctTy,
-    nnkProcTy, 
+    nnkProcTy,
     nnkIteratorTy,         # iterator type
-    nnkSharedTy,           # 'shared T'
+    nnkSinkAsgn,
     nnkEnumTy,
     nnkEnumFieldDef,
-    nnkArglist, nnkPattern
-    nnkReturnToken
-  TNimNodeKinds* = set[TNimrodNodeKind]
-  TNimrodTypeKind* = enum
+    nnkArgList, nnkPattern
+    nnkHiddenTryStmt,
+    nnkClosure,
+    nnkGotoState,
+    nnkState,
+    nnkBreakState,
+    nnkFuncDef,
+    nnkTupleConstr,
+    nnkError,  ## erroneous AST node
+    nnkModuleRef, nnkReplayAction, nnkNilRodNode ## internal IC nodes
+    nnkOpenSym
+
+  NimNodeKinds* = set[NimNodeKind]
+  NimTypeKind* = enum  # some types are no longer used, see ast.nim
     ntyNone, ntyBool, ntyChar, ntyEmpty,
-    ntyArrayConstr, ntyNil, ntyExpr, ntyStmt,
-    ntyTypeDesc, ntyGenericInvokation, ntyGenericBody, ntyGenericInst,
+    ntyAlias, ntyNil, ntyExpr, ntyStmt,
+    ntyTypeDesc, ntyGenericInvocation, ntyGenericBody, ntyGenericInst,
     ntyGenericParam, ntyDistinct, ntyEnum, ntyOrdinal,
     ntyArray, ntyObject, ntyTuple, ntySet,
     ntyRange, ntyPtr, ntyRef, ntyVar,
     ntySequence, ntyProc, ntyPointer, ntyOpenArray,
     ntyString, ntyCString, ntyForward, ntyInt,
     ntyInt8, ntyInt16, ntyInt32, ntyInt64,
-    ntyFloat, ntyFloat32, ntyFloat64, ntyFloat128
-  TNimTypeKinds* = set[TNimrodTypeKind]
-  TNimrodSymKind* = enum
+    ntyFloat, ntyFloat32, ntyFloat64, ntyFloat128,
+    ntyUInt, ntyUInt8, ntyUInt16, ntyUInt32, ntyUInt64,
+    ntyUnused0, ntyUnused1, ntyUnused2,
+    ntyVarargs,
+    ntyUncheckedArray,
+    ntyError,
+    ntyBuiltinTypeClass, ntyUserTypeClass, ntyUserTypeClassInst,
+    ntyCompositeTypeClass, ntyInferred, ntyAnd, ntyOr, ntyNot,
+    ntyAnything, ntyStatic, ntyFromExpr, ntyOptDeprecated, ntyVoid
+
+  TNimTypeKinds* {.deprecated.} = set[NimTypeKind]
+  NimSymKind* = enum
     nskUnknown, nskConditional, nskDynLib, nskParam,
-    nskGenericParam, nskTemp, nskType, nskConst,
-    nskVar, nskProc, nskMethod, nskIterator,
+    nskGenericParam, nskTemp, nskModule, nskType, nskVar, nskLet,
+    nskConst, nskResult,
+    nskProc, nskFunc, nskMethod, nskIterator,
     nskConverter, nskMacro, nskTemplate, nskField,
-    nskEnumField, nskForVar, nskModule, nskLabel,
+    nskEnumField, nskForVar, nskLabel,
     nskStub
-  TNimSymKinds* = set[TNimrodSymKind]
+
+  TNimSymKinds* {.deprecated.} = set[NimSymKind]
+
+const
+  nnkMutableTy* {.deprecated.} = nnkOutTy
+  nnkSharedTy* {.deprecated.} = nnkSinkAsgn
 
 type
-  TNimrodIdent* = object of TObject
-    ## represents a Nimrod identifier in the AST
+  NimIdent* {.deprecated.} = object of RootObj
+    ## Represents a Nim identifier in the AST. **Note**: This is only
+    ## rarely useful, for identifier construction from a string
+    ## use `ident"abc"`.
 
-  TNimrodSymbol {.final.} = object # hidden
-  PNimrodSymbol* {.compilerproc.} = ref TNimrodSymbol
-    ## represents a Nimrod *symbol* in the compiler; a *symbol* is a looked-up
+  NimSymObj = object # hidden
+  NimSym* {.deprecated.} = ref NimSymObj
+    ## Represents a Nim *symbol* in the compiler; a *symbol* is a looked-up
     ## *ident*.
 
+
 const
   nnkLiterals* = {nnkCharLit..nnkNilLit}
+  # see matching set CallNodes below
   nnkCallKinds* = {nnkCall, nnkInfix, nnkPrefix, nnkPostfix, nnkCommand,
-                   nnkCallStrLit}
+                   nnkCallStrLit, nnkHiddenCallConv}
+  nnkPragmaCallKinds = {nnkExprColonExpr, nnkCall, nnkCallStrLit}
+
+{.push warnings: off.}
+
+proc toNimIdent*(s: string): NimIdent {.magic: "StrToIdent", noSideEffect, deprecated:
+  "Deprecated since version 0.18.0: Use 'ident' or 'newIdentNode' instead.".}
+  ## Constructs an identifier from the string `s`.
+
+proc `==`*(a, b: NimIdent): bool {.magic: "EqIdent", noSideEffect, deprecated:
+  "Deprecated since version 0.18.1; Use '==' on 'NimNode' instead.".}
+  ## Compares two Nim identifiers.
+
+proc `==`*(a, b: NimNode): bool {.magic: "EqNimrodNode", noSideEffect.}
+  ## Compare two Nim nodes. Return true if nodes are structurally
+  ## equivalent. This means two independently created nodes can be equal.
+
+proc `==`*(a, b: NimSym): bool {.magic: "EqNimrodNode", noSideEffect, deprecated:
+  "Deprecated since version 0.18.1; Use '==(NimNode, NimNode)' instead.".}
+  ## Compares two Nim symbols.
+
+{.pop.}
+
+proc sameType*(a, b: NimNode): bool {.magic: "SameNodeType", noSideEffect.} =
+  ## Compares two Nim nodes' types. Return true if the types are the same,
+  ## e.g. true when comparing alias with original type.
+  discard
+
+proc len*(n: NimNode): int {.magic: "NLen", noSideEffect.}
+  ## Returns the number of children of `n`.
+
+proc `[]`*(n: NimNode, i: int): NimNode {.magic: "NChild", noSideEffect.}
+  ## Get `n`'s `i`'th child.
+
+proc `[]`*(n: NimNode, i: BackwardsIndex): NimNode = n[n.len - i.int]
+  ## Get `n`'s `i`'th child.
+
+template `^^`(n: NimNode, i: untyped): untyped =
+  (when i is BackwardsIndex: n.len - int(i) else: int(i))
+
+proc `[]`*[T, U: Ordinal](n: NimNode, x: HSlice[T, U]): seq[NimNode] =
+  ## Slice operation for NimNode.
+  ## Returns a seq of child of `n` who inclusive range `[n[x.a], n[x.b]]`.
+  let xa = n ^^ x.a
+  let L = (n ^^ x.b) - xa + 1
+  result = newSeq[NimNode](L)
+  for i in 0..<L:
+    result[i] = n[i + xa]
+
+proc `[]=`*(n: NimNode, i: int, child: NimNode) {.magic: "NSetChild",
+  noSideEffect.}
+  ## Set `n`'s `i`'th child to `child`.
+
+proc `[]=`*(n: NimNode, i: BackwardsIndex, child: NimNode) =
+  ## Set `n`'s `i`'th child to `child`.
+  n[n.len - i.int] = child
+
+template `or`*(x, y: NimNode): NimNode =
+  ## Evaluate `x` and when it is not an empty node, return
+  ## it. Otherwise evaluate to `y`. Can be used to chain several
+  ## expressions to get the first expression that is not empty.
+  ##   ```nim
+  ##   let node = mightBeEmpty() or mightAlsoBeEmpty() or fallbackNode
+  ##   ```
+
+  let arg = x
+  if arg != nil and arg.kind != nnkEmpty:
+    arg
+  else:
+    y
+
+proc add*(father, child: NimNode): NimNode {.magic: "NAdd", discardable,
+  noSideEffect.}
+  ## Adds the `child` to the `father` node. Returns the
+  ## father node so that calls can be nested.
+
+proc add*(father: NimNode, children: varargs[NimNode]): NimNode {.
+  magic: "NAddMultiple", discardable, noSideEffect.}
+  ## Adds each child of `children` to the `father` node.
+  ## Returns the `father` node so that calls can be nested.
+
+proc del*(father: NimNode, idx = 0, n = 1) {.magic: "NDel", noSideEffect.}
+  ## Deletes `n` children of `father` starting at index `idx`.
+
+proc kind*(n: NimNode): NimNodeKind {.magic: "NKind", noSideEffect.}
+  ## Returns the `kind` of the node `n`.
+
+proc intVal*(n: NimNode): BiggestInt {.magic: "NIntVal", noSideEffect.}
+  ## Returns an integer value from any integer literal or enum field symbol.
+
+proc floatVal*(n: NimNode): BiggestFloat {.magic: "NFloatVal", noSideEffect.}
+  ## Returns a float from any floating point literal.
+
+
+proc symKind*(symbol: NimNode): NimSymKind {.magic: "NSymKind", noSideEffect.}
+proc getImpl*(symbol: NimNode): NimNode {.magic: "GetImpl", noSideEffect.}
+  ## Returns a copy of the declaration of a symbol or `nil`.
+proc strVal*(n: NimNode): string  {.magic: "NStrVal", noSideEffect.}
+  ## Returns the string value of an identifier, symbol, comment, or string literal.
+  ##
+  ## See also:
+  ## * `strVal= proc<#strVal=,NimNode,string>`_ for setting the string value.
 
-proc `[]`*(n: PNimrodNode, i: int): PNimrodNode {.magic: "NChild".}
-  ## get `n`'s `i`'th child.
+{.push warnings: off.} # silence `deprecated`
 
-proc `[]=`*(n: PNimrodNode, i: int, child: PNimrodNode) {.magic: "NSetChild".}
-  ## set `n`'s `i`'th child to `child`.
+proc ident*(n: NimNode): NimIdent {.magic: "NIdent", noSideEffect, deprecated:
+  "Deprecated since version 0.18.1; All functionality is defined on 'NimNode'.".}
 
-proc `!`*(s: string): TNimrodIdent {.magic: "StrToIdent".}
-  ## constructs an identifier from the string `s`
+proc symbol*(n: NimNode): NimSym {.magic: "NSymbol", noSideEffect, deprecated:
+  "Deprecated since version 0.18.1; All functionality is defined on 'NimNode'.".}
 
-proc `$`*(i: TNimrodIdent): string {.magic: "IdentToStr".}
-  ## converts a Nimrod identifier to a string
+proc getImpl*(s: NimSym): NimNode {.magic: "GetImpl", noSideEffect, deprecated: "use `getImpl: NimNode -> NimNode` instead".}
 
-proc `$`*(s: PNimrodSymbol): string {.magic: "IdentToStr".}
-  ## converts a Nimrod symbol to a string
+proc `$`*(i: NimIdent): string {.magic: "NStrVal", noSideEffect, deprecated:
+  "Deprecated since version 0.18.1; Use 'strVal' instead.".}
+  ## Converts a Nim identifier to a string.
 
-proc `==`*(a, b: TNimrodIdent): bool {.magic: "EqIdent", noSideEffect.}
-  ## compares two Nimrod identifiers
+proc `$`*(s: NimSym): string {.magic: "NStrVal", noSideEffect, deprecated:
+  "Deprecated since version 0.18.1; Use 'strVal' instead.".}
+  ## Converts a Nim symbol to a string.
 
-proc `==`*(a, b: PNimrodNode): bool {.magic: "EqNimrodNode", noSideEffect.}
-  ## compares two Nimrod nodes
+{.pop.}
 
-proc len*(n: PNimrodNode): int {.magic: "NLen".}
-  ## returns the number of children of `n`.
+when (NimMajor, NimMinor, NimPatch) >= (1, 3, 5) or defined(nimSymImplTransform):
+  proc getImplTransformed*(symbol: NimNode): NimNode {.magic: "GetImplTransf", noSideEffect.}
+    ## For a typed proc returns the AST after transformation pass; this is useful
+    ## for debugging how the compiler transforms code (e.g.: `defer`, `for`) but
+    ## note that code transformations are implementation dependent and subject to change.
+    ## See an example in `tests/macros/tmacros_various.nim`.
 
-proc add*(father, child: PNimrodNode) {.magic: "NAdd".}
-  ## adds the `child` to the `father` node
+proc owner*(sym: NimNode): NimNode {.magic: "SymOwner", noSideEffect, deprecated.}
+  ## Accepts a node of kind `nnkSym` and returns its owner's symbol.
+  ## The meaning of 'owner' depends on `sym`'s `NimSymKind` and declaration
+  ## context. For top level declarations this is an `nskModule` symbol,
+  ## for proc local variables an `nskProc` symbol, for enum/object fields an
+  ## `nskType` symbol, etc. For symbols without an owner, `nil` is returned.
+  ##
+  ## See also:
+  ## * `symKind proc<#symKind,NimNode>`_ to get the kind of a symbol
+  ## * `getImpl proc<#getImpl,NimNode>`_ to get the declaration of a symbol
+
+proc isInstantiationOf*(instanceProcSym, genProcSym: NimNode): bool {.magic: "SymIsInstantiationOf", noSideEffect.}
+  ## Checks if a proc symbol is an instance of the generic proc symbol.
+  ## Useful to check proc symbols against generic symbols
+  ## returned by `bindSym`.
+
+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
+  ## API can be used to traverse types. Recursive types are flattened for you
+  ## so there is no danger of infinite recursions during traversal. To
+  ## resolve recursive types, you have to call 'getType' again. To see what
+  ## kind of type it is, call `typeKind` on getType's result.
+
+proc getType*(n: typedesc): NimNode {.magic: "NGetType", noSideEffect.}
+  ## Version of `getType` which takes a `typedesc`.
+
+proc typeKind*(n: NimNode): NimTypeKind {.magic: "NGetType", noSideEffect.}
+  ## Returns the type kind of the node 'n' that should represent a type, that
+  ## means the node should have been obtained via `getType`.
+
+proc getTypeInst*(n: NimNode): NimNode {.magic: "NGetType", noSideEffect.} =
+  ## Returns the `type`:idx: of a node in a form matching the way the
+  ## type instance was declared in the code.
+  runnableExamples:
+    type
+      Vec[N: static[int], T] = object
+        arr: array[N, T]
+      Vec4[T] = Vec[4, T]
+      Vec4f = Vec4[float32]
+    var a: Vec4f
+    var b: Vec4[float32]
+    var c: Vec[4, float32]
+    macro dumpTypeInst(x: typed): untyped =
+      newLit(x.getTypeInst.repr)
+    doAssert(dumpTypeInst(a) == "Vec4f")
+    doAssert(dumpTypeInst(b) == "Vec4[float32]")
+    doAssert(dumpTypeInst(c) == "Vec[4, float32]")
+
+proc getTypeInst*(n: typedesc): NimNode {.magic: "NGetType", noSideEffect.}
+  ## Version of `getTypeInst` which takes a `typedesc`.
+
+proc getTypeImpl*(n: NimNode): NimNode {.magic: "NGetType", noSideEffect.} =
+  ## Returns the `type`:idx: of a node in a form matching the implementation
+  ## of the type. Any intermediate aliases are expanded to arrive at the final
+  ## type implementation. You can instead use `getImpl` on a symbol if you
+  ## want to find the intermediate aliases.
+  runnableExamples:
+    type
+      Vec[N: static[int], T] = object
+        arr: array[N, T]
+      Vec4[T] = Vec[4, T]
+      Vec4f = Vec4[float32]
+    var a: Vec4f
+    var b: Vec4[float32]
+    var c: Vec[4, float32]
+    macro dumpTypeImpl(x: typed): untyped =
+      newLit(x.getTypeImpl.repr)
+    let t = """
+object
+  arr: array[0 .. 3, float32]"""
+    doAssert(dumpTypeImpl(a) == t)
+    doAssert(dumpTypeImpl(b) == t)
+    doAssert(dumpTypeImpl(c) == t)
+
+proc signatureHash*(n: NimNode): string {.magic: "NSigHash", noSideEffect.}
+  ## Returns a stable identifier derived from the signature of a symbol.
+  ## The signature combines many factors such as the type of the symbol,
+  ## the owning module of the symbol and others. The same identifier is
+  ## used in the back-end to produce the mangled symbol name.
 
-proc add*(father: PNimrodNode, children: varargs[PNimrodNode]) {.
-  magic: "NAddMultiple".}
-  ## adds each child of `children` to the `father` node
+proc symBodyHash*(s: NimNode): string {.noSideEffect.} =
+  ## Returns a stable digest for symbols derived not only from type signature
+  ## and owning module, but also implementation body. All procs/variables used in
+  ## the implementation of this symbol are hashed recursively as well, including
+  ## magics from system module.
+  discard
 
-proc del*(father: PNimrodNode, idx = 0, n = 1) {.magic: "NDel".}
-  ## deletes `n` children of `father` starting at index `idx`.
+proc getTypeImpl*(n: typedesc): NimNode {.magic: "NGetType", noSideEffect.}
+  ## Version of `getTypeImpl` which takes a `typedesc`.
+
+proc `intVal=`*(n: NimNode, val: BiggestInt) {.magic: "NSetIntVal", noSideEffect.}
+proc `floatVal=`*(n: NimNode, val: BiggestFloat) {.magic: "NSetFloatVal", noSideEffect.}
+
+{.push warnings: off.}
+
+proc `symbol=`*(n: NimNode, val: NimSym) {.magic: "NSetSymbol", noSideEffect, deprecated:
+  "Deprecated since version 0.18.1; Generate a new 'NimNode' with 'genSym' instead.".}
+
+proc `ident=`*(n: NimNode, val: NimIdent) {.magic: "NSetIdent", noSideEffect, deprecated:
+  "Deprecated since version 0.18.1; Generate a new 'NimNode' with 'ident(string)' instead.".}
+
+{.pop.}
+
+proc `strVal=`*(n: NimNode, val: string) {.magic: "NSetStrVal", noSideEffect.}
+  ## Sets the string value of a string literal or comment.
+  ## Setting `strVal` is disallowed for `nnkIdent` and `nnkSym` nodes; a new node
+  ## must be created using `ident` or `bindSym` instead.
+  ##
+  ## See also:
+  ## * `strVal proc<#strVal,NimNode>`_ for getting the string value.
+  ## * `ident proc<#ident,string>`_ for creating an identifier.
+  ## * `bindSym proc<#bindSym%2C%2CBindSymRule>`_ for binding a symbol.
+
+proc newNimNode*(kind: NimNodeKind,
+                 lineInfoFrom: NimNode = nil): NimNode
+  {.magic: "NNewNimNode", noSideEffect.}
+  ## Creates a new AST node of the specified kind.
+  ##
+  ## The `lineInfoFrom` parameter is used for line information when the
+  ## produced code crashes. You should ensure that it is set to a node that
+  ## you are transforming.
 
-proc kind*(n: PNimrodNode): TNimrodNodeKind {.magic: "NKind".}
-  ## returns the `kind` of the node `n`.
+proc copyNimNode*(n: NimNode): NimNode {.magic: "NCopyNimNode", noSideEffect.} =
+  ## Creates a new AST node by copying the node `n`. Note that unlike `copyNimTree`,
+  ## child nodes of `n` are not copied.
+  runnableExamples:
+    macro foo(x: typed) =
+      var s = copyNimNode(x)
+      doAssert s.len == 0
+      doAssert s.kind == nnkStmtList
 
-proc intVal*(n: PNimrodNode): biggestInt {.magic: "NIntVal".}
-proc floatVal*(n: PNimrodNode): biggestFloat {.magic: "NFloatVal".}
-proc symbol*(n: PNimrodNode): PNimrodSymbol {.magic: "NSymbol".}
-proc ident*(n: PNimrodNode): TNimrodIdent {.magic: "NIdent".}
-proc typ*(n: PNimrodNode): typedesc {.magic: "NGetType".}
-proc strVal*(n: PNimrodNode): string  {.magic: "NStrVal".}
+    foo:
+      let x = 12
+      echo x
 
-proc `intVal=`*(n: PNimrodNode, val: biggestInt) {.magic: "NSetIntVal".}
-proc `floatVal=`*(n: PNimrodNode, val: biggestFloat) {.magic: "NSetFloatVal".}
-proc `symbol=`*(n: PNimrodNode, val: PNimrodSymbol) {.magic: "NSetSymbol".}
-proc `ident=`*(n: PNimrodNode, val: TNimrodIdent) {.magic: "NSetIdent".}
-proc `typ=`*(n: PNimrodNode, typ: typedesc) {.magic: "NSetType".}
-proc `strVal=`*(n: PNimrodNode, val: string) {.magic: "NSetStrVal".}
+proc copyNimTree*(n: NimNode): NimNode {.magic: "NCopyNimTree", noSideEffect.} =
+  ## Creates a new AST node by recursively copying the node `n`. Note that
+  ## unlike `copyNimNode`, this copies `n`, the children of `n`, etc.
+  runnableExamples:
+    macro foo(x: typed) =
+      var s = copyNimTree(x)
+      doAssert s.len == 2
+      doAssert s.kind == nnkStmtList
 
-proc newNimNode*(kind: TNimrodNodeKind,
-                 n: PNimrodNode=nil): PNimrodNode {.magic: "NNewNimNode".}
+    foo:
+      let x = 12
+      echo x
 
-proc copyNimNode*(n: PNimrodNode): PNimrodNode {.magic: "NCopyNimNode".}
-proc copyNimTree*(n: PNimrodNode): PNimrodNode {.magic: "NCopyNimTree".}
+when defined(nimHasNoReturnError):
+  {.pragma: errorNoReturn, noreturn.}
+else:
+  {.pragma: errorNoReturn.}
 
-proc error*(msg: string) {.magic: "NError".}
-  ## writes an error message at compile time
+proc error*(msg: string, n: NimNode = nil) {.magic: "NError", benign, errorNoReturn.}
+  ## Writes an error message at compile time. The optional `n: NimNode`
+  ## parameter is used as the source for file and line number information in
+  ## the compilation error message.
 
-proc warning*(msg: string) {.magic: "NWarning".}
-  ## writes a warning message at compile time
+proc warning*(msg: string, n: NimNode = nil) {.magic: "NWarning", benign.}
+  ## Writes a warning message at compile time.
 
-proc hint*(msg: string) {.magic: "NHint".}
-  ## writes a hint message at compile time
+proc hint*(msg: string, n: NimNode = nil) {.magic: "NHint", benign.}
+  ## Writes a hint message at compile time.
 
-proc newStrLitNode*(s: string): PNimrodNode {.compileTime.} =
-  ## creates a string literal node from `s`
+proc newStrLitNode*(s: string): NimNode {.noSideEffect.} =
+  ## Creates a string literal node from `s`.
   result = newNimNode(nnkStrLit)
   result.strVal = s
 
-proc newIntLitNode*(i: biggestInt): PNimrodNode {.compileTime.} =
-  ## creates a int literal node from `i`
+proc newCommentStmtNode*(s: string): NimNode {.noSideEffect.} =
+  ## Creates a comment statement node.
+  result = newNimNode(nnkCommentStmt)
+  result.strVal = s
+
+proc newIntLitNode*(i: BiggestInt): NimNode =
+  ## Creates an int literal node from `i`.
   result = newNimNode(nnkIntLit)
   result.intVal = i
 
-proc newFloatLitNode*(f: biggestFloat): PNimrodNode {.compileTime.} =
-  ## creates a float literal node from `f`
+proc newFloatLitNode*(f: BiggestFloat): NimNode =
+  ## Creates a float literal node from `f`.
   result = newNimNode(nnkFloatLit)
   result.floatVal = f
 
-proc newIdentNode*(i: TNimrodIdent): PNimrodNode {.compileTime.} =
-  ## creates an identifier node from `i`
+{.push warnings: off.}
+
+proc newIdentNode*(i: NimIdent): NimNode {.deprecated: "use ident(string)".} =
+  ## Creates an identifier node from `i`.
   result = newNimNode(nnkIdent)
   result.ident = i
 
-proc newIdentNode*(i: string): PNimrodNode {.compileTime.} =
-  ## creates an identifier node from `i`
-  result = newNimNode(nnkIdent)
-  result.ident = !i
+{.pop.}
+
+proc newIdentNode*(i: string): NimNode {.magic: "StrToIdent", noSideEffect.}
+  ## Creates an identifier node from `i`. It is simply an alias for
+  ## `ident(string)`. Use that, it's shorter.
+
+proc ident*(name: string): NimNode {.magic: "StrToIdent", noSideEffect.}
+  ## Create a new ident node from a string.
 
 type
-  TBindSymRule* = enum   ## specifies how ``bindSym`` behaves
+  BindSymRule* = enum    ## Specifies how `bindSym` behaves. The difference
+                         ## between open and closed symbols can be found in
+                         ## `<manual.html#symbol-lookup-in-generics-open-and-closed-symbols>`_
     brClosed,            ## only the symbols in current scope are bound
-    brOpen,              ## open wrt overloaded symbols, but may be a single
+    brOpen,              ## open for overloaded symbols, but may be a single
                          ## symbol if not ambiguous (the rules match that of
                          ## binding in generics)
     brForceOpen          ## same as brOpen, but it will always be open even
                          ## if not ambiguous (this cannot be achieved with
                          ## any other means in the language currently)
 
-proc bindSym*(ident: string, rule: TBindSymRule = brClosed): PNimrodNode {.
-              magic: "NBindSym".}
-  ## creates a node that binds `ident` to a symbol node. The bound symbol
+proc bindSym*(ident: string | NimNode, rule: BindSymRule = brClosed): NimNode {.
+              magic: "NBindSym", noSideEffect.}
+  ## Creates a node that binds `ident` to a symbol node. The bound symbol
   ## may be an overloaded symbol.
-  ## If ``rule == brClosed`` either an ``nkClosedSymChoice`` tree is
-  ## returned or ``nkSym`` if the symbol is not ambiguous.
-  ## If ``rule == brOpen`` either an ``nkOpenSymChoice`` tree is
-  ## returned or ``nkSym`` if the symbol is not ambiguous.
-  ## If ``rule == brForceOpen`` always an ``nkOpenSymChoice`` tree is
+  ## if `ident` is a NimNode, it must have `nnkIdent` kind.
+  ## If `rule == brClosed` either an `nnkClosedSymChoice` tree is
+  ## returned or `nnkSym` if the symbol is not ambiguous.
+  ## If `rule == brOpen` either an `nnkOpenSymChoice` tree is
+  ## returned or `nnkSym` if the symbol is not ambiguous.
+  ## If `rule == brForceOpen` always an `nnkOpenSymChoice` tree is
   ## returned even if the symbol is not ambiguous.
+  ##
+  ## See the `manual <manual.html#macros-bindsym>`_ for more details.
 
-proc callsite*(): PNimrodNode {.magic: "NCallSite".}
-  ## returns the AST if the invokation expression that invoked this macro.
+proc genSym*(kind: NimSymKind = nskLet; ident = ""): NimNode {.
+  magic: "NGenSym", noSideEffect.}
+  ## Generates a fresh symbol that is guaranteed to be unique. The symbol
+  ## needs to occur in a declaration context.
 
-proc toStrLit*(n: PNimrodNode): PNimrodNode {.compileTime.} =
-  ## converts the AST `n` to the concrete Nimrod code and wraps that
-  ## in a string literal node
+proc callsite*(): NimNode {.magic: "NCallSite", benign, deprecated:
+  "Deprecated since v0.18.1; use `varargs[untyped]` in the macro prototype instead".}
+  ## Returns the AST of the invocation expression that invoked this macro.
+  # see https://github.com/nim-lang/RFCs/issues/387 as candidate replacement.
+
+proc toStrLit*(n: NimNode): NimNode =
+  ## Converts the AST `n` to the concrete Nim code and wraps that
+  ## in a string literal node.
   return newStrLitNode(repr(n))
 
-proc lineinfo*(n: PNimrodNode): string {.magic: "NLineInfo".}
-  ## returns the position the node appears in the original source file
-  ## in the form filename(line, col)
+type
+  LineInfo* = object
+    filename*: string
+    line*,column*: int
+
+proc `$`*(arg: LineInfo): string =
+  ## Return a string representation in the form `filepath(line, column)`.
+  # BUG: without `result = `, gives compile error
+  result = 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
+#  ## in the form filename(line, col)
+
+proc getLine(arg: NimNode): int {.magic: "NLineInfo", noSideEffect.}
+proc getColumn(arg: NimNode): int {.magic: "NLineInfo", noSideEffect.}
+proc getFile(arg: NimNode): string {.magic: "NLineInfo", noSideEffect.}
+
+proc copyLineInfo*(arg: NimNode, info: NimNode) {.magic: "NLineInfo", noSideEffect.}
+  ## Copy lineinfo from `info`.
+
+proc setLine(arg: NimNode, line: uint16) {.magic: "NLineInfo", noSideEffect.}
+proc setColumn(arg: NimNode, column: int16) {.magic: "NLineInfo", noSideEffect.}
+proc setFile(arg: NimNode, file: string) {.magic: "NLineInfo", noSideEffect.}
+
+proc setLineInfo*(arg: NimNode, file: string, line: int, column: int) =
+  ## Sets the line info on the NimNode. The file needs to exists, but can be a
+  ## relative path. If you want to attach line info to a block using `quote`
+  ## you'll need to add the line information after the quote block.
+  arg.setFile(file)
+  arg.setLine(line.uint16)
+  arg.setColumn(column.int16)
+
+proc setLineInfo*(arg: NimNode, lineInfo: LineInfo) =
+  ## See `setLineInfo proc<#setLineInfo,NimNode,string,int,int>`_
+  setLineInfo(arg, lineInfo.filename, lineInfo.line, lineInfo.column)
+
+proc lineInfoObj*(n: NimNode): LineInfo =
+  ## Returns `LineInfo` of `n`, using absolute path for `filename`.
+  result = LineInfo(filename: n.getFile, line: n.getLine, column: n.getColumn)
+
+proc lineInfo*(arg: NimNode): string =
+  ## Return line info in the form `filepath(line, column)`.
+  $arg.lineInfoObj
 
-proc parseExpr*(s: string): PNimrodNode {.magic: "ParseExprToAst".}
+proc internalParseExpr(s, filename: string): NimNode {.
+  magic: "ParseExprToAst", noSideEffect.}
+
+proc internalParseStmt(s, filename: string): NimNode {.
+  magic: "ParseStmtToAst", noSideEffect.}
+
+proc internalErrorFlag*(): string {.magic: "NError", noSideEffect.}
+  ## Some builtins set an error flag. This is then turned into a proper
+  ## exception. **Note**: Ordinary application code should not call this.
+
+proc parseExpr*(s: string; filename: string = ""): NimNode {.noSideEffect.} =
   ## Compiles the passed string to its AST representation.
-  ## Expects a single expression.
+  ## Expects a single expression. Raises `ValueError` for parsing errors.
+  ## A filename can be given for more informative errors.
+  result = internalParseExpr(s, filename)
+  let x = internalErrorFlag()
+  if x.len > 0: raise newException(ValueError, x)
 
-proc parseStmt*(s: string): PNimrodNode {.magic: "ParseStmtToAst".}
+proc parseStmt*(s: string; filename: string = ""): NimNode {.noSideEffect.} =
   ## Compiles the passed string to its AST representation.
-  ## Expects one or more statements.
+  ## Expects one or more statements. Raises `ValueError` for parsing errors.
+  ## A filename can be given for more informative errors.
+  result = internalParseStmt(s, filename)
+  let x = internalErrorFlag()
+  if x.len > 0: raise newException(ValueError, x)
 
-proc getAst*(macroOrTemplate: expr): PNimrodNode {.magic: "ExpandToAst".}
+proc getAst*(macroOrTemplate: untyped): NimNode {.magic: "ExpandToAst", noSideEffect.}
   ## Obtains the AST nodes returned from a macro or template invocation.
+  ## See also `genasts.genAst`.
   ## Example:
-  ##
-  ## .. code-block:: nimrod
-  ##
+  ##   ```nim
   ##   macro FooMacro() =
   ##     var ast = getAst(BarTemplate())
+  ##   ```
 
-proc quote*(bl: stmt, op = "``"): PNimrodNode {.magic: "QuoteAst".}
+proc quote*(bl: typed, op = "``"): NimNode {.magic: "QuoteAst", noSideEffect.} =
   ## Quasi-quoting operator.
   ## Accepts an expression or a block and returns the AST that represents it.
-  ## Within the quoted AST, you are able to interpolate PNimrodNode expressions
+  ## Within the quoted AST, you are able to interpolate NimNode expressions
   ## from the surrounding scope. If no operator is given, quoting is done using
   ## backticks. Otherwise, the given operator must be used as a prefix operator
   ## for any interpolated expression. The original meaning of the interpolation
-  ## operator may be obtained by escaping it (by prefixing it with itself):
-  ## e.g. `@` is escaped as `@@`, `@@` is escaped as `@@@` and so on.
-  ##
-  ## Example:
-  ##   
-  ##   macro check(ex: expr): stmt =
-  ##     # this is a simplified version of the check macro from the
-  ##     # unittest module.
-  ##
-  ##     # If there is a failed check, we want to make it easy for
-  ##     # the user to jump to the faulty line in the code, so we
-  ##     # get the line info here:
-  ##     var info = ex.lineinfo
-  ##
-  ##     # We will also display the code string of the failed check:
-  ##     var expString = ex.toStrLit
+  ## operator may be obtained by escaping it (by prefixing it with itself) when used
+  ## as a unary operator:
+  ## e.g. `@` is escaped as `@@`, `&%` is escaped as `&%&%` and so on; see examples.
   ##
-  ##     # Finally we compose the code to implement the check:
-  ##     result = quote do:
-  ##       if not `ex`:
-  ##         echo `info` & ": Check failed: " & `expString`
-  
-template emit*(e: expr[string]): stmt =
-  ## accepts a single string argument and treats it as nimrod code
-  ## that should be inserted verbatim in the program
-  ## Example:
-  ##
-  ##   emit("echo " & '"' & "hello world".toUpper & '"')
+  ## A custom operator interpolation needs accent quoted (``) whenever it resolves
+  ## to a symbol.
   ##
-  eval: result = e.parseStmt
+  ## See also `genasts <genasts.html>`_ which avoids some issues with `quote`.
+  runnableExamples:
+    macro check(ex: untyped) =
+      # this is a simplified version of the check macro from the
+      # unittest module.
+
+      # If there is a failed check, we want to make it easy for
+      # the user to jump to the faulty line in the code, so we
+      # get the line info here:
+      var info = ex.lineinfo
+
+      # We will also display the code string of the failed check:
+      var expString = ex.toStrLit
+
+      # Finally we compose the code to implement the check:
+      result = quote do:
+        if not `ex`:
+          echo `info` & ": Check failed: " & `expString`
+    check 1 + 1 == 2
+
+  runnableExamples:
+    # example showing how to define a symbol that requires backtick without
+    # quoting it.
+    var destroyCalled = false
+    macro bar() =
+      let s = newTree(nnkAccQuoted, ident"=destroy")
+      # let s = ident"`=destroy`" # this would not work
+      result = quote do:
+        type Foo = object
+        # proc `=destroy`(a: var Foo) = destroyCalled = true # this would not work
+        proc `s`(a: var Foo) = destroyCalled = true
+        block:
+          let a = Foo()
+    bar()
+    doAssert destroyCalled
+
+  runnableExamples:
+    # custom `op`
+    var destroyCalled = false
+    macro bar(ident) =
+      var x = 1.5
+      result = quote("@") do:
+        type Foo = object
+        let `@ident` = 0 # custom op interpolated symbols need quoted (``)
+        proc `=destroy`(a: var Foo) =
+          doAssert @x == 1.5
+          doAssert compiles(@x == 1.5)
+          let b1 = @[1,2]
+          let b2 = @@[1,2]
+          doAssert $b1 == "[1, 2]"
+          doAssert $b2 == "@[1, 2]"
+          destroyCalled = true
+        block:
+          let a = Foo()
+    bar(someident)
+    doAssert destroyCalled
+
+    proc `&%`(x: int): int = 1
+    proc `&%`(x, y: int): int = 2
 
-proc expectKind*(n: PNimrodNode, k: TNimrodNodeKind) {.compileTime.} =
-  ## checks that `n` is of kind `k`. If this is not the case,
+    macro bar2() =
+      var x = 3
+      result = quote("&%") do:
+        var y = &%x # quoting operator
+        doAssert &%&%y == 1 # unary operator => need to escape
+        doAssert y &% y == 2 # binary operator => no need to escape
+        doAssert y == 3
+    bar2()
+
+proc expectKind*(n: NimNode, k: NimNodeKind) =
+  ## Checks that `n` is of kind `k`. If this is not the case,
   ## compilation aborts with an error message. This is useful for writing
   ## macros that check the AST that is passed to them.
-  if n.kind != k: error("macro expects a node of kind: " & repr(k))
+  if n.kind != k: error("Expected a node of kind " & $k & ", got " & $n.kind, n)
 
-proc expectMinLen*(n: PNimrodNode, min: int) {.compileTime.} =
-  ## checks that `n` has at least `min` children. If this is not the case,
+proc expectMinLen*(n: NimNode, min: int) =
+  ## Checks that `n` has at least `min` children. If this is not the case,
   ## compilation aborts with an error message. This is useful for writing
   ## macros that check its number of arguments.
-  if n.len < min: error("macro expects a node with " & $min & " children")
+  if n.len < min: error("Expected a node with at least " & $min & " children, got " & $n.len, n)
 
-proc expectLen*(n: PNimrodNode, len: int) {.compileTime.} =
-  ## checks that `n` has exactly `len` children. If this is not the case,
+proc expectLen*(n: NimNode, len: int) =
+  ## Checks that `n` has exactly `len` children. If this is not the case,
   ## compilation aborts with an error message. This is useful for writing
   ## macros that check its number of arguments.
-  if n.len != len: error("macro expects a node with " & $len & " children")
+  if n.len != len: error("Expected a node with " & $len & " children, got " & $n.len, n)
+
+proc expectLen*(n: NimNode, min, max: int) =
+  ## Checks that `n` has a number of children in the range `min..max`.
+  ## If this is not the case, compilation aborts with an error message.
+  ## This is useful for writing macros that check its number of arguments.
+  if n.len < min or n.len > max:
+    error("Expected a node with " & $min & ".." & $max & " children, got " & $n.len, n)
+
+proc newTree*(kind: NimNodeKind,
+              children: varargs[NimNode]): NimNode =
+  ## Produces a new node with children.
+  result = newNimNode(kind)
+  result.add(children)
 
-proc newCall*(theProc: PNimrodNode,
-              args: varargs[PNimrodNode]): PNimrodNode {.compileTime.} =
-  ## produces a new call node. `theProc` is the proc that is called with
-  ## the arguments ``args[0..]``.
+proc newCall*(theProc: NimNode, args: varargs[NimNode]): NimNode =
+  ## Produces a new call node. `theProc` is the proc that is called with
+  ## the arguments `args[0..]`.
   result = newNimNode(nnkCall)
   result.add(theProc)
   result.add(args)
 
-proc newCall*(theProc: TNimrodIdent,
-              args: varargs[PNimrodNode]): PNimrodNode {.compileTime.} =
-  ## produces a new call node. `theProc` is the proc that is called with
-  ## the arguments ``args[0..]``.
+{.push warnings: off.}
+
+proc newCall*(theProc: NimIdent, args: varargs[NimNode]): NimNode {.deprecated:
+  "Deprecated since v0.18.1; use 'newCall(string, ...)' or 'newCall(NimNode, ...)' instead".} =
+  ## Produces a new call node. `theProc` is the proc that is called with
+  ## the arguments `args[0..]`.
   result = newNimNode(nnkCall)
   result.add(newIdentNode(theProc))
   result.add(args)
 
+{.pop.}
+
 proc newCall*(theProc: string,
-              args: varargs[PNimrodNode]): PNimrodNode {.compileTime.} =
-  ## produces a new call node. `theProc` is the proc that is called with
-  ## the arguments ``args[0..]``.
+              args: varargs[NimNode]): NimNode =
+  ## Produces a new call node. `theProc` is the proc that is called with
+  ## the arguments `args[0..]`.
   result = newNimNode(nnkCall)
   result.add(newIdentNode(theProc))
   result.add(args)
 
-proc nestList*(theProc: TNimrodIdent,
-               x: PNimrodNode): PNimrodNode {.compileTime.} =
-  ## nests the list `x` into a tree of call expressions:
-  ## ``[a, b, c]`` is transformed into ``theProc(a, theProc(c, d))``.
-  var L = x.len
-  result = newCall(theProc, x[L-2], x[L-1])
-  var a = result
-  for i in countdown(L-3, 0):
-    a = newCall(theProc, x[i], copyNimTree(a))
-
-proc treeRepr*(n: PNimrodNode): string {.compileTime.} =
+proc newLit*(c: char): NimNode =
+  ## Produces a new character literal node.
+  result = newNimNode(nnkCharLit)
+  result.intVal = ord(c)
+
+proc newLit*(i: int): NimNode =
+  ## Produces a new integer literal node.
+  result = newNimNode(nnkIntLit)
+  result.intVal = i
+
+proc newLit*(i: int8): NimNode =
+  ## Produces a new integer literal node.
+  result = newNimNode(nnkInt8Lit)
+  result.intVal = i
+
+proc newLit*(i: int16): NimNode =
+  ## Produces a new integer literal node.
+  result = newNimNode(nnkInt16Lit)
+  result.intVal = i
+
+proc newLit*(i: int32): NimNode =
+  ## Produces a new integer literal node.
+  result = newNimNode(nnkInt32Lit)
+  result.intVal = i
+
+proc newLit*(i: int64): NimNode =
+  ## Produces a new integer literal node.
+  result = newNimNode(nnkInt64Lit)
+  result.intVal = i
+
+proc newLit*(i: uint): NimNode =
+  ## Produces a new unsigned integer literal node.
+  result = newNimNode(nnkUIntLit)
+  result.intVal = BiggestInt(i)
+
+proc newLit*(i: uint8): NimNode =
+  ## Produces a new unsigned integer literal node.
+  result = newNimNode(nnkUInt8Lit)
+  result.intVal = BiggestInt(i)
+
+proc newLit*(i: uint16): NimNode =
+  ## Produces a new unsigned integer literal node.
+  result = newNimNode(nnkUInt16Lit)
+  result.intVal = BiggestInt(i)
+
+proc newLit*(i: uint32): NimNode =
+  ## Produces a new unsigned integer literal node.
+  result = newNimNode(nnkUInt32Lit)
+  result.intVal = BiggestInt(i)
+
+proc newLit*(i: uint64): NimNode =
+  ## Produces a new unsigned integer literal node.
+  result = newNimNode(nnkUInt64Lit)
+  result.intVal = BiggestInt(i)
+
+proc newLit*(b: bool): NimNode =
+  ## Produces a new boolean literal node.
+  result = if b: bindSym"true" else: bindSym"false"
+
+proc newLit*(s: string): NimNode =
+  ## Produces a new string literal node.
+  result = newNimNode(nnkStrLit)
+  result.strVal = s
+
+when false:
+  # the float type is not really a distinct type as described in https://github.com/nim-lang/Nim/issues/5875
+  proc newLit*(f: float): NimNode =
+    ## Produces a new float literal node.
+    result = newNimNode(nnkFloatLit)
+    result.floatVal = f
+
+proc newLit*(f: float32): NimNode =
+  ## Produces a new float literal node.
+  result = newNimNode(nnkFloat32Lit)
+  result.floatVal = f
+
+proc newLit*(f: float64): NimNode =
+  ## Produces a new float literal node.
+  result = newNimNode(nnkFloat64Lit)
+  result.floatVal = f
+
+when declared(float128):
+  proc newLit*(f: float128): NimNode =
+    ## Produces a new float literal node.
+    result = newNimNode(nnkFloat128Lit)
+    result.floatVal = f
+
+proc newLit*(arg: enum): NimNode =
+  result = newCall(
+    arg.typeof.getTypeInst[1],
+    newLit(int(arg))
+  )
+
+proc newLit*[N,T](arg: array[N,T]): NimNode
+proc newLit*[T](arg: seq[T]): NimNode
+proc newLit*[T](s: set[T]): NimNode
+proc newLit*[T: tuple](arg: T): NimNode
+
+proc newLit*(arg: object): NimNode =
+  result = nnkObjConstr.newTree(arg.typeof.getTypeInst[1])
+  for a, b in arg.fieldPairs:
+    result.add nnkExprColonExpr.newTree( newIdentNode(a), newLit(b) )
+
+proc newLit*(arg: ref object): NimNode =
+  ## produces a new ref type literal node.
+  result = nnkObjConstr.newTree(arg.typeof.getTypeInst[1])
+  for a, b in fieldPairs(arg[]):
+    result.add nnkExprColonExpr.newTree(newIdentNode(a), newLit(b))
+
+proc newLit*[N,T](arg: array[N,T]): NimNode =
+  result = nnkBracket.newTree
+  for x in arg:
+    result.add newLit(x)
+
+proc newLit*[T](arg: seq[T]): NimNode =
+  let bracket = nnkBracket.newTree
+  for x in arg:
+    bracket.add newLit(x)
+  result = nnkPrefix.newTree(
+    bindSym"@",
+    bracket
+  )
+  if arg.len == 0:
+    # add type cast for empty seq
+    var typ = getTypeInst(typeof(arg))[1]
+    result = newCall(typ,result)
+
+proc newLit*[T](s: set[T]): NimNode =
+  result = nnkCurly.newTree
+  for x in s:
+    result.add newLit(x)
+  if result.len == 0:
+    # add type cast for empty set
+    var typ = getTypeInst(typeof(s))[1]
+    result = newCall(typ,result)
+
+proc isNamedTuple(T: typedesc): bool {.magic: "TypeTrait".}
+  ## See `typetraits.isNamedTuple`
+
+proc newLit*[T: tuple](arg: T): NimNode =
+  ## use -d:nimHasWorkaround14720 to restore behavior prior to PR, forcing
+  ## a named tuple even when `arg` is unnamed.
+  result = nnkTupleConstr.newTree
+  when defined(nimHasWorkaround14720) or isNamedTuple(T):
+    for a, b in arg.fieldPairs:
+      result.add nnkExprColonExpr.newTree(newIdentNode(a), newLit(b))
+  else:
+    for b in arg.fields:
+      result.add newLit(b)
+
+proc nestList*(op: NimNode; pack: NimNode): NimNode =
+  ## Nests the list `pack` into a tree of call expressions:
+  ## `[a, b, c]` is transformed into `op(a, op(c, d))`.
+  ## This is also known as fold expression.
+  if pack.len < 1:
+    error("`nestList` expects a node with at least 1 child")
+  result = pack[^1]
+  for i in countdown(pack.len - 2, 0):
+    result = newCall(op, pack[i], result)
+
+proc nestList*(op: NimNode; pack: NimNode; init: NimNode): NimNode =
+  ## Nests the list `pack` into a tree of call expressions:
+  ## `[a, b, c]` is transformed into `op(a, op(c, d))`.
+  ## This is also known as fold expression.
+  result = init
+  for i in countdown(pack.len - 1, 0):
+    result = newCall(op, pack[i], result)
+
+proc eqIdent*(a: string; b: string): bool {.magic: "EqIdent", noSideEffect.}
+  ## Style insensitive comparison.
+
+proc eqIdent*(a: NimNode; b: string): bool {.magic: "EqIdent", noSideEffect.}
+  ## Style insensitive comparison.  `a` can be an identifier or a
+  ## symbol. `a` may be wrapped in an export marker
+  ## (`nnkPostfix`) or quoted with backticks (`nnkAccQuoted`),
+  ## these nodes will be unwrapped.
+
+proc eqIdent*(a: string; b: NimNode): bool {.magic: "EqIdent", noSideEffect.}
+  ## Style insensitive comparison.  `b` can be an identifier or a
+  ## symbol. `b` may be wrapped in an export marker
+  ## (`nnkPostfix`) or quoted with backticks (`nnkAccQuoted`),
+  ## these nodes will be unwrapped.
+
+proc eqIdent*(a: NimNode; b: NimNode): bool {.magic: "EqIdent", noSideEffect.}
+  ## Style insensitive comparison.  `a` and `b` can be an
+  ## identifier or a symbol. Both may be wrapped in an export marker
+  ## (`nnkPostfix`) or quoted with backticks (`nnkAccQuoted`),
+  ## these nodes will be unwrapped.
+
+const collapseSymChoice = not defined(nimLegacyMacrosCollapseSymChoice)
+
+proc treeTraverse(n: NimNode; res: var string; level = 0; isLisp = false, indented = false) {.benign.} =
+  if level > 0:
+    if indented:
+      res.add("\n")
+      for i in 0 .. level-1:
+        if isLisp:
+          res.add(" ")          # dumpLisp indentation
+        else:
+          res.add("  ")         # dumpTree indentation
+    else:
+      res.add(" ")
+
+  if isLisp:
+    res.add("(")
+  res.add(($n.kind).substr(3))
+
+  case n.kind
+  of nnkEmpty, nnkNilLit:
+    discard # same as nil node in this representation
+  of nnkCharLit .. nnkInt64Lit:
+    res.add(" " & $n.intVal)
+  of nnkUIntLit .. nnkUInt64Lit:
+    res.add(" " & $cast[uint64](n.intVal))
+  of nnkFloatLit .. nnkFloat64Lit:
+    res.add(" " & $n.floatVal)
+  of nnkStrLit .. nnkTripleStrLit, nnkCommentStmt, nnkIdent, nnkSym:
+    res.add(" " & $n.strVal.newLit.repr)
+  of nnkNone:
+    assert false
+  elif n.kind in {nnkOpenSymChoice, nnkClosedSymChoice} and collapseSymChoice:
+    res.add(" " & $n.len)
+    if n.len > 0:
+      var allSameSymName = true
+      for i in 0..<n.len:
+        if n[i].kind != nnkSym or not eqIdent(n[i], n[0]):
+          allSameSymName = false
+          break
+      if allSameSymName:
+        res.add(" " & $n[0].strVal.newLit.repr)
+      else:
+        for j in 0 ..< n.len:
+          n[j].treeTraverse(res, level+1, isLisp, indented)
+  else:
+    for j in 0 ..< n.len:
+      n[j].treeTraverse(res, level+1, isLisp, indented)
+
+  if isLisp:
+    res.add(")")
+
+proc treeRepr*(n: NimNode): string {.benign.} =
   ## Convert the AST `n` to a human-readable tree-like string.
   ##
-  ## See also `repr` and `lispRepr`.
-  proc traverse(res: var string, level: int, n: PNimrodNode) =
+  ## See also `repr`, `lispRepr`_, and `astGenRepr`_.
+  result = ""
+  n.treeTraverse(result, isLisp = false, indented = true)
+
+proc lispRepr*(n: NimNode; indented = false): string {.benign.} =
+  ## Convert the AST `n` to a human-readable lisp-like string.
+  ##
+  ## See also `repr`, `treeRepr`_, and `astGenRepr`_.
+  result = ""
+  n.treeTraverse(result, isLisp = true, indented = indented)
+
+proc astGenRepr*(n: NimNode): string {.benign.} =
+  ## Convert the AST `n` to the code required to generate that AST.
+  ##
+  ## See also `repr`_, `treeRepr`_, and `lispRepr`_.
+
+  const
+    NodeKinds = {nnkEmpty, nnkIdent, nnkSym, nnkNone, nnkCommentStmt}
+    LitKinds = {nnkCharLit..nnkInt64Lit, nnkFloatLit..nnkFloat64Lit, nnkStrLit..nnkTripleStrLit}
+
+  proc traverse(res: var string, level: int, n: NimNode) {.benign.} =
     for i in 0..level-1: res.add "  "
-    res.add(($n.kind).substr(3))
+    if n.kind in NodeKinds:
+      res.add("new" & ($n.kind).substr(3) & "Node(")
+    elif n.kind in LitKinds:
+      res.add("newLit(")
+    elif n.kind == nnkNilLit:
+      res.add("newNilLit()")
+    else:
+      res.add($n.kind)
 
     case n.kind
-    of nnkEmpty: nil # same as nil node in this representation
-    of nnkNilLit: res.add(" nil")
-    of nnkCharLit..nnkInt64Lit: res.add(" " & $n.intVal)
-    of nnkFloatLit..nnkFloat64Lit: res.add(" " & $n.floatVal)
-    of nnkStrLit..nnkTripleStrLit: res.add(" " & $n.strVal)
-    of nnkIdent: res.add(" !\"" & $n.ident & '"')
-    of nnkSym: res.add(" \"" & $n.symbol & '"')
+    of nnkEmpty, nnkNilLit: discard
+    of nnkCharLit: res.add("'" & $chr(n.intVal) & "'")
+    of nnkIntLit..nnkInt64Lit: res.add($n.intVal)
+    of nnkFloatLit..nnkFloat64Lit: res.add($n.floatVal)
+    of nnkStrLit..nnkTripleStrLit, nnkCommentStmt, nnkIdent, nnkSym:
+      res.add(n.strVal.newLit.repr)
     of nnkNone: assert false
+    elif n.kind in {nnkOpenSymChoice, nnkClosedSymChoice} and collapseSymChoice:
+      res.add(", # unrepresentable symbols: " & $n.len)
+      if n.len > 0:
+        res.add(" " & n[0].strVal.newLit.repr)
     else:
-      for j in 0..n.len-1:
+      res.add(".newTree(")
+      for j in 0..<n.len:
         res.add "\n"
         traverse(res, level + 1, n[j])
+        if j != n.len-1:
+          res.add(",")
+
+      res.add("\n")
+      for i in 0..level-1: res.add "  "
+      res.add(")")
+
+    if n.kind in NodeKinds+LitKinds:
+      res.add(")")
 
   result = ""
   traverse(result, 0, n)
 
-proc lispRepr*(n: PNimrodNode): string {.compileTime.} =
-  ## Convert the AST `n` to a human-readable lisp-like string,
+macro dumpTree*(s: untyped): untyped = echo s.treeRepr
+  ## Accepts a block of nim code and prints the parsed abstract syntax
+  ## tree using the `treeRepr` proc. Printing is done *at compile time*.
+  ##
+  ## You can use this as a tool to explore the Nim's abstract syntax
+  ## tree and to discover what kind of nodes must be created to represent
+  ## a certain expression/statement.
+  ##
+  ## For example:
+  ##   ```nim
+  ##   dumpTree:
+  ##     echo "Hello, World!"
+  ##   ```
+  ##
+  ## Outputs:
+  ##   ```
+  ##   StmtList
+  ##     Command
+  ##       Ident "echo"
+  ##       StrLit "Hello, World!"
+  ##   ```
+  ##
+  ## Also see `dumpAstGen` and `dumpLisp`.
+
+macro dumpLisp*(s: untyped): untyped = echo s.lispRepr(indented = true)
+  ## Accepts a block of nim code and prints the parsed abstract syntax
+  ## tree using the `lispRepr` proc. Printing is done *at compile time*.
+  ##
+  ## You can use this as a tool to explore the Nim's abstract syntax
+  ## tree and to discover what kind of nodes must be created to represent
+  ## a certain expression/statement.
+  ##
+  ## For example:
+  ##   ```nim
+  ##   dumpLisp:
+  ##     echo "Hello, World!"
+  ##   ```
+  ##
+  ## Outputs:
+  ##   ```
+  ##   (StmtList
+  ##    (Command
+  ##     (Ident "echo")
+  ##     (StrLit "Hello, World!")))
+  ##   ```
+  ##
+  ## Also see `dumpAstGen` and `dumpTree`.
+
+macro dumpAstGen*(s: untyped): untyped = echo s.astGenRepr
+  ## Accepts a block of nim code and prints the parsed abstract syntax
+  ## tree using the `astGenRepr` proc. Printing is done *at compile time*.
   ##
-  ## See also `repr` and `treeRepr`.
+  ## You can use this as a tool to write macros quicker by writing example
+  ## outputs and then copying the snippets into the macro for modification.
+  ##
+  ## For example:
+  ##   ```nim
+  ##   dumpAstGen:
+  ##     echo "Hello, World!"
+  ##   ```
+  ##
+  ## Outputs:
+  ##   ```
+  ##   nnkStmtList.newTree(
+  ##     nnkCommand.newTree(
+  ##       newIdentNode("echo"),
+  ##       newLit("Hello, World!")
+  ##     )
+  ##   )
+  ##   ```
+  ##
+  ## Also see `dumpTree` and `dumpLisp`.
 
-  result = ($n.kind).substr(3)
-  add(result, "(")
+proc newEmptyNode*(): NimNode {.noSideEffect.} =
+  ## Create a new empty node.
+  result = newNimNode(nnkEmpty)
 
-  case n.kind
-  of nnkEmpty: nil # same as nil node in this representation
-  of nnkNilLit: add(result, "nil")
-  of nnkCharLit..nnkInt64Lit: add(result, $n.intVal)
-  of nnkFloatLit..nnkFloat64Lit: add(result, $n.floatVal)
-  of nnkStrLit..nnkTripleStrLit: add(result, $n.strVal)
-  of nnkIdent: add(result, "!\"" & $n.ident & '"')
-  of nnkSym, nnkNone: assert false
+proc newStmtList*(stmts: varargs[NimNode]): NimNode =
+  ## Create a new statement list.
+  result = newNimNode(nnkStmtList).add(stmts)
+
+proc newPar*(exprs: NimNode): NimNode =
+  ## Create a new parentheses-enclosed expression.
+  newNimNode(nnkPar).add(exprs)
+
+proc newPar*(exprs: varargs[NimNode]): NimNode {.deprecated:
+        "don't use newPar/nnkPar to construct tuple expressions; use nnkTupleConstr instead".} =
+  ## Create a new parentheses-enclosed expression.
+  newNimNode(nnkPar).add(exprs)
+
+proc newBlockStmt*(label, body: NimNode): NimNode =
+  ## Create a new block statement with label.
+  return newNimNode(nnkBlockStmt).add(label, body)
+
+proc newBlockStmt*(body: NimNode): NimNode =
+  ## Create a new block: stmt.
+  return newNimNode(nnkBlockStmt).add(newEmptyNode(), body)
+
+proc newVarStmt*(name, value: NimNode): NimNode =
+  ## Create a new var stmt.
+  return newNimNode(nnkVarSection).add(
+    newNimNode(nnkIdentDefs).add(name, newNimNode(nnkEmpty), value))
+
+proc newLetStmt*(name, value: NimNode): NimNode =
+  ## Create a new let stmt.
+  return newNimNode(nnkLetSection).add(
+    newNimNode(nnkIdentDefs).add(name, newNimNode(nnkEmpty), value))
+
+proc newConstStmt*(name, value: NimNode): NimNode =
+  ## Create a new const stmt.
+  newNimNode(nnkConstSection).add(
+    newNimNode(nnkConstDef).add(name, newNimNode(nnkEmpty), value))
+
+proc newAssignment*(lhs, rhs: NimNode): NimNode =
+  return newNimNode(nnkAsgn).add(lhs, rhs)
+
+proc newDotExpr*(a, b: NimNode): NimNode =
+  ## Create new dot expression.
+  ## a.dot(b) -> `a.b`
+  return newNimNode(nnkDotExpr).add(a, b)
+
+proc newColonExpr*(a, b: NimNode): NimNode =
+  ## Create new colon expression.
+  ## newColonExpr(a, b) -> `a: b`
+  newNimNode(nnkExprColonExpr).add(a, b)
+
+proc newIdentDefs*(name, kind: NimNode;
+                   default = newEmptyNode()): NimNode =
+  ## Creates a new `nnkIdentDefs` node of a specific kind and value.
+  ##
+  ## `nnkIdentDefs` need to have at least three children, but they can have
+  ## more: first comes a list of identifiers followed by a type and value
+  ## nodes. This helper proc creates a three node subtree, the first subnode
+  ## being a single identifier name. Both the `kind` node and `default`
+  ## (value) nodes may be empty depending on where the `nnkIdentDefs`
+  ## appears: tuple or object definitions will have an empty `default` node,
+  ## `let` or `var` blocks may have an empty `kind` node if the
+  ## identifier is being assigned a value. Example:
+  ##
+  ##   ```nim
+  ##   var varSection = newNimNode(nnkVarSection).add(
+  ##     newIdentDefs(ident("a"), ident("string")),
+  ##     newIdentDefs(ident("b"), newEmptyNode(), newLit(3)))
+  ##   # --> var
+  ##   #       a: string
+  ##   #       b = 3
+  ##   ```
+  ##
+  ## If you need to create multiple identifiers you need to use the lower level
+  ## `newNimNode`:
+  ##   ```nim
+  ##   result = newNimNode(nnkIdentDefs).add(
+  ##     ident("a"), ident("b"), ident("c"), ident("string"),
+  ##       newStrLitNode("Hello"))
+  ##   ```
+  newNimNode(nnkIdentDefs).add(name, kind, default)
+
+proc newNilLit*(): NimNode =
+  ## New nil literal shortcut.
+  result = newNimNode(nnkNilLit)
+
+proc last*(node: NimNode): NimNode = node[node.len-1]
+  ## Return the last item in nodes children. Same as `node[^1]`.
+
+
+const
+  RoutineNodes* = {nnkProcDef, nnkFuncDef, nnkMethodDef, nnkDo, nnkLambda,
+                   nnkIteratorDef, nnkTemplateDef, nnkConverterDef, nnkMacroDef}
+  AtomicNodes* = {nnkNone..nnkNilLit}
+  # see matching set nnkCallKinds above
+  CallNodes* = nnkCallKinds
+
+proc expectKind*(n: NimNode; k: set[NimNodeKind]) =
+  ## Checks that `n` is of kind `k`. If this is not the case,
+  ## compilation aborts with an error message. This is useful for writing
+  ## macros that check the AST that is passed to them.
+  if n.kind notin k: error("Expected one of " & $k & ", got " & $n.kind, n)
+
+proc newProc*(name = newEmptyNode();
+              params: openArray[NimNode] = [newEmptyNode()];
+              body: NimNode = newStmtList();
+              procType = nnkProcDef;
+              pragmas: NimNode = newEmptyNode()): NimNode =
+  ## Shortcut for creating a new proc.
+  ##
+  ## The `params` array must start with the return type of the proc,
+  ## followed by a list of IdentDefs which specify the params.
+  if procType notin RoutineNodes:
+    error("Expected one of " & $RoutineNodes & ", got " & $procType)
+  pragmas.expectKind({nnkEmpty, nnkPragma})
+  result = newNimNode(procType).add(
+    name,
+    newEmptyNode(),
+    newEmptyNode(),
+    newNimNode(nnkFormalParams).add(params),
+    pragmas,
+    newEmptyNode(),
+    body)
+
+proc newIfStmt*(branches: varargs[tuple[cond, body: NimNode]]): NimNode =
+  ## Constructor for `if` statements.
+  ##   ```nim
+  ##   newIfStmt(
+  ##     (Ident, StmtList),
+  ##     ...
+  ##   )
+  ##   ```
+  result = newNimNode(nnkIfStmt)
+  if len(branches) < 1:
+    error("If statement must have at least one branch")
+  for i in branches:
+    result.add(newTree(nnkElifBranch, i.cond, i.body))
+
+proc newEnum*(name: NimNode, fields: openArray[NimNode],
+              public, pure: bool): NimNode =
+
+  ## Creates a new enum. `name` must be an ident. Fields are allowed to be
+  ## either idents or EnumFieldDef:
+  ##   ```nim
+  ##   newEnum(
+  ##     name    = ident("Colors"),
+  ##     fields  = [ident("Blue"), ident("Red")],
+  ##     public  = true, pure = false)
+  ##
+  ##   # type Colors* = Blue Red
+  ##   ```
+
+  expectKind name, nnkIdent
+  if len(fields) < 1:
+    error("Enum must contain at least one field")
+  for field in fields:
+    expectKind field, {nnkIdent, nnkEnumFieldDef}
+
+  let enumBody = newNimNode(nnkEnumTy).add(newEmptyNode()).add(fields)
+  var typeDefArgs = [name, newEmptyNode(), enumBody]
+
+  if public:
+    let postNode = newNimNode(nnkPostfix).add(
+      newIdentNode("*"), typeDefArgs[0])
+
+    typeDefArgs[0] = postNode
+
+  if pure:
+    let pragmaNode = newNimNode(nnkPragmaExpr).add(
+      typeDefArgs[0],
+      add(newNimNode(nnkPragma), newIdentNode("pure")))
+
+    typeDefArgs[0] = pragmaNode
+
+  let
+    typeDef   = add(newNimNode(nnkTypeDef), typeDefArgs)
+    typeSect  = add(newNimNode(nnkTypeSection), typeDef)
+
+  return typeSect
+
+proc copyChildrenTo*(src, dest: NimNode) =
+  ## Copy all children from `src` to `dest`.
+  for i in 0 ..< src.len:
+    dest.add src[i].copyNimTree
+
+template expectRoutine(node: NimNode) =
+  expectKind(node, RoutineNodes)
+
+proc name*(someProc: NimNode): NimNode =
+  someProc.expectRoutine
+  result = someProc[0]
+  if result.kind == nnkPostfix:
+    if result[1].kind == nnkAccQuoted:
+      result = result[1][0]
+    else:
+      result = result[1]
+  elif result.kind == nnkAccQuoted:
+    result = result[0]
+
+proc `name=`*(someProc: NimNode; val: NimNode) =
+  someProc.expectRoutine
+  if someProc[0].kind == nnkPostfix:
+    someProc[0][1] = val
+  else: someProc[0] = val
+
+proc params*(someProc: NimNode): NimNode =
+  if someProc.kind == nnkProcTy:
+    someProc[0]
+  else:
+    someProc.expectRoutine
+    someProc[3]
+
+proc `params=`* (someProc: NimNode; params: NimNode) =
+  expectKind(params, nnkFormalParams)
+  if someProc.kind == nnkProcTy:
+    someProc[0] = params
+  else:
+    someProc.expectRoutine
+    someProc[3] = params
+
+proc pragma*(someProc: NimNode): NimNode =
+  ## Get the pragma of a proc type.
+  ## These will be expanded.
+  if someProc.kind == nnkProcTy:
+    result = someProc[1]
+  else:
+    someProc.expectRoutine
+    result = someProc[4]
+proc `pragma=`*(someProc: NimNode; val: NimNode) =
+  ## Set the pragma of a proc type.
+  expectKind(val, {nnkEmpty, nnkPragma})
+  if someProc.kind == nnkProcTy:
+    someProc[1] = val
+  else:
+    someProc.expectRoutine
+    someProc[4] = val
+
+proc addPragma*(someProc, pragma: NimNode) =
+  ## Adds pragma to routine definition.
+  someProc.expectKind(RoutineNodes + {nnkProcTy})
+  var pragmaNode = someProc.pragma
+  if pragmaNode.isNil or pragmaNode.kind == nnkEmpty:
+    pragmaNode = newNimNode(nnkPragma)
+    someProc.pragma = pragmaNode
+  pragmaNode.add(pragma)
+
+template badNodeKind(n, f) =
+  error("Invalid node kind " & $n.kind & " for macros.`" & $f & "`", n)
+
+proc body*(someProc: NimNode): NimNode =
+  case someProc.kind:
+  of RoutineNodes:
+    return someProc[6]
+  of nnkBlockStmt, nnkWhileStmt:
+    return someProc[1]
+  of nnkForStmt:
+    return someProc.last
+  else:
+    badNodeKind someProc, "body"
+
+proc `body=`*(someProc: NimNode, val: NimNode) =
+  case someProc.kind
+  of RoutineNodes:
+    someProc[6] = val
+  of nnkBlockStmt, nnkWhileStmt:
+    someProc[1] = val
+  of nnkForStmt:
+    someProc[len(someProc)-1] = val
+  else:
+    badNodeKind someProc, "body="
+
+proc basename*(a: NimNode): NimNode =
+  ## Pull an identifier from prefix/postfix expressions.
+  case a.kind
+  of nnkIdent: result = a
+  of nnkPostfix, nnkPrefix: result = a[1]
+  of nnkPragmaExpr: result = basename(a[0])
+  else:
+    error("Do not know how to get basename of (" & treeRepr(a) & ")\n" &
+      repr(a), a)
+
+proc `$`*(node: NimNode): string =
+  ## Get the string of an identifier node.
+  case node.kind
+  of nnkPostfix:
+    result = node.basename.strVal & "*"
+  of nnkStrLit..nnkTripleStrLit, nnkCommentStmt, nnkSym, nnkIdent:
+    result = node.strVal
+  of nnkOpenSymChoice, nnkClosedSymChoice, nnkOpenSym:
+    result = $node[0]
+  of nnkAccQuoted:
+    result = ""
+    for i in 0 ..< node.len:
+      result.add(repr(node[i]))
+  else:
+    badNodeKind node, "$"
+
+iterator items*(n: NimNode): NimNode {.inline.} =
+  ## Iterates over the children of the NimNode `n`.
+  for i in 0 ..< n.len:
+    yield n[i]
+
+iterator pairs*(n: NimNode): (int, NimNode) {.inline.} =
+  ## Iterates over the children of the NimNode `n` and its indices.
+  for i in 0 ..< n.len:
+    yield (i, n[i])
+
+iterator children*(n: NimNode): NimNode {.inline.} =
+  ## Iterates over the children of the NimNode `n`.
+  for i in 0 ..< n.len:
+    yield n[i]
+
+template findChild*(n: NimNode; cond: untyped): NimNode {.dirty.} =
+  ## Find the first child node matching condition (or nil).
+  ##   ```nim
+  ##   var res = findChild(n, it.kind == nnkPostfix and
+  ##                          it.basename.ident == ident"foo")
+  ##   ```
+  block:
+    var res: NimNode
+    for it in n.children:
+      if cond:
+        res = it
+        break
+    res
+
+proc insert*(a: NimNode; pos: int; b: NimNode) =
+  ## Insert node `b` into node `a` at `pos`.
+  if len(a)-1 < pos:
+    # add some empty nodes first
+    for i in len(a)-1..pos-2:
+      a.add newEmptyNode()
+    a.add b
   else:
-    add(result, lispRepr(n[0]))
-    for j in 1..n.len-1:
-      add(result, ", ")
-      add(result, lispRepr(n[j]))
+    # push the last item onto the list again
+    # and shift each item down to pos up one
+    a.add(a[a.len-1])
+    for i in countdown(len(a) - 3, pos):
+      a[i + 1] = a[i]
+    a[pos] = b
+
+proc `basename=`*(a: NimNode; val: string) =
+  case a.kind
+  of nnkIdent:
+    a.strVal = val
+  of nnkPostfix, nnkPrefix:
+    a[1] = ident(val)
+  of nnkPragmaExpr: `basename=`(a[0], val)
+  else:
+    error("Do not know how to get basename of (" & treeRepr(a) & ")\n" &
+      repr(a), a)
+
+proc postfix*(node: NimNode; op: string): NimNode =
+  newNimNode(nnkPostfix).add(ident(op), node)
+
+proc prefix*(node: NimNode; op: string): NimNode =
+  newNimNode(nnkPrefix).add(ident(op), node)
+
+proc infix*(a: NimNode; op: string;
+            b: NimNode): NimNode =
+  newNimNode(nnkInfix).add(ident(op), a, b)
 
-  add(result, ")")
+proc unpackPostfix*(node: NimNode): tuple[node: NimNode; op: string] =
+  node.expectKind nnkPostfix
+  result = (node[1], $node[0])
 
-macro dumpTree*(s: stmt): stmt = echo s.treeRepr
-  ## Accepts a block of nimrod code and prints the parsed abstract syntax
-  ## tree using the `toTree` function. Printing is done *at compile time*.
+proc unpackPrefix*(node: NimNode): tuple[node: NimNode; op: string] =
+  node.expectKind nnkPrefix
+  result = (node[1], $node[0])
+
+proc unpackInfix*(node: NimNode): tuple[left: NimNode; op: string; right: NimNode] =
+  expectKind(node, nnkInfix)
+  result = (node[1], $node[0], node[2])
+
+proc copy*(node: NimNode): NimNode =
+  ## An alias for `copyNimTree<#copyNimTree,NimNode>`_.
+  return node.copyNimTree()
+
+proc expectIdent*(n: NimNode, name: string) {.since: (1,1).} =
+  ## Check that `eqIdent(n,name)` holds true. If this is not the
+  ## case, compilation aborts with an error message. This is useful
+  ## for writing macros that check the AST that is passed to them.
+  if not eqIdent(n, name):
+    error("Expected identifier to be `" & name & "` here", n)
+
+proc hasArgOfName*(params: NimNode; name: string): bool =
+  ## Search `nnkFormalParams` for an argument.
+  expectKind(params, nnkFormalParams)
+  for i in 1..<params.len:
+    for j in 0..<params[i].len-2:
+      if name.eqIdent($params[i][j]):
+        return true
+
+proc addIdentIfAbsent*(dest: NimNode, ident: string) =
+  ## Add `ident` to `dest` if it is not present. This is intended for use
+  ## with pragmas.
+  for node in dest.children:
+    case node.kind
+    of nnkIdent:
+      if ident.eqIdent($node): return
+    of nnkExprColonExpr:
+      if ident.eqIdent($node[0]): return
+    else: discard
+  dest.add(ident(ident))
+
+proc boolVal*(n: NimNode): bool {.noSideEffect.} =
+  if n.kind == nnkIntLit: n.intVal != 0
+  else: n == bindSym"true" # hacky solution for now
+
+proc nodeID*(n: NimNode): int {.magic: "NodeId".}
+  ## Returns the id of `n`, when the compiler has been compiled
+  ## with the flag `-d:useNodeids`, otherwise returns `-1`. This
+  ## proc is for the purpose to debug the compiler only.
+
+macro expandMacros*(body: typed): untyped =
+  ## Expands one level of macro - useful for debugging.
+  ## Can be used to inspect what happens when a macro call is expanded,
+  ## without altering its result.
   ##
-  ## You can use this as a tool to explore the Nimrod's abstract syntax
-  ## tree and to discover what kind of nodes must be created to represent
-  ## a certain expression/statement.
+  ## For instance,
+  ##
+  ##   ```nim
+  ##   import std/[sugar, macros]
+  ##
+  ##   let
+  ##     x = 10
+  ##     y = 20
+  ##   expandMacros:
+  ##     dump(x + y)
+  ##   ```
+  ##
+  ## will actually dump `x + y`, but at the same time will print at
+  ## compile time the expansion of the `dump` macro, which in this
+  ## case is `debugEcho ["x + y", " = ", x + y]`.
+  echo body.toStrLit
+  result = body
+
+proc extractTypeImpl(n: NimNode): NimNode =
+  ## attempts to extract the type definition of the given symbol
+  case n.kind
+  of nnkSym: # can extract an impl
+    result = n.getImpl.extractTypeImpl()
+  of nnkObjectTy, nnkRefTy, nnkPtrTy: result = n
+  of nnkBracketExpr:
+    if n.typeKind == ntyTypeDesc:
+      result = n[1].extractTypeImpl()
+    else:
+      doAssert n.typeKind == ntyGenericInst
+      result = n[0].getImpl()
+  of nnkTypeDef:
+    result = n[2]
+  else: error("Invalid node to retrieve type implementation of: " & $n.kind)
+
+proc customPragmaNode(n: NimNode): NimNode =
+  expectKind(n, {nnkSym, nnkDotExpr, nnkBracketExpr, nnkTypeOfExpr, nnkType, nnkCheckedFieldExpr})
+  let
+    typ = n.getTypeInst()
+
+  if typ.kind == nnkBracketExpr and typ.len > 1 and typ[1].kind == nnkProcTy:
+    return typ[1][1]
+  elif typ.typeKind == ntyTypeDesc:
+    let impl = getImpl(
+      if kind(typ[1]) == nnkBracketExpr: typ[1][0]
+      else: typ[1]
+    )
+    if impl.kind == nnkNilLit:
+      return impl
+    elif impl[0].kind == nnkPragmaExpr:
+      return impl[0][1]
+    else:
+      return impl[0] # handle types which don't have macro at all
+
+  if n.kind == nnkSym: # either an variable or a proc
+    let impl = n.getImpl()
+    if impl.kind in RoutineNodes:
+      return impl.pragma
+    elif impl.kind in {nnkIdentDefs, nnkConstDef} and impl[0].kind == nnkPragmaExpr:
+      return impl[0][1]
+    else:
+      let timpl = getImpl(if typ.kind == nnkBracketExpr: typ[0] else: typ)
+      if timpl.len>0 and timpl[0].len>1:
+        return timpl[0][1]
+      else:
+        return timpl
+
+  if n.kind in {nnkDotExpr, nnkCheckedFieldExpr}:
+    let name = $(if n.kind == nnkCheckedFieldExpr: n[0][1] else: n[1])
+    var typInst = getTypeInst(if n.kind == nnkCheckedFieldExpr or n[0].kind == nnkHiddenDeref: n[0][0] else: n[0])
+    while typInst.kind in {nnkVarTy, nnkBracketExpr}: typInst = typInst[0]
+    var typDef = getImpl(typInst)
+    while typDef != nil:
+      typDef.expectKind(nnkTypeDef)
+      let typ = typDef[2].extractTypeImpl()
+      if typ.kind notin {nnkRefTy, nnkPtrTy, nnkObjectTy}: break
+      let isRef = typ.kind in {nnkRefTy, nnkPtrTy}
+      if isRef and typ[0].kind in {nnkSym, nnkBracketExpr}: # defines ref type for another object(e.g. X = ref X)
+        typDef = getImpl(typ[0])
+      else: # object definition, maybe an object directly defined as a ref type
+        let
+          obj = (if isRef: typ[0] else: typ)
+        var identDefsStack = newSeq[NimNode](obj[2].len)
+        for i in 0..<identDefsStack.len: identDefsStack[i] = obj[2][i]
+        while identDefsStack.len > 0:
+          var identDefs = identDefsStack.pop()
+
+          case identDefs.kind
+          of nnkRecList:
+            for child in identDefs.children:
+              identDefsStack.add(child)
+          of nnkRecCase:
+            # Add condition definition
+            identDefsStack.add(identDefs[0])
+            # Add branches
+            for i in 1 ..< identDefs.len:
+              identDefsStack.add(identDefs[i].last)
+          else:
+            for i in 0 .. identDefs.len - 3:
+              let varNode = identDefs[i]
+              if varNode.kind == nnkPragmaExpr:
+                var varName = varNode[0]
+                if varName.kind == nnkPostfix:
+                  # This is a public field. We are skipping the postfix *
+                  varName = varName[1]
+                if eqIdent($varName, name):
+                  return varNode[1]
+
+        if obj[1].kind == nnkOfInherit: # explore the parent object
+          typDef = getImpl(obj[1][0])
+        else:
+          typDef = nil
+
+macro hasCustomPragma*(n: typed, cp: typed{nkSym}): untyped =
+  ## Expands to `true` if expression `n` which is expected to be `nnkDotExpr`
+  ## (if checking a field), a proc or a type has custom pragma `cp`.
+  ##
+  ## See also `getCustomPragmaVal`_.
+  ##
+  ##   ```nim
+  ##   template myAttr() {.pragma.}
+  ##   type
+  ##     MyObj = object
+  ##       myField {.myAttr.}: int
+  ##
+  ##   proc myProc() {.myAttr.} = discard
+  ##
+  ##   var o: MyObj
+  ##   assert(o.myField.hasCustomPragma(myAttr))
+  ##   assert(myProc.hasCustomPragma(myAttr))
+  ##   ```
+  let pragmaNode = customPragmaNode(n)
+  for p in pragmaNode:
+    if (p.kind == nnkSym and p == cp) or
+        (p.kind in nnkPragmaCallKinds and p.len > 0 and p[0].kind == nnkSym and p[0] == cp):
+      return newLit(true)
+  return newLit(false)
+
+macro getCustomPragmaVal*(n: typed, cp: typed{nkSym}): untyped =
+  ## Expands to value of custom pragma `cp` of expression `n` which is expected
+  ## to be `nnkDotExpr`, a proc or a type.
+  ##
+  ## See also `hasCustomPragma`_.
+  ##
+  ##   ```nim
+  ##   template serializationKey(key: string) {.pragma.}
+  ##   type
+  ##     MyObj {.serializationKey: "mo".} = object
+  ##       myField {.serializationKey: "mf".}: int
+  ##   var o: MyObj
+  ##   assert(o.myField.getCustomPragmaVal(serializationKey) == "mf")
+  ##   assert(o.getCustomPragmaVal(serializationKey) == "mo")
+  ##   assert(MyObj.getCustomPragmaVal(serializationKey) == "mo")
+  ##   ```
+  result = nil
+  let pragmaNode = customPragmaNode(n)
+  for p in pragmaNode:
+    if p.kind in nnkPragmaCallKinds and p.len > 0 and p[0].kind == nnkSym and p[0] == cp:
+      if p.len == 2 or (p.len == 3 and p[1].kind == nnkSym and p[1].symKind == nskType):
+        result = p[1]
+      else:
+        let def = p[0].getImpl[3]
+        result = newTree(nnkPar)
+        for i in 1 ..< def.len:
+          let key = def[i][0]
+          let val = p[i]
+          result.add newTree(nnkExprColonExpr, key, val)
+      break
+  if result.kind == nnkEmpty:
+    error(n.repr & " doesn't have a pragma named " & cp.repr()) # returning an empty node results in most cases in a cryptic error,
+
+macro unpackVarargs*(callee: untyped; args: varargs[untyped]): untyped =
+  ## Calls `callee` with `args` unpacked as individual arguments.
+  ## This is useful in 2 cases:
+  ## * when forwarding `varargs[T]` for some typed `T`
+  ## * when forwarding `varargs[untyped]` when `args` can potentially be empty,
+  ##   due to a compiler limitation
+  runnableExamples:
+    template call1(fun: typed; args: varargs[untyped]): untyped =
+      unpackVarargs(fun, args)
+      # when varargsLen(args) > 0: fun(args) else: fun() # this would also work
+    template call2(fun: typed; args: varargs[typed]): untyped =
+      unpackVarargs(fun, args)
+    proc fn1(a = 0, b = 1) = discard (a, b)
+    call1(fn1, 10, 11)
+    call1(fn1) # `args` is empty in this case
+    if false: call2(echo, 10, 11) # would print 1011
+  result = newCall(callee)
+  for i in 0 ..< args.len:
+    result.add args[i]
+
+proc getProjectPath*(): string = discard
+  ## Returns the path to the currently compiling project.
+  ##
+  ## This is not to be confused with `system.currentSourcePath <system.html#currentSourcePath.t>`_
+  ## which returns the path of the source file containing that template
+  ## call.
+  ##
+  ## For example, assume a `dir1/foo.nim` that imports a `dir2/bar.nim`,
+  ## have the `bar.nim` print out both `getProjectPath` and
+  ## `currentSourcePath` outputs.
+  ##
+  ## Now when `foo.nim` is compiled, the `getProjectPath` from
+  ## `bar.nim` will return the `dir1/` path, while the `currentSourcePath`
+  ## will return the path to the `bar.nim` source file.
+  ##
+  ## Now when `bar.nim` is compiled directly, the `getProjectPath`
+  ## will now return the `dir2/` path, and the `currentSourcePath`
+  ## will still return the same path, the path to the `bar.nim` source
+  ## file.
+  ##
+  ## The path returned by this proc is set at compile time.
+  ##
+  ## See also:
+  ## * `getCurrentDir proc <os.html#getCurrentDir>`_
+
+proc getSize*(arg: NimNode): int {.magic: "NSizeOf", noSideEffect.} =
+  ## Returns the same result as `system.sizeof` if the size is
+  ## known by the Nim compiler. Returns a negative value if the Nim
+  ## compiler does not know the size.
+proc getAlign*(arg: NimNode): int {.magic: "NSizeOf", noSideEffect.} =
+  ## Returns the same result as `system.alignof` if the alignment
+  ## is known by the Nim compiler. It works on `NimNode` for use
+  ## in macro context. Returns a negative value if the Nim compiler
+  ## does not know the alignment.
+proc getOffset*(arg: NimNode): int {.magic: "NSizeOf", noSideEffect.} =
+  ## Returns the same result as `system.offsetof` if the offset is
+  ## known by the Nim compiler. It expects a resolved symbol node
+  ## from a field of a type. Therefore it only requires one argument
+  ## instead of two. Returns a negative value if the Nim compiler
+  ## does not know the offset.
 
-macro dumpLisp*(s: stmt): stmt = echo s.lispRepr
-  ## Accepts a block of nimrod code and prints the parsed abstract syntax
-  ## tree using the `toLisp` function. Printing is done *at compile time*.
+proc isExported*(n: NimNode): bool {.noSideEffect.} =
+  ## Returns whether the symbol is exported or not.
+
+proc extractDocCommentsAndRunnables*(n: NimNode): NimNode =
+  ## returns a `nnkStmtList` containing the top-level doc comments and
+  ## runnableExamples in `a`, stopping at the first child that is neither.
+  ## Example:
+  ##
+  ##   ```nim
+  ##   import std/macros
+  ##   macro transf(a): untyped =
+  ##     result = quote do:
+  ##       proc fun2*() = discard
+  ##     let header = extractDocCommentsAndRunnables(a.body)
+  ##     # correct usage: rest is appended
+  ##     result.body = header
+  ##     result.body.add quote do: discard # just an example
+  ##     # incorrect usage: nesting inside a nnkStmtList:
+  ##     # result.body = quote do: (`header`; discard)
   ##
-  ## See `dumpTree`.
+  ##   proc fun*() {.transf.} =
+  ##     ## first comment
+  ##     runnableExamples: discard
+  ##     runnableExamples: discard
+  ##     ## last comment
+  ##     discard # first statement after doc comments + runnableExamples
+  ##     ## not docgen'd
+  ##   ```
 
+  result = newStmtList()
+  for ni in n:
+    case ni.kind
+    of nnkCommentStmt:
+      result.add ni
+    of nnkCall, nnkCommand:
+      if ni[0].kind == nnkIdent and ni[0].eqIdent "runnableExamples":
+        result.add ni
+      else: break
+    else: break
diff --git a/lib/core/rlocks.nim b/lib/core/rlocks.nim
new file mode 100644
index 000000000..8cb0cef05
--- /dev/null
+++ b/lib/core/rlocks.nim
@@ -0,0 +1,57 @@
+#
+#
+#            Nim's Runtime Library
+#        (c) Copyright 2016 Anatoly Galiulin
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+## This module contains Nim's support for reentrant locks.
+
+
+when not compileOption("threads") and not defined(nimdoc):
+  when false:
+    # make rlocks modlue consistent with locks module,
+    # so they can replace each other seamlessly.
+    {.error: "Rlocks requires --threads:on option.".}
+
+import std/private/syslocks
+
+type
+  RLock* = SysLock ## Nim lock, re-entrant
+
+proc initRLock*(lock: var RLock) {.inline.} =
+  ## Initializes the given lock.
+  when defined(posix):
+    var a: SysLockAttr
+    initSysLockAttr(a)
+    setSysLockType(a, SysLockType_Reentrant)
+    initSysLock(lock, a.addr)
+  else:
+    initSysLock(lock)
+
+proc deinitRLock*(lock: RLock) {.inline.} =
+  ## Frees the resources associated with the lock.
+  deinitSys(lock)
+
+proc tryAcquire*(lock: var RLock): bool {.inline.} =
+  ## Tries to acquire the given lock. Returns `true` on success.
+  result = tryAcquireSys(lock)
+
+proc acquire*(lock: var RLock) {.inline.} =
+  ## Acquires the given lock.
+  acquireSys(lock)
+
+proc release*(lock: var RLock) {.inline.} =
+  ## Releases the given lock.
+  releaseSys(lock)
+
+template withRLock*(lock: RLock, code: untyped) =
+  ## Acquires the given lock and then executes the code.
+  acquire(lock)
+  {.locks: [lock].}:
+    try:
+      code
+    finally:
+      release(lock)
diff --git a/lib/core/typeinfo.nim b/lib/core/typeinfo.nim
index 6f8081b5f..f2fee91c4 100755..100644
--- a/lib/core/typeinfo.nim
+++ b/lib/core/typeinfo.nim
@@ -1,248 +1,351 @@
 #
 #
-#            Nimrod's Runtime Library
+#            Nim's Runtime Library
 #        (c) Copyright 2013 Dominik Picheta, Andreas Rumpf
 #
 #    See the file "copying.txt", included in this
 #    distribution, for details about the copyright.
 #
 
-## This module implements an interface to Nimrod's runtime type information.
-## Note that even though ``TAny`` and its operations hide the nasty low level
-## details from its clients, it remains inherently unsafe!
+## This module implements an interface to Nim's `runtime type information`:idx:
+## (`RTTI`:idx:). See the `marshal <marshal.html>`_ module for an example of
+## what this allows you to do.
+##
+## .. note:: Even though `Any` and its operations hide the nasty low level
+##   details from its users, it remains inherently unsafe! Also, Nim's
+##   runtime type information will evolve and may eventually be deprecated.
+##   As an alternative approach to programmatically understanding and
+##   manipulating types, consider using the `macros <macros.html>`_ module to
+##   work with the types' AST representation at compile time. See for example
+##   the `getTypeImpl proc <macros.html#getTypeImpl,NimNode>`_. As an alternative
+##   approach to storing arbitrary types at runtime, consider using generics.
+
+runnableExamples:
+  var x: Any
+
+  var i = 42
+  x = i.toAny
+  assert x.kind == akInt
+  assert x.getInt == 42
+
+  var s = @[1, 2, 3]
+  x = s.toAny
+  assert x.kind == akSequence
+  assert x.len == 3
 
 {.push hints: off.}
 
+include "system/inclrtl.nim"
 include "system/hti.nim"
 
 {.pop.}
 
+when defined(nimPreviewSlimSystem):
+  import std/assertions
+
+
 type
-  TAnyKind* = enum      ## what kind of ``any`` it is
-    akNone = 0,         ## invalid any
-    akBool = 1,         ## any represents a ``bool``
-    akChar = 2,         ## any represents a ``char``
-    akEnum = 14,        ## any represents an enum
-    akArray = 16,       ## any represents an array
-    akObject = 17,      ## any represents an object
-    akTuple = 18,       ## any represents a tuple
-    akSet = 19,         ## any represents a set
-    akRange = 20,       ## any represents a range
-    akPtr = 21,         ## any represents a ptr
-    akRef = 22,         ## any represents a ref
-    akSequence = 24,    ## any represents a sequence
-    akProc = 25,        ## any represents a proc
-    akPointer = 26,     ## any represents a pointer
-    akString = 28,      ## any represents a string
-    akCString = 29,     ## any represents a cstring
-    akInt = 31,         ## any represents an int
-    akInt8 = 32,        ## any represents an int8
-    akInt16 = 33,       ## any represents an int16
-    akInt32 = 34,       ## any represents an int32
-    akInt64 = 35,       ## any represents an int64
-    akFloat = 36,       ## any represents a float
-    akFloat32 = 37,     ## any represents a float32
-    akFloat64 = 38,     ## any represents a float64
-    akFloat128 = 39,    ## any represents a float128
-    akUInt = 40,        ## any represents an unsigned int
-    akUInt8 = 41,       ## any represents an unsigned int8
-    akUInt16 = 42,      ## any represents an unsigned in16
-    akUInt32 = 43,      ## any represents an unsigned int32
-    akUInt64 = 44,      ## any represents an unsigned int64
-    
-  TAny* = object {.pure.} ## can represent any nimrod value; NOTE: the wrapped
-                          ## value can be modified with its wrapper! This means
-                          ## that ``TAny`` keeps a non-traced pointer to its
-                          ## wrapped value and **must not** live longer than
-                          ## its wrapped value.
+  AnyKind* = enum       ## The kind of `Any`.
+    akNone = 0,         ## invalid
+    akBool = 1,         ## bool
+    akChar = 2,         ## char
+    akEnum = 14,        ## enum
+    akArray = 16,       ## array
+    akObject = 17,      ## object
+    akTuple = 18,       ## tuple
+    akSet = 19,         ## set
+    akRange = 20,       ## range
+    akPtr = 21,         ## ptr
+    akRef = 22,         ## ref
+    akSequence = 24,    ## sequence
+    akProc = 25,        ## proc
+    akPointer = 26,     ## pointer
+    akString = 28,      ## string
+    akCString = 29,     ## cstring
+    akInt = 31,         ## int
+    akInt8 = 32,        ## int8
+    akInt16 = 33,       ## int16
+    akInt32 = 34,       ## int32
+    akInt64 = 35,       ## int64
+    akFloat = 36,       ## float
+    akFloat32 = 37,     ## float32
+    akFloat64 = 38,     ## float64
+    akFloat128 = 39,    ## float128
+    akUInt = 40,        ## uint
+    akUInt8 = 41,       ## uint8
+    akUInt16 = 42,      ## uin16
+    akUInt32 = 43,      ## uint32
+    akUInt64 = 44,      ## uint64
+#    akOpt = 44+18       ## the builtin 'opt' type.
+
+  Any* = object
+    ## A type that can represent any nim value.
+    ##
+    ## .. danger:: The wrapped value can be modified with its wrapper! This means
+    ##   that `Any` keeps a non-traced pointer to its wrapped value and
+    ##   **must not** live longer than its wrapped value.
     value: pointer
-    rawType: PNimType
+    when defined(js):
+      rawType: PNimType
+    else:
+      rawTypePtr: pointer
 
   ppointer = ptr pointer
-  pbyteArray = ptr array[0.. 0xffff, int8]
+  pbyteArray = ptr array[0xffff, uint8]
+
+when not defined(gcDestructors):
+  type
+    TGenericSeq {.importc.} = object
+      len, space: int
+      when defined(gogc):
+        elemSize: int
+    PGenSeq = ptr TGenericSeq
+
+  when defined(gogc):
+    const GenericSeqSize = 3 * sizeof(int)
+  else:
+    const GenericSeqSize = 2 * sizeof(int)
 
-  TGenSeq {.pure.} = object
-    len, space: int
-  PGenSeq = ptr TGenSeq
+else:
+  include system/seqs_v2_reimpl
 
-const
-  GenericSeqSize = (2 * sizeof(int))
+from std/private/strimpl import cmpNimIdentifier
 
-proc genericAssign(dest, src: Pointer, mt: PNimType) {.importCompilerProc.}
-proc genericShallowAssign(dest, src: Pointer, mt: PNimType) {.
-  importCompilerProc.}
-proc incrSeq(seq: PGenSeq, elemSize: int): PGenSeq {.importCompilerProc.}
-proc newObj(typ: PNimType, size: int): pointer {.importCompilerProc.}
-proc newSeq(typ: PNimType, len: int): pointer {.importCompilerProc.}
-proc objectInit(dest: Pointer, typ: PNimType) {.importCompilerProc.}
+when not defined(js):
+  template rawType(x: Any): PNimType =
+    cast[PNimType](x.rawTypePtr)
 
-template `+!!`(a, b: expr): expr = cast[pointer](cast[TAddress](a) + b)
+  template `rawType=`(x: var Any, p: PNimType) =
+    x.rawTypePtr = cast[pointer](p)
 
-proc getDiscriminant(aa: Pointer, n: ptr TNimNode): int =
+proc genericAssign(dest, src: pointer, mt: PNimType) {.importCompilerProc.}
+
+when not defined(gcDestructors):
+  proc genericShallowAssign(dest, src: pointer, mt: PNimType) {.importCompilerProc.}
+  proc incrSeq(seq: PGenSeq, elemSize, elemAlign: int): PGenSeq {.importCompilerProc.}
+  proc newObj(typ: PNimType, size: int): pointer {.importCompilerProc.}
+  proc newSeq(typ: PNimType, len: int): pointer {.importCompilerProc.}
+  proc objectInit(dest: pointer, typ: PNimType) {.importCompilerProc.}
+else:
+  proc nimNewObj(size, align: int): pointer {.importCompilerProc.}
+  proc newSeqPayload(cap, elemSize, elemAlign: int): pointer {.importCompilerProc.}
+  proc prepareSeqAddUninit(len: int; p: pointer; addlen, elemSize, elemAlign: int): pointer {.
+    importCompilerProc.}
+  proc zeroNewElements(len: int; p: pointer; addlen, elemSize, elemAlign: int) {.
+    importCompilerProc.}
+
+template `+!!`(a, b): untyped = cast[pointer](cast[int](a) + b)
+
+proc getDiscriminant(aa: pointer, n: ptr TNimNode): int =
   assert(n.kind == nkCase)
   var d: int
-  var a = cast[TAddress](aa)
+  let a = cast[int](aa)
   case n.typ.size
-  of 1: d = ze(cast[ptr int8](a +% n.offset)[])
-  of 2: d = ze(cast[ptr int16](a +% n.offset)[])
-  of 4: d = int(cast[ptr int32](a +% n.offset)[])
+  of 1: d = int(cast[ptr uint8](a +% n.offset)[])
+  of 2: d = int(cast[ptr uint16](a +% n.offset)[])
+  of 4: d = int(cast[ptr uint32](a +% n.offset)[])
+  of 8: d = int(cast[ptr uint64](a +% n.offset)[])
   else: assert(false)
   return d
 
-proc selectBranch(aa: Pointer, n: ptr TNimNode): ptr TNimNode =
-  var discr = getDiscriminant(aa, n)
+proc selectBranch(aa: pointer, n: ptr TNimNode): ptr TNimNode =
+  let discr = getDiscriminant(aa, n)
   if discr <% n.len:
     result = n.sons[discr]
     if result == nil: result = n.sons[n.len]
-    # n.sons[n.len] contains the ``else`` part (but may be nil)
+    # n.sons[n.len] contains the `else` part (but may be nil)
   else:
     result = n.sons[n.len]
 
-proc newAny(value: pointer, rawType: PNimType): TAny =
+proc newAny(value: pointer, rawType: PNimType): Any {.inline.} =
   result.value = value
   result.rawType = rawType
 
-when defined(system.TVarSlot):
-  proc toAny*(x: TVarSlot): TAny {.inline.} =
-    ## constructs a ``TAny`` object from a variable slot ``x``. 
-    ## This captures `x`'s address, so `x` can be modified with its
-    ## ``TAny`` wrapper! The client needs to ensure that the wrapper
-    ## **does not** live longer than `x`!
-    ## This is provided for easier reflection capabilities of a debugger.
-    result.value = x.address
-    result.rawType = x.typ
-
-proc toAny*[T](x: var T): TAny {.inline.} =
-  ## constructs a ``TAny`` object from `x`. This captures `x`'s address, so
-  ## `x` can be modified with its ``TAny`` wrapper! The client needs to ensure
+proc toAny*[T](x: var T): Any {.inline.} =
+  ## Constructs an `Any` object from `x`. This captures `x`'s address, so
+  ## `x` can be modified with its `Any` wrapper! The caller needs to ensure
   ## that the wrapper **does not** live longer than `x`!
-  result.value = addr(x)
-  result.rawType = cast[PNimType](getTypeInfo(x))
-  
-proc kind*(x: TAny): TAnyKind {.inline.} = 
-  ## get the type kind
-  result = TAnyKind(ord(x.rawType.kind))
-
-proc size*(x: TAny): int {.inline.} =
-  ## returns the size of `x`'s type.
+  newAny(addr(x), cast[PNimType](getTypeInfo(x)))
+
+proc kind*(x: Any): AnyKind {.inline.} =
+  ## Gets the type kind.
+  result = AnyKind(ord(x.rawType.kind))
+
+proc size*(x: Any): int {.inline.} =
+  ## Returns the size of `x`'s type.
   result = x.rawType.size
-  
-proc baseTypeKind*(x: TAny): TAnyKind {.inline.} = 
-  ## get the base type's kind; ``akNone`` is returned if `x` has no base type.
+
+proc baseTypeKind*(x: Any): AnyKind {.inline.} =
+  ## Gets the base type's kind. If `x` has no base type, `akNone` is returned.
   if x.rawType.base != nil:
-    result = TAnyKind(ord(x.rawType.base.kind))
+    result = AnyKind(ord(x.rawType.base.kind))
 
-proc baseTypeSize*(x: TAny): int {.inline.} =
-  ## returns the size of `x`'s basetype.
+proc baseTypeSize*(x: Any): int {.inline.} =
+  ## Returns the size of `x`'s base type. If `x` has no base type, 0 is returned.
   if x.rawType.base != nil:
     result = x.rawType.base.size
-  
-proc invokeNew*(x: TAny) =
-  ## performs ``new(x)``. `x` needs to represent a ``ref``.
+
+proc invokeNew*(x: Any) =
+  ## Performs `new(x)`. `x` needs to represent a `ref`.
   assert x.rawType.kind == tyRef
-  var z = newObj(x.rawType, x.rawType.base.size)
-  genericAssign(x.value, addr(z), x.rawType)
+  when defined(gcDestructors):
+    cast[ppointer](x.value)[] = nimNewObj(x.rawType.base.size, x.rawType.base.align)
+  else:
+    var z = newObj(x.rawType, x.rawType.base.size)
+    genericAssign(x.value, addr(z), x.rawType)
 
-proc invokeNewSeq*(x: TAny, len: int) =
-  ## performs ``newSeq(x, len)``. `x` needs to represent a ``seq``.
+proc invokeNewSeq*(x: Any, len: int) =
+  ## Performs `newSeq(x, len)`. `x` needs to represent a `seq`.
   assert x.rawType.kind == tySequence
-  var z = newSeq(x.rawType, len)
-  genericShallowAssign(x.value, addr(z), x.rawType)
+  when defined(gcDestructors):
+    var s = cast[ptr NimSeqV2Reimpl](x.value)
+    s.len = len
+    let elem = x.rawType.base
+    s.p = cast[ptr NimSeqPayloadReimpl](newSeqPayload(len, elem.size, elem.align))
+  else:
+    var z = newSeq(x.rawType, len)
+    genericShallowAssign(x.value, addr(z), x.rawType)
 
-proc extendSeq*(x: TAny) =
-  ## performs ``setLen(x, x.len+1)``. `x` needs to represent a ``seq``.
+proc extendSeq*(x: Any) =
+  ## Performs `setLen(x, x.len+1)`. `x` needs to represent a `seq`.
   assert x.rawType.kind == tySequence
-  var y = cast[ptr PGenSeq](x.value)[]
-  var z = incrSeq(y, x.rawType.base.size)
-  # 'incrSeq' already freed the memory for us and copied over the RC!
-  # So we simply copy the raw pointer into 'x.value':
-  cast[ppointer](x.value)[] = z
-  #genericShallowAssign(x.value, addr(z), x.rawType)
-
-proc setObjectRuntimeType*(x: TAny) =
-  ## this needs to be called to set `x`'s runtime object type field.
+  when defined(gcDestructors):
+    var s = cast[ptr NimSeqV2Reimpl](x.value)
+    let elem = x.rawType.base
+    if s.p == nil or s.p.cap < s.len+1:
+      s.p = cast[ptr NimSeqPayloadReimpl](prepareSeqAddUninit(s.len, s.p, 1, elem.size, elem.align))
+    zeroNewElements(s.len, s.p, 1, elem.size, elem.align)
+    inc s.len
+  else:
+    var y = cast[ptr PGenSeq](x.value)[]
+    var z = incrSeq(y, x.rawType.base.size, x.rawType.base.align)
+    # 'incrSeq' already freed the memory for us and copied over the RC!
+    # So we simply copy the raw pointer into 'x.value':
+    cast[ppointer](x.value)[] = z
+    #genericShallowAssign(x.value, addr(z), x.rawType)
+
+proc setObjectRuntimeType*(x: Any) =
+  ## This needs to be called to set `x`'s runtime object type field.
   assert x.rawType.kind == tyObject
-  objectInit(x.value, x.rawType)
+  when defined(gcDestructors):
+    cast[ppointer](x.value)[] = x.rawType.typeInfoV2
+  else:
+    objectInit(x.value, x.rawType)
 
 proc skipRange(x: PNimType): PNimType {.inline.} =
   result = x
   if result.kind == tyRange: result = result.base
 
-proc `[]`*(x: TAny, i: int): TAny =
-  ## accessor for an any `x` that represents an array or a sequence.
+proc align(address, alignment: int): int =
+  result = (address + (alignment - 1)) and not (alignment - 1)
+
+proc `[]`*(x: Any, i: int): Any =
+  ## Accessor for an any `x` that represents an array or a sequence.
   case x.rawType.kind
   of tyArray:
-    var bs = x.rawType.base.size
-    if i >=% x.rawType.size div bs: 
-      raise newException(EInvalidIndex, "index out of bounds")
+    let bs = x.rawType.base.size
+    if i >=% x.rawType.size div bs:
+      raise newException(IndexDefect, formatErrorIndexBound(i, x.rawType.size div bs))
     return newAny(x.value +!! i*bs, x.rawType.base)
   of tySequence:
-    var s = cast[ppointer](x.value)[]
-    if s == nil: raise newException(EInvalidValue, "sequence is nil")
-    var bs = x.rawType.base.size
-    if i >=% cast[PGenSeq](s).len:
-      raise newException(EInvalidIndex, "index out of bounds")
-    return newAny(s +!! (GenericSeqSize+i*bs), x.rawType.base)
+    when defined(gcDestructors):
+      var s = cast[ptr NimSeqV2Reimpl](x.value)
+      if i >=% s.len:
+        raise newException(IndexDefect, formatErrorIndexBound(i, s.len-1))
+      let bs = x.rawType.base.size
+      let ba = x.rawType.base.align
+      let headerSize = align(sizeof(int), ba)
+      return newAny(s.p +!! (headerSize+i*bs), x.rawType.base)
+    else:
+      var s = cast[ppointer](x.value)[]
+      if s == nil: raise newException(ValueError, "sequence is nil")
+      let bs = x.rawType.base.size
+      if i >=% cast[PGenSeq](s).len:
+        raise newException(IndexDefect, formatErrorIndexBound(i, cast[PGenSeq](s).len-1))
+      return newAny(s +!! (align(GenericSeqSize, x.rawType.base.align)+i*bs), x.rawType.base)
   else: assert false
 
-proc `[]=`*(x: TAny, i: int, y: TAny) =
-  ## accessor for an any `x` that represents an array or a sequence.
+proc `[]=`*(x: Any, i: int, y: Any) =
+  ## Accessor for an any `x` that represents an array or a sequence.
   case x.rawType.kind
   of tyArray:
     var bs = x.rawType.base.size
-    if i >=% x.rawType.size div bs: 
-      raise newException(EInvalidIndex, "index out of bounds")
+    if i >=% x.rawType.size div bs:
+      raise newException(IndexDefect, formatErrorIndexBound(i, x.rawType.size div bs))
     assert y.rawType == x.rawType.base
     genericAssign(x.value +!! i*bs, y.value, y.rawType)
   of tySequence:
-    var s = cast[ppointer](x.value)[]
-    if s == nil: raise newException(EInvalidValue, "sequence is nil")
-    var bs = x.rawType.base.size
-    if i >=% cast[PGenSeq](s).len:
-      raise newException(EInvalidIndex, "index out of bounds")
-    assert y.rawType == x.rawType.base
-    genericAssign(s +!! (GenericSeqSize+i*bs), y.value, y.rawType)
+    when defined(gcDestructors):
+      var s = cast[ptr NimSeqV2Reimpl](x.value)
+      if i >=% s.len:
+        raise newException(IndexDefect, formatErrorIndexBound(i, s.len-1))
+      let bs = x.rawType.base.size
+      let ba = x.rawType.base.align
+      let headerSize = align(sizeof(int), ba)
+      assert y.rawType == x.rawType.base
+      genericAssign(s.p +!! (headerSize+i*bs), y.value, y.rawType)
+    else:
+      var s = cast[ppointer](x.value)[]
+      if s == nil: raise newException(ValueError, "sequence is nil")
+      var bs = x.rawType.base.size
+      if i >=% cast[PGenSeq](s).len:
+        raise newException(IndexDefect, formatErrorIndexBound(i, cast[PGenSeq](s).len-1))
+      assert y.rawType == x.rawType.base
+      genericAssign(s +!! (align(GenericSeqSize, x.rawType.base.align)+i*bs), y.value, y.rawType)
   else: assert false
 
-proc len*(x: TAny): int =
-  ## len for an any `x` that represents an array or a sequence.
+proc len*(x: Any): int =
+  ## `len` for an any `x` that represents an array or a sequence.
   case x.rawType.kind
-  of tyArray: result = x.rawType.size div x.rawType.base.size
-  of tySequence: result = cast[PGenSeq](cast[ppointer](x.value)[]).len
+  of tyArray:
+    result = x.rawType.size div x.rawType.base.size
+  of tySequence:
+    when defined(gcDestructors):
+      result = cast[ptr NimSeqV2Reimpl](x.value).len
+    else:
+      let pgenSeq = cast[PGenSeq](cast[ppointer](x.value)[])
+      if isNil(pgenSeq):
+        result = 0
+      else:
+        result = pgenSeq.len
   else: assert false
 
 
-proc base*(x: TAny): TAny =
-  ## returns base TAny (useful for inherited object types).
+proc base*(x: Any): Any =
+  ## Returns the base type of `x` (useful for inherited object types).
   result.rawType = x.rawType.base
   result.value = x.value
 
 
-proc isNil*(x: TAny): bool =
-  ## `isNil` for an any `x` that represents a sequence, string, cstring,
-  ## proc or some pointer type.
-  assert x.rawType.kind in {tyString, tyCString, tyRef, tyPtr, tyPointer, 
-                            tySequence, tyProc}
+proc isNil*(x: Any): bool =
+  ## `isNil` for an `x` that represents a cstring, proc or
+  ## some pointer type.
+  assert x.rawType.kind in {tyCstring, tyRef, tyPtr, tyPointer, tyProc}
   result = isNil(cast[ppointer](x.value)[])
 
-proc getPointer*(x: TAny): pointer =
-  ## retrieve the pointer value out of `x`. ``x`` needs to be of kind
-  ## ``akString``, ``akCString``, ``akProc``, ``akRef``, ``akPtr``, 
-  ## ``akPointer``, ``akSequence``.
-  assert x.rawType.kind in {tyString, tyCString, tyRef, tyPtr, tyPointer, 
-                            tySequence, tyProc}
+const pointerLike =
+  when defined(gcDestructors): {tyCstring, tyRef, tyPtr, tyPointer, tyProc}
+  else: {tyString, tyCstring, tyRef, tyPtr, tyPointer, tySequence, tyProc}
+
+proc getPointer*(x: Any): pointer =
+  ## Retrieves the pointer value out of `x`. `x` needs to be of kind
+  ## `akString`, `akCString`, `akProc`, `akRef`, `akPtr`,
+  ## `akPointer` or `akSequence`.
+  assert x.rawType.kind in pointerLike
   result = cast[ppointer](x.value)[]
 
-proc setPointer*(x: TAny, y: pointer) =
-  ## sets the pointer value of `x`. ``x`` needs to be of kind
-  ## ``akString``, ``akCString``, ``akProc``, ``akRef``, ``akPtr``, 
-  ## ``akPointer``, ``akSequence``.
-  assert x.rawType.kind in {tyString, tyCString, tyRef, tyPtr, tyPointer, 
-                            tySequence, tyProc}
-  cast[ppointer](x.value)[] = y
+proc setPointer*(x: Any, y: pointer) =
+  ## Sets the pointer value of `x`. `x` needs to be of kind
+  ## `akString`, `akCString`, `akProc`, `akRef`, `akPtr`,
+  ## `akPointer` or `akSequence`.
+  assert x.rawType.kind in pointerLike
+  if y != nil and x.rawType.kind != tyPointer:
+    genericAssign(x.value, y, x.rawType)
+  else:
+    cast[ppointer](x.value)[] = y
 
 proc fieldsAux(p: pointer, n: ptr TNimNode,
-               ret: var seq[tuple[name: cstring, any: TAny]]) =
+               ret: var seq[tuple[name: cstring, any: Any]]) =
   case n.kind
   of nkNone: assert(false)
   of nkSlot:
@@ -255,303 +358,353 @@ proc fieldsAux(p: pointer, n: ptr TNimNode,
     ret.add((n.name, newAny(p +!! n.offset, n.typ)))
     if m != nil: fieldsAux(p, m, ret)
 
-iterator fields*(x: TAny): tuple[name: string, any: TAny] =
-  ## iterates over every active field of the any `x` that represents an object
+iterator fields*(x: Any): tuple[name: string, any: Any] =
+  ## Iterates over every active field of `x`. `x` needs to represent an object
   ## or a tuple.
   assert x.rawType.kind in {tyTuple, tyObject}
-  var p = x.value
+  let p = x.value
   var t = x.rawType
   # XXX BUG: does not work yet, however is questionable anyway
   when false:
     if x.rawType.kind == tyObject: t = cast[ptr PNimType](x.value)[]
-  var n = t.node
-  var ret: seq[tuple[name: cstring, any: TAny]] = @[]
-  fieldsAux(p, n, ret)
+  var ret: seq[tuple[name: cstring, any: Any]]
+  if t.kind == tyObject:
+    while true:
+      fieldsAux(p, t.node, ret)
+      t = t.base
+      if t.isNil: break
+  else:
+    fieldsAux(p, t.node, ret)
   for name, any in items(ret):
     yield ($name, any)
 
-proc cmpIgnoreStyle(a, b: cstring): int {.noSideEffect.} =
-  proc toLower(c: char): char {.inline.} =
-    if c in {'A'..'Z'}: result = chr(ord(c) + (ord('a') - ord('A')))
-    else: result = c
-  var i = 0
-  var j = 0
-  while True:
-    while a[i] == '_': inc(i)
-    while b[j] == '_': inc(j) # BUGFIX: typo
-    var aa = toLower(a[i])
-    var bb = toLower(b[j])
-    result = ord(aa) - ord(bb)
-    if result != 0 or aa == '\0': break
-    inc(i)
-    inc(j)
-
-proc getFieldNode(p: pointer, n: ptr TNimNode,
-                  name: cstring): ptr TNimNode =
+proc getFieldNode(p: pointer, n: ptr TNimNode, name: cstring): ptr TNimNode =
   case n.kind
   of nkNone: assert(false)
   of nkSlot:
-    if cmpIgnoreStyle(n.name, name) == 0:
+    if cmpNimIdentifier(n.name, name) == 0:
       result = n
   of nkList:
-    for i in 0..n.len-1: 
+    for i in 0..n.len-1:
       result = getFieldNode(p, n.sons[i], name)
       if result != nil: break
   of nkCase:
-    if cmpIgnoreStyle(n.name, name) == 0:
+    if cmpNimIdentifier(n.name, name) == 0:
       result = n
     else:
-      var m = selectBranch(p, n)
+      let m = selectBranch(p, n)
       if m != nil: result = getFieldNode(p, m, name)
 
-proc `[]=`*(x: TAny, fieldName: string, value: TAny) =
-  ## sets a field of `x`; `x` represents an object or a tuple.
+proc `[]=`*(x: Any, fieldName: string, value: Any) =
+  ## Sets a field of `x`. `x` needs to represent an object or a tuple.
   var t = x.rawType
   # XXX BUG: does not work yet, however is questionable anyway
   when false:
     if x.rawType.kind == tyObject: t = cast[ptr PNimType](x.value)[]
   assert x.rawType.kind in {tyTuple, tyObject}
-  var n = getFieldNode(x.value, t.node, fieldname)
+  let n = getFieldNode(x.value, t.node, fieldName)
   if n != nil:
     assert n.typ == value.rawType
     genericAssign(x.value +!! n.offset, value.value, value.rawType)
   else:
-    raise newException(EInvalidValue, "invalid field name: " & fieldName)
+    raise newException(ValueError, "invalid field name: " & fieldName)
 
-proc `[]`*(x: TAny, fieldName: string): TAny =
-  ## gets a field of `x`; `x` represents an object or a tuple.
+proc `[]`*(x: Any, fieldName: string): Any =
+  ## Gets a field of `x`. `x` needs to represent an object or a tuple.
   var t = x.rawType
   # XXX BUG: does not work yet, however is questionable anyway
   when false:
     if x.rawType.kind == tyObject: t = cast[ptr PNimType](x.value)[]
   assert x.rawType.kind in {tyTuple, tyObject}
-  var n = getFieldNode(x.value, t.node, fieldname)
+  let n = getFieldNode(x.value, t.node, fieldName)
   if n != nil:
     result.value = x.value +!! n.offset
     result.rawType = n.typ
+  elif x.rawType.kind == tyObject and x.rawType.base != nil:
+    return `[]`(newAny(x.value, x.rawType.base), fieldName)
   else:
-    raise newException(EInvalidValue, "invalid field name: " & fieldName)
+    raise newException(ValueError, "invalid field name: " & fieldName)
 
-proc `[]`*(x: TAny): TAny =
-  ## dereference operation for the any `x` that represents a ptr or a ref.
-  assert x.rawtype.kind in {tyRef, tyPtr}
+proc `[]`*(x: Any): Any =
+  ## Dereference operator for `Any`. `x` needs to represent a ptr or a ref.
+  assert x.rawType.kind in {tyRef, tyPtr}
   result.value = cast[ppointer](x.value)[]
   result.rawType = x.rawType.base
 
-proc `[]=`*(x, y: TAny) =
-  ## dereference operation for the any `x` that represents a ptr or a ref.
-  assert x.rawtype.kind in {tyRef, tyPtr}
+proc `[]=`*(x, y: Any) =
+  ## Dereference operator for `Any`. `x` needs to represent a ptr or a ref.
+  assert x.rawType.kind in {tyRef, tyPtr}
   assert y.rawType == x.rawType.base
   genericAssign(cast[ppointer](x.value)[], y.value, y.rawType)
 
-proc getInt*(x: TAny): int =
-  ## retrieve the int value out of `x`. `x` needs to represent an int.
-  assert skipRange(x.rawtype).kind == tyInt
+proc getInt*(x: Any): int =
+  ## Retrieves the `int` value out of `x`. `x` needs to represent an `int`.
+  assert skipRange(x.rawType).kind == tyInt
   result = cast[ptr int](x.value)[]
 
-proc getInt8*(x: TAny): int8 = 
-  ## retrieve the int8 value out of `x`. `x` needs to represent an int8.
-  assert skipRange(x.rawtype).kind == tyInt8
+proc getInt8*(x: Any): int8 =
+  ## Retrieves the `int8` value out of `x`. `x` needs to represent an `int8`.
+  assert skipRange(x.rawType).kind == tyInt8
   result = cast[ptr int8](x.value)[]
 
-proc getInt16*(x: TAny): int16 = 
-  ## retrieve the int16 value out of `x`. `x` needs to represent an int16.
-  assert skipRange(x.rawtype).kind == tyInt16
+proc getInt16*(x: Any): int16 =
+  ## Retrieves the `int16` value out of `x`. `x` needs to represent an `int16`.
+  assert skipRange(x.rawType).kind == tyInt16
   result = cast[ptr int16](x.value)[]
-  
-proc getInt32*(x: TAny): int32 = 
-  ## retrieve the int32 value out of `x`. `x` needs to represent an int32.
-  assert skipRange(x.rawtype).kind == tyInt32
+
+proc getInt32*(x: Any): int32 =
+  ## Retrieves the `int32` value out of `x`. `x` needs to represent an `int32`.
+  assert skipRange(x.rawType).kind == tyInt32
   result = cast[ptr int32](x.value)[]
 
-proc getInt64*(x: TAny): int64 = 
-  ## retrieve the int64 value out of `x`. `x` needs to represent an int64.
-  assert skipRange(x.rawtype).kind == tyInt64
+proc getInt64*(x: Any): int64 =
+  ## Retrieves the `int64` value out of `x`. `x` needs to represent an `int64`.
+  assert skipRange(x.rawType).kind == tyInt64
   result = cast[ptr int64](x.value)[]
 
-proc getBiggestInt*(x: TAny): biggestInt =
-  ## retrieve the integer value out of `x`. `x` needs to represent
+proc getBiggestInt*(x: Any): BiggestInt =
+  ## Retrieves the integer value out of `x`. `x` needs to represent
   ## some integer, a bool, a char, an enum or a small enough bit set.
-  ## The value might be sign-extended to ``biggestInt``.
-  var t = skipRange(x.rawtype)
+  ## The value might be sign-extended to `BiggestInt`.
+  let t = skipRange(x.rawType)
   case t.kind
-  of tyInt: result = biggestInt(cast[ptr int](x.value)[])
-  of tyInt8: result = biggestInt(cast[ptr int8](x.value)[])
-  of tyInt16: result = biggestInt(cast[ptr int16](x.value)[])
-  of tyInt32: result = biggestInt(cast[ptr int32](x.value)[])
-  of tyInt64: result = biggestInt(cast[ptr int64](x.value)[])
-  of tyBool: result = biggestInt(cast[ptr bool](x.value)[])
-  of tyChar: result = biggestInt(cast[ptr char](x.value)[])
+  of tyInt: result = BiggestInt(cast[ptr int](x.value)[])
+  of tyInt8: result = BiggestInt(cast[ptr int8](x.value)[])
+  of tyInt16: result = BiggestInt(cast[ptr int16](x.value)[])
+  of tyInt32: result = BiggestInt(cast[ptr int32](x.value)[])
+  of tyInt64, tyUInt64: result = BiggestInt(cast[ptr int64](x.value)[])
+  of tyBool: result = BiggestInt(cast[ptr bool](x.value)[])
+  of tyChar: result = BiggestInt(cast[ptr char](x.value)[])
   of tyEnum, tySet:
     case t.size
-    of 1: result = ze64(cast[ptr int8](x.value)[])
-    of 2: result = ze64(cast[ptr int16](x.value)[])
-    of 4: result = biggestInt(cast[ptr int32](x.value)[])
-    of 8: result = biggestInt(cast[ptr int64](x.value)[])
+    of 1: result = int64(cast[ptr uint8](x.value)[])
+    of 2: result = int64(cast[ptr uint16](x.value)[])
+    of 4: result = BiggestInt(cast[ptr int32](x.value)[])
+    of 8: result = BiggestInt(cast[ptr int64](x.value)[])
     else: assert false
+  of tyUInt: result = BiggestInt(cast[ptr uint](x.value)[])
+  of tyUInt8: result = BiggestInt(cast[ptr uint8](x.value)[])
+  of tyUInt16: result = BiggestInt(cast[ptr uint16](x.value)[])
+  of tyUInt32: result = BiggestInt(cast[ptr uint32](x.value)[])
   else: assert false
 
-proc setBiggestInt*(x: TAny, y: biggestInt) =
-  ## sets the integer value of `x`. `x` needs to represent
+proc setBiggestInt*(x: Any, y: BiggestInt) =
+  ## Sets the integer value of `x`. `x` needs to represent
   ## some integer, a bool, a char, an enum or a small enough bit set.
-  var t = skipRange(x.rawtype)
+  let t = skipRange(x.rawType)
   case t.kind
   of tyInt: cast[ptr int](x.value)[] = int(y)
   of tyInt8: cast[ptr int8](x.value)[] = int8(y)
   of tyInt16: cast[ptr int16](x.value)[] = int16(y)
   of tyInt32: cast[ptr int32](x.value)[] = int32(y)
-  of tyInt64: cast[ptr int64](x.value)[] = int64(y)
+  of tyInt64, tyUInt64: cast[ptr int64](x.value)[] = int64(y)
   of tyBool: cast[ptr bool](x.value)[] = y != 0
   of tyChar: cast[ptr char](x.value)[] = chr(y.int)
   of tyEnum, tySet:
     case t.size
-    of 1: cast[ptr int8](x.value)[] = toU8(y.int)
-    of 2: cast[ptr int16](x.value)[] = toU16(y.int)
+    of 1: cast[ptr uint8](x.value)[] = uint8(y.int)
+    of 2: cast[ptr uint16](x.value)[] = uint16(y.int)
     of 4: cast[ptr int32](x.value)[] = int32(y)
     of 8: cast[ptr int64](x.value)[] = y
     else: assert false
+  of tyUInt: cast[ptr uint](x.value)[] = uint(y)
+  of tyUInt8: cast[ptr uint8](x.value)[] = uint8(y)
+  of tyUInt16: cast[ptr uint16](x.value)[] = uint16(y)
+  of tyUInt32: cast[ptr uint32](x.value)[] = uint32(y)
+  else: assert false
+
+proc getUInt*(x: Any): uint =
+  ## Retrieves the `uint` value out of `x`. `x` needs to represent a `uint`.
+  assert skipRange(x.rawType).kind == tyUInt
+  result = cast[ptr uint](x.value)[]
+
+proc getUInt8*(x: Any): uint8 =
+  ## Retrieves the `uint8` value out of `x`. `x` needs to represent a `uint8`.
+  assert skipRange(x.rawType).kind == tyUInt8
+  result = cast[ptr uint8](x.value)[]
+
+proc getUInt16*(x: Any): uint16 =
+  ## Retrieves the `uint16` value out of `x`. `x` needs to represent a `uint16`.
+  assert skipRange(x.rawType).kind == tyUInt16
+  result = cast[ptr uint16](x.value)[]
+
+proc getUInt32*(x: Any): uint32 =
+  ## Retrieves the `uint32` value out of `x`. `x` needs to represent a `uint32`.
+  assert skipRange(x.rawType).kind == tyUInt32
+  result = cast[ptr uint32](x.value)[]
+
+proc getUInt64*(x: Any): uint64 =
+  ## Retrieves the `uint64` value out of `x`. `x` needs to represent a `uint64`.
+  assert skipRange(x.rawType).kind == tyUInt64
+  result = cast[ptr uint64](x.value)[]
+
+proc getBiggestUint*(x: Any): uint64 =
+  ## Retrieves the unsigned integer value out of `x`. `x` needs to
+  ## represent an unsigned integer.
+  let t = skipRange(x.rawType)
+  case t.kind
+  of tyUInt: result = uint64(cast[ptr uint](x.value)[])
+  of tyUInt8: result = uint64(cast[ptr uint8](x.value)[])
+  of tyUInt16: result = uint64(cast[ptr uint16](x.value)[])
+  of tyUInt32: result = uint64(cast[ptr uint32](x.value)[])
+  of tyUInt64: result = uint64(cast[ptr uint64](x.value)[])
   else: assert false
 
-proc getChar*(x: TAny): char =
-  ## retrieve the char value out of `x`. `x` needs to represent a char.
-  var t = skipRange(x.rawtype)
+proc setBiggestUint*(x: Any; y: uint64) =
+  ## Sets the unsigned integer value of `x`. `x` needs to represent an
+  ## unsigned integer.
+  let t = skipRange(x.rawType)
+  case t.kind:
+  of tyUInt: cast[ptr uint](x.value)[] = uint(y)
+  of tyUInt8: cast[ptr uint8](x.value)[] = uint8(y)
+  of tyUInt16: cast[ptr uint16](x.value)[] = uint16(y)
+  of tyUInt32: cast[ptr uint32](x.value)[] = uint32(y)
+  of tyUInt64: cast[ptr uint64](x.value)[] = uint64(y)
+  else: assert false
+
+proc getChar*(x: Any): char =
+  ## Retrieves the `char` value out of `x`. `x` needs to represent a `char`.
+  let t = skipRange(x.rawType)
   assert t.kind == tyChar
   result = cast[ptr char](x.value)[]
 
-proc getBool*(x: TAny): bool =
-  ## retrieve the bool value out of `x`. `x` needs to represent a bool.
-  var t = skipRange(x.rawtype)
+proc getBool*(x: Any): bool =
+  ## Retrieves the `bool` value out of `x`. `x` needs to represent a `bool`.
+  let t = skipRange(x.rawType)
   assert t.kind == tyBool
   result = cast[ptr bool](x.value)[]
 
-proc skipRange*(x: TAny): TAny =
-  ## skips the range information of `x`.
+proc skipRange*(x: Any): Any =
+  ## Skips the range information of `x`.
   assert x.rawType.kind == tyRange
   result.rawType = x.rawType.base
   result.value = x.value
 
-proc getEnumOrdinal*(x: TAny, name: string): int =
-  ## gets the enum field ordinal from `name`. `x` needs to represent an enum
+proc getEnumOrdinal*(x: Any, name: string): int =
+  ## Gets the enum field ordinal from `name`. `x` needs to represent an enum
   ## but is only used to access the type information. In case of an error
-  ## ``low(int)`` is returned.
-  var typ = skipRange(x.rawtype)
+  ## `low(int)` is returned.
+  let typ = skipRange(x.rawType)
   assert typ.kind == tyEnum
-  var n = typ.node
-  var s = n.sons
+  let n = typ.node
+  let s = n.sons
   for i in 0 .. n.len-1:
-    if cmpIgnoreStyle($s[i].name, name) == 0: 
+    if cmpNimIdentifier($s[i].name, name) == 0:
       if ntfEnumHole notin typ.flags:
         return i
       else:
         return s[i].offset
   result = low(int)
 
-proc getEnumField*(x: TAny, ordinalValue: int): string =
-  ## gets the enum field name as a string. `x` needs to represent an enum
+proc getEnumField*(x: Any, ordinalValue: int): string =
+  ## Gets the enum field name as a string. `x` needs to represent an enum
   ## but is only used to access the type information. The field name of
-  ## `ordinalValue` is returned. 
-  var typ = skipRange(x.rawtype)
+  ## `ordinalValue` is returned.
+  let typ = skipRange(x.rawType)
   assert typ.kind == tyEnum
-  var e = ordinalValue
+  let e = ordinalValue
   if ntfEnumHole notin typ.flags:
     if e <% typ.node.len:
       return $typ.node.sons[e].name
   else:
     # ugh we need a slow linear search:
-    var n = typ.node
-    var s = n.sons
+    let n = typ.node
+    let s = n.sons
     for i in 0 .. n.len-1:
       if s[i].offset == e: return $s[i].name
   result = $e
 
-proc getEnumField*(x: TAny): string =
-  ## gets the enum field name as a string. `x` needs to represent an enum.
+proc getEnumField*(x: Any): string =
+  ## Gets the enum field name as a string. `x` needs to represent an enum.
   result = getEnumField(x, getBiggestInt(x).int)
 
-proc getFloat*(x: TAny): float = 
-  ## retrieve the float value out of `x`. `x` needs to represent an float.  
-  assert skipRange(x.rawtype).kind == tyFloat
+proc getFloat*(x: Any): float =
+  ## Retrieves the `float` value out of `x`. `x` needs to represent a `float`.
+  assert skipRange(x.rawType).kind == tyFloat
   result = cast[ptr float](x.value)[]
 
-proc getFloat32*(x: TAny): float32 = 
-  ## retrieve the float32 value out of `x`. `x` needs to represent an float32.
-  assert skipRange(x.rawtype).kind == tyFloat32
+proc getFloat32*(x: Any): float32 =
+  ## Retrieves the `float32` value out of `x`. `x` needs to represent a `float32`.
+  assert skipRange(x.rawType).kind == tyFloat32
   result = cast[ptr float32](x.value)[]
-  
-proc getFloat64*(x: TAny): float64 = 
-  ## retrieve the float64 value out of `x`. `x` needs to represent an float64.
-  assert skipRange(x.rawtype).kind == tyFloat64
+
+proc getFloat64*(x: Any): float64 =
+  ## Retrieves the `float64` value out of `x`. `x` needs to represent a `float64`.
+  assert skipRange(x.rawType).kind == tyFloat64
   result = cast[ptr float64](x.value)[]
 
-proc getBiggestFloat*(x: TAny): biggestFloat =
-  ## retrieve the float value out of `x`. `x` needs to represent
-  ## some float. The value is extended to ``biggestFloat``.
-  case skipRange(x.rawtype).kind
-  of tyFloat: result = biggestFloat(cast[ptr Float](x.value)[])
-  of tyFloat32: result = biggestFloat(cast[ptr Float32](x.value)[])
-  of tyFloat64: result = biggestFloat(cast[ptr Float64](x.value)[])
+proc getBiggestFloat*(x: Any): BiggestFloat =
+  ## Retrieves the float value out of `x`. `x` needs to represent
+  ## some float. The value is extended to `BiggestFloat`.
+  case skipRange(x.rawType).kind
+  of tyFloat: result = BiggestFloat(cast[ptr float](x.value)[])
+  of tyFloat32: result = BiggestFloat(cast[ptr float32](x.value)[])
+  of tyFloat64: result = BiggestFloat(cast[ptr float64](x.value)[])
   else: assert false
 
-proc setBiggestFloat*(x: TAny, y: biggestFloat) =
-  ## sets the float value of `x`. `x` needs to represent
+proc setBiggestFloat*(x: Any, y: BiggestFloat) =
+  ## Sets the float value of `x`. `x` needs to represent
   ## some float.
-  case skipRange(x.rawtype).kind
-  of tyFloat: cast[ptr Float](x.value)[] = y
-  of tyFloat32: cast[ptr Float32](x.value)[] = y
-  of tyFloat64: cast[ptr Float64](x.value)[] = y
+  case skipRange(x.rawType).kind
+  of tyFloat: cast[ptr float](x.value)[] = y
+  of tyFloat32: cast[ptr float32](x.value)[] = y.float32
+  of tyFloat64: cast[ptr float64](x.value)[] = y
   else: assert false
 
-proc getString*(x: TAny): string = 
-  ## retrieve the string value out of `x`. `x` needs to represent a string.
-  assert x.rawtype.kind == tyString
-  if not isNil(cast[ptr pointer](x.value)[]):
+proc getString*(x: Any): string =
+  ## Retrieves the `string` value out of `x`. `x` needs to represent a `string`.
+  assert x.rawType.kind == tyString
+  when defined(gcDestructors):
     result = cast[ptr string](x.value)[]
+  else:
+    if not isNil(cast[ptr pointer](x.value)[]):
+      result = cast[ptr string](x.value)[]
 
-proc setString*(x: TAny, y: string) = 
-  ## sets the string value of `x`. `x` needs to represent a string.
-  assert x.rawtype.kind == tyString
-  cast[ptr string](x.value)[] = y
+proc setString*(x: Any, y: string) =
+  ## Sets the `string` value of `x`. `x` needs to represent a `string`.
+  assert x.rawType.kind == tyString
+  cast[ptr string](x.value)[] = y # also correct for gcDestructors
 
-proc getCString*(x: TAny): cstring = 
-  ## retrieve the cstring value out of `x`. `x` needs to represent a cstring.
-  assert x.rawtype.kind == tyCString
+proc getCString*(x: Any): cstring =
+  ## Retrieves the `cstring` value out of `x`. `x` needs to represent a `cstring`.
+  assert x.rawType.kind == tyCstring
   result = cast[ptr cstring](x.value)[]
 
-proc assign*(x, y: TAny) = 
-  ## copies the value of `y` to `x`. The assignment operator for ``TAny``
+proc assign*(x, y: Any) =
+  ## Copies the value of `y` to `x`. The assignment operator for `Any`
   ## does NOT do this; it performs a shallow copy instead!
   assert y.rawType == x.rawType
   genericAssign(x.value, y.value, y.rawType)
 
-iterator elements*(x: TAny): int =
-  ## iterates over every element of `x` that represents a Nimrod bitset.
+iterator elements*(x: Any): int =
+  ## Iterates over every element of `x`. `x` needs to represent a `set`.
   assert x.rawType.kind == tySet
-  var typ = x.rawtype
-  var p = x.value
+  let typ = x.rawType
+  let p = x.value
   # "typ.slots.len" field is for sets the "first" field
   var u: int64
   case typ.size
-  of 1: u = ze64(cast[ptr int8](p)[])
-  of 2: u = ze64(cast[ptr int16](p)[])
-  of 4: u = ze64(cast[ptr int32](p)[])
+  of 1: u = int64(cast[ptr uint8](p)[])
+  of 2: u = int64(cast[ptr uint16](p)[])
+  of 4: u = int64(cast[ptr uint32](p)[])
   of 8: u = cast[ptr int64](p)[]
   else:
-    var a = cast[pbyteArray](p)
+    let a = cast[pbyteArray](p)
     for i in 0 .. typ.size*8-1:
-      if (ze(a[i div 8]) and (1 shl (i mod 8))) != 0:
-        yield i+typ.node.len
+      if (int(a[i div 8]) and (1 shl (i mod 8))) != 0:
+        yield i + typ.node.len
   if typ.size <= 8:
     for i in 0..sizeof(int64)*8-1:
       if (u and (1'i64 shl int64(i))) != 0'i64:
-        yield i+typ.node.len
+        yield i + typ.node.len
 
-proc inclSetElement*(x: TAny, elem: int) =
-  ## includes an element `elem` in `x`. `x` needs to represent a Nimrod bitset.
+proc inclSetElement*(x: Any, elem: int) =
+  ## Includes an element `elem` in `x`. `x` needs to represent a Nim bitset.
   assert x.rawType.kind == tySet
-  var typ = x.rawtype
-  var p = x.value
+  let typ = x.rawType
+  let p = x.value
   # "typ.slots.len" field is for sets the "first" field
-  var e = elem - typ.node.len
+  let e = elem - typ.node.len
   case typ.size
   of 1:
     var a = cast[ptr int8](p)
@@ -559,7 +712,7 @@ proc inclSetElement*(x: TAny, elem: int) =
   of 2:
     var a = cast[ptr int16](p)
     a[] = a[] or (1'i16 shl int16(e))
-  of 4: 
+  of 4:
     var a = cast[ptr int32](p)
     a[] = a[] or (1'i32 shl int32(e))
   of 8:
@@ -567,65 +720,4 @@ proc inclSetElement*(x: TAny, elem: int) =
     a[] = a[] or (1'i64 shl e)
   else:
     var a = cast[pbyteArray](p)
-    a[e shr 3] = toU8(a[e shr 3] or (1 shl (e and 7)))
-
-when isMainModule:
-  type
-    TE = enum
-      blah, blah2
-  
-    TestObj = object
-      test, asd: int
-      case test2: TE
-      of blah:
-        help: string
-      else:
-        nil
-
-  var test = @[0,1,2,3,4]
-  var x = toAny(test)
-  var y = 78
-  x[4] = toAny(y)
-  assert cast[ptr int](x[2].value)[] == 2
-  
-  var test2: tuple[name: string, s: int] = ("test", 56)
-  var x2 = toAny(test2)
-  var i = 0
-  for n, a in fields(x2):
-    case i
-    of 0: assert n == "name" and $a.kind == "akString"
-    of 1: assert n == "s" and $a.kind == "akInt"
-    else: assert false
-    inc i
-    
-  var test3: TestObj
-  test3.test = 42
-  test3.test2 = blah2
-  var x3 = toAny(test3)
-  i = 0
-  for n, a in fields(x3):
-    case i
-    of 0: assert n == "test" and $a.kind == "akInt" 
-    of 1: assert n == "asd" and $a.kind == "akInt"
-    of 2: assert n == "test2" and $a.kind == "akEnum"
-    else: assert false
-    inc i
-  
-  var test4: ref string
-  new(test4)
-  test4[] = "test"
-  var x4 = toAny(test4)
-  assert($x4[].kind() == "akString")
-  
-  block:
-    # gimme a new scope dammit
-    var myarr: array[0..4, array[0..4, string]] = [
-      ["test", "1", "2", "3", "4"], ["test", "1", "2", "3", "4"], 
-      ["test", "1", "2", "3", "4"], ["test", "1", "2", "3", "4"], 
-      ["test", "1", "2", "3", "4"]]
-    var m = toAny(myArr)
-    for i in 0 .. m.len-1:
-      for j in 0 .. m[i].len-1:
-        echo getString(m[i][j])
-      
-
+    a[e shr 3] = a[e shr 3] or uint8(1 shl (e and 7))
diff --git a/lib/core/unsigned.nim b/lib/core/unsigned.nim
deleted file mode 100644
index a3ddd4125..000000000
--- a/lib/core/unsigned.nim
+++ /dev/null
@@ -1,59 +0,0 @@
-#
-#
-#            Nimrod's Runtime Library
-#        (c) Copyright 2012 Andreas Rumpf
-#
-#    See the file "copying.txt", included in this
-#    distribution, for details about the copyright.
-#
-
-## This module implements basic arithmetic operators for unsigned integers.
-## To discourage users from using ``unsigned``, it's not part of ``system``,
-## but an extra import.
-
-type
-  SomeUInt = uint|uint8|uint16|uint32|uint64
-
-proc `not`*[T: SomeUInt](x: T): T {.magic: "BitnotI", noSideEffect.}
-  ## computes the `bitwise complement` of the integer `x`.
-
-proc `shr`*[T: SomeUInt](x, y: T): T {.magic: "ShrI", noSideEffect.}
-  ## computes the `shift right` operation of `x` and `y`.
-
-proc `shl`*[T: SomeUInt](x, y: T): T {.magic: "ShlI", noSideEffect.}
-  ## computes the `shift left` operation of `x` and `y`.
-
-proc `and`*[T: SomeUInt](x, y: T): T {.magic: "BitandI", noSideEffect.}
-  ## computes the `bitwise and` of numbers `x` and `y`.
-
-proc `or`*[T: SomeUInt](x, y: T): T {.magic: "BitorI", noSideEffect.}
-  ## computes the `bitwise or` of numbers `x` and `y`.
-
-proc `xor`*[T: SomeUInt](x, y: T): T {.magic: "BitxorI", noSideEffect.}
-  ## computes the `bitwise xor` of numbers `x` and `y`.
-
-proc `==`*[T: SomeUInt](x, y: T): bool {.magic: "EqI", noSideEffect.}
-  ## Compares two unsigned integers for equality.
-
-proc `+`*[T: SomeUInt](x, y: T): T {.magic: "AddU", noSideEffect.}
-  ## Binary `+` operator for unsigned integers.
-
-proc `-`*[T: SomeUInt](x, y: T): T {.magic: "SubU", noSideEffect.}
-  ## Binary `-` operator for unsigned integers.
-
-proc `*`*[T: SomeUInt](x, y: T): T {.magic: "MulU", noSideEffect.}
-  ## Binary `*` operator for unsigned integers.
-
-proc `div`*[T: SomeUInt](x, y: T): T {.magic: "DivU", noSideEffect.}
-  ## computes the integer division. This is roughly the same as
-  ## ``floor(x/y)``.
-
-proc `mod`*[T: SomeUInt](x, y: T): T {.magic: "ModU", noSideEffect.}
-  ## computes the integer modulo operation. This is the same as
-  ## ``x - (x div y) * y``.
-
-proc `<=`*[T: SomeUInt](x, y: T): bool {.magic: "LeU", noSideEffect.}
-  ## Returns true iff ``x <= y``.
-
-proc `<`*[T: SomeUInt](x, y: T): bool {.magic: "LtU", noSideEffect.}
-  ## Returns true iff ``unsigned(x) < unsigned(y)``.