summary refs log tree commit diff stats
path: root/compiler
diff options
context:
space:
mode:
Diffstat (limited to 'compiler')
-rw-r--r--compiler/ast.nim32
-rw-r--r--compiler/astalgo.nim48
-rw-r--r--compiler/ccgexprs.nim27
-rw-r--r--compiler/cgen.nim13
-rw-r--r--compiler/commands.nim3
-rw-r--r--compiler/condsyms.nim1
-rw-r--r--compiler/crc.nim147
-rw-r--r--compiler/docgen.nim6
-rw-r--r--compiler/extccomp.nim23
-rw-r--r--compiler/forloops.nim6
-rw-r--r--compiler/guards.nim16
-rw-r--r--compiler/idents.nim10
-rw-r--r--compiler/installer.ini1
-rw-r--r--compiler/jsgen.nim78
-rw-r--r--compiler/lambdalifting.nim6
-rw-r--r--compiler/lexer.nim388
-rw-r--r--compiler/modules.nim10
-rw-r--r--compiler/msgs.nim93
-rw-r--r--compiler/nimfix/nimfix.nim14
-rw-r--r--compiler/nimfix/pretty.nim20
-rw-r--r--compiler/nimfix/prettybase.nim7
-rw-r--r--compiler/nimsuggest/nimsuggest.nim328
-rw-r--r--compiler/nimsuggest/nimsuggest.nim.cfg17
-rw-r--r--compiler/nodejs.nim2
-rw-r--r--compiler/options.nim11
-rw-r--r--compiler/parser.nim14
-rw-r--r--compiler/patterns.nim4
-rw-r--r--compiler/plugins/locals/locals.nim3
-rw-r--r--compiler/pragmas.nim4
-rw-r--r--compiler/rodread.nim24
-rw-r--r--compiler/rodwrite.nim13
-rw-r--r--compiler/securehash.nim199
-rw-r--r--compiler/semcall.nim5
-rw-r--r--compiler/semfold.nim48
-rw-r--r--compiler/sempass2.nim10
-rw-r--r--compiler/semstmts.nim2
-rw-r--r--compiler/treetab.nim14
-rw-r--r--compiler/vm.nim6
-rw-r--r--compiler/vmgen.nim30
-rw-r--r--compiler/wordrecg.nim4
40 files changed, 769 insertions, 918 deletions
diff --git a/compiler/ast.nim b/compiler/ast.nim
index 64cb1b1bc..167f58d0b 100644
--- a/compiler/ast.nim
+++ b/compiler/ast.nim
@@ -10,7 +10,7 @@
 # abstract syntax tree + symbol table
 
 import
-  msgs, hashes, nversion, options, strutils, crc, ropes, idents, lists,
+  msgs, hashes, nversion, options, strutils, securehash, ropes, idents, lists,
   intsets, idgen
 
 type
@@ -423,6 +423,7 @@ type
                 # but unfortunately it has measurable impact for compilation
                 # efficiency
     nfTransf,   # node has been transformed
+    nfNoRewrite # node should not be transformed anymore
     nfSem       # node has been checked for semantics
     nfLL        # node has gone through lambda lifting
     nfDotField  # the call can use a dot operator
@@ -538,22 +539,21 @@ type
     mIncl, mExcl, mCard, mChr,
     mGCref, mGCunref,
 
-    mAddI, mSubI, mMulI, mDivI, mModI, mAddI64, mSubI64, mMulI64,
-    mDivI64, mModI64, mSucc, mPred,
+    mAddI, mSubI, mMulI, mDivI, mModI,
+    mSucc, mPred,
     mAddF64, mSubF64, mMulF64, mDivF64,
 
     mShrI, mShlI, mBitandI, mBitorI, mBitxorI, mMinI, mMaxI,
-    mShrI64, mShlI64, mBitandI64, mBitorI64, mBitxorI64,
     mMinF64, mMaxF64, mAddU, mSubU, mMulU,
     mDivU, mModU, mEqI, mLeI,
     mLtI,
-    mEqI64, mLeI64, mLtI64, mEqF64, mLeF64, mLtF64,
+    mEqF64, mLeF64, mLtF64,
     mLeU, mLtU, mLeU64, mLtU64,
     mEqEnum, mLeEnum, mLtEnum, mEqCh, mLeCh, mLtCh, mEqB, mLeB, mLtB, mEqRef,
     mEqUntracedRef, mLePtr, mLtPtr, mEqCString, mXor, mEqProc, mUnaryMinusI,
-    mUnaryMinusI64, mAbsI, mAbsI64, mNot,
+    mUnaryMinusI64, mAbsI, mNot,
     mUnaryPlusI, mBitnotI,
-    mBitnotI64, mUnaryPlusF64, mUnaryMinusF64, mAbsF64, mZe8ToI, mZe8ToI64,
+    mUnaryPlusF64, mUnaryMinusF64, mAbsF64, mZe8ToI, mZe8ToI64,
     mZe16ToI, mZe16ToI64, mZe32ToI64, mZeIToI64, mToU8, mToU16, mToU32,
     mToFloat, mToBiggestFloat, mToInt, mToBiggestInt, mCharToStr, mBoolToStr,
     mIntToStr, mInt64ToStr, mFloatToStr, mCStrToStr, mStrToStr, mEnumToStr,
@@ -593,20 +593,19 @@ const
     mPred, mInc, mDec, mOrd, mLengthOpenArray,
     mLengthStr, mLengthArray, mLengthSeq, mXLenStr, mXLenSeq,
     mIncl, mExcl, mCard, mChr,
-    mAddI, mSubI, mMulI, mDivI, mModI, mAddI64, mSubI64, mMulI64,
-    mDivI64, mModI64, mAddF64, mSubF64, mMulF64, mDivF64,
+    mAddI, mSubI, mMulI, mDivI, mModI,
+    mAddF64, mSubF64, mMulF64, mDivF64,
     mShrI, mShlI, mBitandI, mBitorI, mBitxorI, mMinI, mMaxI,
-    mShrI64, mShlI64, mBitandI64, mBitorI64, mBitxorI64,
     mMinF64, mMaxF64, mAddU, mSubU, mMulU,
     mDivU, mModU, mEqI, mLeI,
     mLtI,
-    mEqI64, mLeI64, mLtI64, mEqF64, mLeF64, mLtF64,
+    mEqF64, mLeF64, mLtF64,
     mLeU, mLtU, mLeU64, mLtU64,
     mEqEnum, mLeEnum, mLtEnum, mEqCh, mLeCh, mLtCh, mEqB, mLeB, mLtB, mEqRef,
     mEqProc, mEqUntracedRef, mLePtr, mLtPtr, mEqCString, mXor, mUnaryMinusI,
-    mUnaryMinusI64, mAbsI, mAbsI64, mNot,
+    mUnaryMinusI64, mAbsI, mNot,
     mUnaryPlusI, mBitnotI,
-    mBitnotI64, mUnaryPlusF64, mUnaryMinusF64, mAbsF64, mZe8ToI, mZe8ToI64,
+    mUnaryPlusF64, mUnaryMinusF64, mAbsF64, mZe8ToI, mZe8ToI64,
     mZe16ToI, mZe16ToI64, mZe32ToI64, mZeIToI64, mToU8, mToU16, mToU32,
     mToFloat, mToBiggestFloat, mToInt, mToBiggestInt, mCharToStr, mBoolToStr,
     mIntToStr, mInt64ToStr, mFloatToStr, mCStrToStr, mStrToStr, mEnumToStr,
@@ -842,7 +841,7 @@ type
     data*: TIdNodePairSeq
 
   TNodePair* = object
-    h*: THash                 # because it is expensive to compute!
+    h*: Hash                 # because it is expensive to compute!
     key*: PNode
     val*: int
 
@@ -947,6 +946,9 @@ proc add*(father, son: PNode) =
 proc `[]`*(n: PNode, i: int): PNode {.inline.} =
   result = n.sons[i]
 
+template `-|`*(b, s: expr): expr =
+  (if b >= 0: b else: s.len + b)
+
 # son access operators with support for negative indices
 template `{}`*(n: PNode, i: int): expr = n[i -| n]
 template `{}=`*(n: PNode, i: int, s: PNode): stmt =
@@ -1345,7 +1347,7 @@ proc propagateToOwner*(owner, elem: PType) =
       owner.flags.incl tfHasAsgn
 
   if owner.kind notin {tyProc, tyGenericInst, tyGenericBody,
-                       tyGenericInvocation}:
+                       tyGenericInvocation, tyPtr}:
     let elemB = elem.skipTypes({tyGenericInst})
     if elemB.isGCedMem or tfHasGCedMem in elemB.flags:
       # for simplicity, we propagate this flag even to generics. We then
diff --git a/compiler/astalgo.nim b/compiler/astalgo.nim
index 1707718d7..5980edb27 100644
--- a/compiler/astalgo.nim
+++ b/compiler/astalgo.nim
@@ -14,7 +14,7 @@
 import
   ast, hashes, intsets, strutils, options, msgs, ropes, idents, rodutils
 
-proc hashNode*(p: RootRef): THash
+proc hashNode*(p: RootRef): Hash
 proc treeToYaml*(n: PNode, indent: int = 0, maxRecDepth: int = - 1): Rope
   # Convert a tree into its YAML representation; this is used by the
   # YAML code generator and it is invaluable for debugging purposes.
@@ -49,7 +49,7 @@ proc strTableGet*(t: TStrTable, name: PIdent): PSym
 
 type
   TTabIter*{.final.} = object # consider all fields here private
-    h*: THash                 # current hash
+    h*: Hash                  # current hash
 
 proc initTabIter*(ti: var TTabIter, tab: TStrTable): PSym
 proc nextIter*(ti: var TTabIter, tab: TStrTable): PSym
@@ -65,7 +65,7 @@ proc nextIter*(ti: var TTabIter, tab: TStrTable): PSym
 
 type
   TIdentIter*{.final.} = object # iterator over all syms with same identifier
-    h*: THash                   # current hash
+    h*: Hash                    # current hash
     name*: PIdent
 
 
@@ -94,7 +94,7 @@ proc getSymFromList*(list: PNode, ident: PIdent, start: int = 0): PSym
 proc lookupInRecord*(n: PNode, field: PIdent): PSym
 proc getModule*(s: PSym): PSym
 proc mustRehash*(length, counter: int): bool
-proc nextTry*(h, maxHash: THash): THash {.inline.}
+proc nextTry*(h, maxHash: Hash): Hash {.inline.}
 
 # ------------- table[int, int] ---------------------------------------------
 const
@@ -196,7 +196,7 @@ proc getSymFromList(list: PNode, ident: PIdent, start: int = 0): PSym =
     else: internalError(list.info, "getSymFromList")
   result = nil
 
-proc hashNode(p: RootRef): THash =
+proc hashNode(p: RootRef): Hash =
   result = hash(cast[pointer](p))
 
 proc mustRehash(length, counter: int): bool =
@@ -466,7 +466,7 @@ proc debug(n: PNode) =
 const
   EmptySeq = @[]
 
-proc nextTry(h, maxHash: THash): THash =
+proc nextTry(h, maxHash: Hash): Hash =
   result = ((5 * h) + 1) and maxHash
   # For any initial h in range(maxHash), repeating that maxHash times
   # generates each int in range(maxHash) exactly once (see any text on
@@ -474,7 +474,7 @@ proc nextTry(h, maxHash: THash): THash =
 
 proc objectSetContains(t: TObjectSet, obj: RootRef): bool =
   # returns true whether n is in t
-  var h: THash = hashNode(obj) and high(t.data) # start with real hash value
+  var h: Hash = hashNode(obj) and high(t.data) # start with real hash value
   while t.data[h] != nil:
     if t.data[h] == obj:
       return true
@@ -482,7 +482,7 @@ proc objectSetContains(t: TObjectSet, obj: RootRef): bool =
   result = false
 
 proc objectSetRawInsert(data: var TObjectSeq, obj: RootRef) =
-  var h: THash = hashNode(obj) and high(data)
+  var h: Hash = hashNode(obj) and high(data)
   while data[h] != nil:
     assert(data[h] != obj)
     h = nextTry(h, high(data))
@@ -503,7 +503,7 @@ proc objectSetIncl(t: var TObjectSet, obj: RootRef) =
 
 proc objectSetContainsOrIncl(t: var TObjectSet, obj: RootRef): bool =
   # returns true if obj is already in the string table:
-  var h: THash = hashNode(obj) and high(t.data)
+  var h: Hash = hashNode(obj) and high(t.data)
   while true:
     var it = t.data[h]
     if it == nil: break
@@ -520,7 +520,7 @@ proc objectSetContainsOrIncl(t: var TObjectSet, obj: RootRef): bool =
   result = false
 
 proc tableRawGet(t: TTable, key: RootRef): int =
-  var h: THash = hashNode(key) and high(t.data) # start with real hash value
+  var h: Hash = hashNode(key) and high(t.data) # start with real hash value
   while t.data[h].key != nil:
     if t.data[h].key == key:
       return h
@@ -529,7 +529,7 @@ proc tableRawGet(t: TTable, key: RootRef): int =
 
 proc tableSearch(t: TTable, key, closure: RootRef,
                  comparator: TCmpProc): RootRef =
-  var h: THash = hashNode(key) and high(t.data) # start with real hash value
+  var h: Hash = hashNode(key) and high(t.data) # start with real hash value
   while t.data[h].key != nil:
     if t.data[h].key == key:
       if comparator(t.data[h].val, closure):
@@ -544,7 +544,7 @@ proc tableGet(t: TTable, key: RootRef): RootRef =
   else: result = nil
 
 proc tableRawInsert(data: var TPairSeq, key, val: RootRef) =
-  var h: THash = hashNode(key) and high(data)
+  var h: Hash = hashNode(key) and high(data)
   while data[h].key != nil:
     assert(data[h].key != key)
     h = nextTry(h, high(data))
@@ -569,7 +569,7 @@ proc tablePut(t: var TTable, key, val: RootRef) =
     inc(t.counter)
 
 proc strTableContains(t: TStrTable, n: PSym): bool =
-  var h: THash = n.name.h and high(t.data) # start with real hash value
+  var h: Hash = n.name.h and high(t.data) # start with real hash value
   while t.data[h] != nil:
     if (t.data[h] == n):
       return true
@@ -577,7 +577,7 @@ proc strTableContains(t: TStrTable, n: PSym): bool =
   result = false
 
 proc strTableRawInsert(data: var TSymSeq, n: PSym) =
-  var h: THash = n.name.h and high(data)
+  var h: Hash = n.name.h and high(data)
   if sfImmediate notin n.flags:
     # fast path:
     while data[h] != nil:
@@ -606,7 +606,7 @@ proc strTableRawInsert(data: var TSymSeq, n: PSym) =
 
 proc symTabReplaceRaw(data: var TSymSeq, prevSym: PSym, newSym: PSym) =
   assert prevSym.name.h == newSym.name.h
-  var h: THash = prevSym.name.h and high(data)
+  var h: Hash = prevSym.name.h and high(data)
   while data[h] != nil:
     if data[h] == prevSym:
       data[h] = newSym
@@ -640,7 +640,7 @@ proc strTableIncl*(t: var TStrTable, n: PSym): bool {.discardable.} =
   # It is essential that `n` is written nevertheless!
   # This way the newest redefinition is picked by the semantic analyses!
   assert n.name != nil
-  var h: THash = n.name.h and high(t.data)
+  var h: Hash = n.name.h and high(t.data)
   var replaceSlot = -1
   while true:
     var it = t.data[h]
@@ -666,7 +666,7 @@ proc strTableIncl*(t: var TStrTable, n: PSym): bool {.discardable.} =
   result = false
 
 proc strTableGet(t: TStrTable, name: PIdent): PSym =
-  var h: THash = name.h and high(t.data)
+  var h: Hash = name.h and high(t.data)
   while true:
     result = t.data[h]
     if result == nil: break
@@ -694,7 +694,7 @@ proc nextIdentIter(ti: var TIdentIter, tab: TStrTable): PSym =
 
 proc nextIdentExcluding*(ti: var TIdentIter, tab: TStrTable,
                          excluding: IntSet): PSym =
-  var h: THash = ti.h and high(tab.data)
+  var h: Hash = ti.h and high(tab.data)
   var start = h
   result = tab.data[h]
   while result != nil:
@@ -743,7 +743,7 @@ proc hasEmptySlot(data: TIdPairSeq): bool =
   result = false
 
 proc idTableRawGet(t: TIdTable, key: int): int =
-  var h: THash
+  var h: Hash
   h = key and high(t.data)    # start with real hash value
   while t.data[h].key != nil:
     if t.data[h].key.id == key:
@@ -772,7 +772,7 @@ iterator pairs*(t: TIdTable): tuple[key: int, value: RootRef] =
       yield (t.data[i].key.id, t.data[i].val)
 
 proc idTableRawInsert(data: var TIdPairSeq, key: PIdObj, val: RootRef) =
-  var h: THash
+  var h: Hash
   h = key.id and high(data)
   while data[h].key != nil:
     assert(data[h].key.id != key.id)
@@ -805,7 +805,7 @@ iterator idTablePairs*(t: TIdTable): tuple[key: PIdObj, val: RootRef] =
     if not isNil(t.data[i].key): yield (t.data[i].key, t.data[i].val)
 
 proc idNodeTableRawGet(t: TIdNodeTable, key: PIdObj): int =
-  var h: THash
+  var h: Hash
   h = key.id and high(t.data) # start with real hash value
   while t.data[h].key != nil:
     if t.data[h].key.id == key.id:
@@ -824,7 +824,7 @@ proc idNodeTableGetLazy*(t: TIdNodeTable, key: PIdObj): PNode =
     result = idNodeTableGet(t, key)
 
 proc idNodeTableRawInsert(data: var TIdNodePairSeq, key: PIdObj, val: PNode) =
-  var h: THash
+  var h: Hash
   h = key.id and high(data)
   while data[h].key != nil:
     assert(data[h].key.id != key.id)
@@ -863,7 +863,7 @@ proc initIITable(x: var TIITable) =
   for i in countup(0, StartSize - 1): x.data[i].key = InvalidKey
 
 proc iiTableRawGet(t: TIITable, key: int): int =
-  var h: THash
+  var h: Hash
   h = key and high(t.data)    # start with real hash value
   while t.data[h].key != InvalidKey:
     if t.data[h].key == key: return h
@@ -876,7 +876,7 @@ proc iiTableGet(t: TIITable, key: int): int =
   else: result = InvalidKey
 
 proc iiTableRawInsert(data: var TIIPairSeq, key, val: int) =
-  var h: THash
+  var h: Hash
   h = key and high(data)
   while data[h].key != InvalidKey:
     assert(data[h].key != key)
diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim
index 05a3602d1..55fa7564c 100644
--- a/compiler/ccgexprs.nim
+++ b/compiler/ccgexprs.nim
@@ -503,15 +503,15 @@ proc binaryArithOverflow(p: BProc, e: PNode, d: var TLoc, m: TMagic) =
       "$# = #addInt($#, $#);$n", "$# = #subInt($#, $#);$n",
       "$# = #mulInt($#, $#);$n", "$# = #divInt($#, $#);$n",
       "$# = #modInt($#, $#);$n",
+      "$# = #addInt($#, $#);$n", "$# = #subInt($#, $#);$n"]
+    prc64: array[mAddI..mPred, string] = [
       "$# = #addInt64($#, $#);$n", "$# = #subInt64($#, $#);$n",
       "$# = #mulInt64($#, $#);$n", "$# = #divInt64($#, $#);$n",
       "$# = #modInt64($#, $#);$n",
-      "$# = #addInt($#, $#);$n", "$# = #subInt($#, $#);$n"]
+      "$# = #addInt64($#, $#);$n", "$# = #subInt64($#, $#);$n"]
     opr: array[mAddI..mPred, string] = [
       "($#)($# + $#)", "($#)($# - $#)", "($#)($# * $#)",
       "($#)($# / $#)", "($#)($# % $#)",
-      "($#)($# + $#)", "($#)($# - $#)", "($#)($# * $#)",
-      "($#)($# / $#)", "($#)($# % $#)",
       "($#)($# + $#)", "($#)($# - $#)"]
   var a, b: TLoc
   assert(e.sons[1].typ != nil)
@@ -525,16 +525,16 @@ proc binaryArithOverflow(p: BProc, e: PNode, d: var TLoc, m: TMagic) =
     let res = opr[m] % [getTypeDesc(p.module, t), rdLoc(a), rdLoc(b)]
     putIntoDest(p, d, e.typ, res)
   else:
-    let res = binaryArithOverflowRaw(p, t, a, b, prc[m])
+    let res = binaryArithOverflowRaw(p, t, a, b,
+                                   if t.kind == tyInt64: prc64[m] else: prc[m])
     putIntoDest(p, d, e.typ, "($#)($#)" % [getTypeDesc(p.module, t), res])
 
 proc unaryArithOverflow(p: BProc, e: PNode, d: var TLoc, m: TMagic) =
   const
-    opr: array[mUnaryMinusI..mAbsI64, string] = [
+    opr: array[mUnaryMinusI..mAbsI, string] = [
       mUnaryMinusI: "((NI$2)-($1))",
       mUnaryMinusI64: "-($1)",
-      mAbsI: "($1 > 0? ($1) : -($1))",
-      mAbsI64: "($1 > 0? ($1) : -($1))"]
+      mAbsI: "($1 > 0? ($1) : -($1))"]
   var
     a: TLoc
     t: PType
@@ -561,11 +561,6 @@ proc binaryArith(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
       "($4)($1 ^ $2)",      # BitxorI
       "(($1 <= $2) ? $1 : $2)", # MinI
       "(($1 >= $2) ? $1 : $2)", # MaxI
-      "($4)((NU64)($1) >> (NU64)($2))", # ShrI64
-      "($4)((NU64)($1) << (NU64)($2))", # ShlI64
-      "($4)($1 & $2)",            # BitandI64
-      "($4)($1 | $2)",            # BitorI64
-      "($4)($1 ^ $2)",            # BitxorI64
       "(($1 <= $2) ? $1 : $2)", # MinF64
       "(($1 >= $2) ? $1 : $2)", # MaxF64
       "($4)((NU$3)($1) + (NU$3)($2))", # AddU
@@ -576,9 +571,6 @@ proc binaryArith(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
       "($1 == $2)",           # EqI
       "($1 <= $2)",           # LeI
       "($1 < $2)",            # LtI
-      "($1 == $2)",           # EqI64
-      "($1 <= $2)",           # LeI64
-      "($1 < $2)",            # LtI64
       "($1 == $2)",           # EqF64
       "($1 <= $2)",           # LeF64
       "($1 < $2)",            # LtF64
@@ -638,7 +630,6 @@ proc unaryArith(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
     unArithTab: array[mNot..mToBiggestInt, string] = ["!($1)", # Not
       "$1",                   # UnaryPlusI
       "($3)((NU$2) ~($1))",   # BitnotI
-      "($3)((NU$2) ~($1))",   # BitnotI64
       "$1",                   # UnaryPlusF64
       "-($1)",                # UnaryMinusF64
       "($1 > 0? ($1) : -($1))", # AbsF64; BUGFIX: fabs() makes problems
@@ -1661,7 +1652,7 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
   case op
   of mOr, mAnd: genAndOr(p, e, d, op)
   of mNot..mToBiggestInt: unaryArith(p, e, d, op)
-  of mUnaryMinusI..mAbsI64: unaryArithOverflow(p, e, d, op)
+  of mUnaryMinusI..mAbsI: unaryArithOverflow(p, e, d, op)
   of mAddF64..mDivF64: binaryFloatArith(p, e, d, op)
   of mShrI..mXor: binaryArith(p, e, d, op)
   of mEqProc: genEqProc(p, e, d)
@@ -2150,7 +2141,7 @@ proc genNamedConstExpr(p: BProc, n: PNode): Rope =
 proc genConstSimpleList(p: BProc, n: PNode): Rope =
   var length = sonsLen(n)
   result = rope("{")
-  for i in countup(0, length - 2):
+  for i in countup(ord(n.kind == nkObjConstr), length - 2):
     addf(result, "$1,$n", [genNamedConstExpr(p, n.sons[i])])
   if length > 0: add(result, genNamedConstExpr(p, n.sons[length - 1]))
   addf(result, "}$n", [])
diff --git a/compiler/cgen.nim b/compiler/cgen.nim
index 4b0bac28a..390150cf7 100644
--- a/compiler/cgen.nim
+++ b/compiler/cgen.nim
@@ -10,12 +10,11 @@
 ## This module implements the C code generator.
 
 import
-  ast, astalgo, hashes, trees, platform, magicsys, extccomp,
-  options, intsets,
-  nversion, nimsets, msgs, crc, bitsets, idents, lists, types, ccgutils, os,
-  ropes, math, passes, rodread, wordrecg, treetab, cgmeth, condsyms,
-  rodutils, renderer, idgen, cgendata, ccgmerge, semfold, aliases, lowerings,
-  semparallel
+  ast, astalgo, hashes, trees, platform, magicsys, extccomp, options, intsets,
+  nversion, nimsets, msgs, securehash, bitsets, idents, lists, types,
+  ccgutils, os, ropes, math, passes, rodread, wordrecg, treetab, cgmeth,
+  condsyms, rodutils, renderer, idgen, cgendata, ccgmerge, semfold, aliases,
+  lowerings, semparallel
 
 import strutils except `%` # collides with ropes.`%`
 
@@ -721,6 +720,8 @@ proc genProcPrototype(m: BModule, sym: PSym) =
                         getTypeDesc(m, sym.loc.t), mangleDynLibProc(sym)))
   elif not containsOrIncl(m.declaredProtos, sym.id):
     var header = genProcHeader(m, sym)
+    if sfNoReturn in sym.flags and hasDeclspec in extccomp.CC[cCompiler].props:
+      header = "__declspec(noreturn) " & header
     if sym.typ.callConv != ccInline and crossesCppBoundary(m, sym):
       header = "extern \"C\" " & header
     if sfPure in sym.flags and hasAttribute in CC[cCompiler].props:
diff --git a/compiler/commands.nim b/compiler/commands.nim
index d0719a420..7c8abd9b8 100644
--- a/compiler/commands.nim
+++ b/compiler/commands.nim
@@ -537,6 +537,9 @@ proc processSwitch(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) =
   of "genscript":
     expectNoArg(switch, arg, pass, info)
     incl(gGlobalOptions, optGenScript)
+  of "usecolors":
+    expectNoArg(switch, arg, pass, info)
+    incl(gGlobalOptions, optUseColors)
   of "lib":
     expectArg(switch, arg, pass, info)
     libpath = processPath(arg, notRelativeToProj=true)
diff --git a/compiler/condsyms.nim b/compiler/condsyms.nim
index ad7d80c85..34322471f 100644
--- a/compiler/condsyms.nim
+++ b/compiler/condsyms.nim
@@ -88,3 +88,4 @@ proc initDefines*() =
   defineSymbol("nimalias")
   defineSymbol("nimlocks")
   defineSymbol("nimnode")
+  defineSymbol("nimnomagic64")
diff --git a/compiler/crc.nim b/compiler/crc.nim
deleted file mode 100644
index a8b61f2a5..000000000
--- a/compiler/crc.nim
+++ /dev/null
@@ -1,147 +0,0 @@
-#
-#
-#           The Nim Compiler
-#        (c) Copyright 2012 Andreas Rumpf
-#
-#    See the file "copying.txt", included in this
-#    distribution, for details about the copyright.
-#
-
-import 
-  strutils
-
-type 
-  TCrc32* = int32
-
-const 
-  InitCrc32* = TCrc32(- 1)
-  InitAdler32* = int32(1)
-
-proc updateCrc32*(val: int8, crc: TCrc32): TCrc32 {.inline.}
-proc updateCrc32*(val: char, crc: TCrc32): TCrc32 {.inline.}
-proc crcFromBuf*(buf: pointer, length: int): TCrc32
-proc strCrc32*(s: string): TCrc32
-proc crcFromFile*(filename: string): TCrc32
-proc updateAdler32*(adler: int32, buf: pointer, length: int): int32
-# implementation
-
-type 
-  TCRC_TabEntry = int
-
-const 
-  crc32table: array[0..255, TCRC_TabEntry] = [0, 1996959894, - 301047508, 
-    - 1727442502, 124634137, 1886057615, - 379345611, - 1637575261, 249268274, 
-    2044508324, - 522852066, - 1747789432, 162941995, 2125561021, - 407360249, 
-    - 1866523247, 498536548, 1789927666, - 205950648, - 2067906082, 450548861, 
-    1843258603, - 187386543, - 2083289657, 325883990, 1684777152, - 43845254, 
-    - 1973040660, 335633487, 1661365465, - 99664541, - 1928851979, 997073096, 
-    1281953886, - 715111964, - 1570279054, 1006888145, 1258607687, - 770865667, 
-    - 1526024853, 901097722, 1119000684, - 608450090, - 1396901568, 853044451, 
-    1172266101, - 589951537, - 1412350631, 651767980, 1373503546, - 925412992, 
-    - 1076862698, 565507253, 1454621731, - 809855591, - 1195530993, 671266974, 
-    1594198024, - 972236366, - 1324619484, 795835527, 1483230225, - 1050600021, 
-    - 1234817731, 1994146192, 31158534, - 1731059524, - 271249366, 1907459465, 
-    112637215, - 1614814043, - 390540237, 2013776290, 251722036, - 1777751922, 
-    - 519137256, 2137656763, 141376813, - 1855689577, - 429695999, 1802195444, 
-    476864866, - 2056965928, - 228458418, 1812370925, 453092731, - 2113342271, 
-    - 183516073, 1706088902, 314042704, - 1950435094, - 54949764, 1658658271, 
-    366619977, - 1932296973, - 69972891, 1303535960, 984961486, - 1547960204, 
-    - 725929758, 1256170817, 1037604311, - 1529756563, - 740887301, 1131014506, 
-    879679996, - 1385723834, - 631195440, 1141124467, 855842277, - 1442165665, 
-    - 586318647, 1342533948, 654459306, - 1106571248, - 921952122, 1466479909, 
-    544179635, - 1184443383, - 832445281, 1591671054, 702138776, - 1328506846, 
-    - 942167884, 1504918807, 783551873, - 1212326853, - 1061524307, - 306674912, 
-    - 1698712650, 62317068, 1957810842, - 355121351, - 1647151185, 81470997, 
-    1943803523, - 480048366, - 1805370492, 225274430, 2053790376, - 468791541, 
-    - 1828061283, 167816743, 2097651377, - 267414716, - 2029476910, 503444072, 
-    1762050814, - 144550051, - 2140837941, 426522225, 1852507879, - 19653770, 
-    - 1982649376, 282753626, 1742555852, - 105259153, - 1900089351, 397917763, 
-    1622183637, - 690576408, - 1580100738, 953729732, 1340076626, - 776247311, 
-    - 1497606297, 1068828381, 1219638859, - 670225446, - 1358292148, 906185462, 
-    1090812512, - 547295293, - 1469587627, 829329135, 1181335161, - 882789492, 
-    - 1134132454, 628085408, 1382605366, - 871598187, - 1156888829, 570562233, 
-    1426400815, - 977650754, - 1296233688, 733239954, 1555261956, - 1026031705, 
-    - 1244606671, 752459403, 1541320221, - 1687895376, - 328994266, 1969922972, 
-    40735498, - 1677130071, - 351390145, 1913087877, 83908371, - 1782625662, 
-    - 491226604, 2075208622, 213261112, - 1831694693, - 438977011, 2094854071, 
-    198958881, - 2032938284, - 237706686, 1759359992, 534414190, - 2118248755, 
-    - 155638181, 1873836001, 414664567, - 2012718362, - 15766928, 1711684554, 
-    285281116, - 1889165569, - 127750551, 1634467795, 376229701, - 1609899400, 
-    - 686959890, 1308918612, 956543938, - 1486412191, - 799009033, 1231636301, 
-    1047427035, - 1362007478, - 640263460, 1088359270, 936918000, - 1447252397, 
-    - 558129467, 1202900863, 817233897, - 1111625188, - 893730166, 1404277552, 
-    615818150, - 1160759803, - 841546093, 1423857449, 601450431, - 1285129682, 
-    - 1000256840, 1567103746, 711928724, - 1274298825, - 1022587231, 1510334235, 
-    755167117]
-
-proc updateCrc32(val: int8, crc: TCrc32): TCrc32 = 
-  result = TCrc32(crc32table[(int(crc) xor (int(val) and 0x000000FF)) and
-      0x000000FF]) xor (crc shr TCrc32(8))
-
-proc updateCrc32(val: char, crc: TCrc32): TCrc32 = 
-  result = updateCrc32(toU8(ord(val)), crc)
-
-proc strCrc32(s: string): TCrc32 = 
-  result = InitCrc32
-  for i in countup(0, len(s) - 1): result = updateCrc32(s[i], result)
-  
-proc `><`*(c: TCrc32, s: string): TCrc32 = 
-  result = c
-  for i in 0..len(s)-1: result = updateCrc32(s[i], result)  
-  
-type 
-  TByteArray = array[0..10000000, int8]
-  PByteArray = ref TByteArray
-
-proc crcFromBuf(buf: pointer, length: int): TCrc32 = 
-  var p = cast[PByteArray](buf)
-  result = InitCrc32
-  for i in countup(0, length - 1): result = updateCrc32(p[i], result)
-  
-proc crcFromFile(filename: string): TCrc32 = 
-  const 
-    bufSize = 8000 # don't use 8K for the memory allocator!
-  var 
-    bin: File
-  result = InitCrc32
-  if not open(bin, filename): 
-    return                    # not equal if file does not exist
-  var buf = alloc(bufSize)
-  var p = cast[PByteArray](buf)
-  while true: 
-    var readBytes = readBuffer(bin, buf, bufSize)
-    for i in countup(0, readBytes - 1): result = updateCrc32(p[i], result)
-    if readBytes != bufSize: break 
-  dealloc(buf)
-  close(bin)
-
-const 
-  base = int32(65521) # largest prime smaller than 65536 
-                      # NMAX = 5552; original code with unsigned 32 bit integer 
-                      # NMAX is the largest n 
-                      # such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 
-  nmax = 3854 # code with signed 32 bit integer 
-              # NMAX is the largest n such that 
-              # 255n(n+1)/2 + (n+1)(BASE-1) <= 2^31-1 
-              # The penalty is the time loss in the extra MOD-calls. 
-
-proc updateAdler32(adler: int32, buf: pointer, length: int): int32 = 
-  var 
-    s1, s2: int32
-    L, k, b: int
-  s1 = adler and int32(0x0000FFFF)
-  s2 = (adler shr int32(16)) and int32(0x0000FFFF)
-  L = length
-  b = 0
-  while (L > 0): 
-    if L < nmax: k = L
-    else: k = nmax
-    dec(L, k)
-    while (k > 0): 
-      s1 = s1 +% int32((cast[cstring](buf))[b])
-      s2 = s2 +% s1
-      inc(b)
-      dec(k)
-    s1 = `%%`(s1, base)
-    s2 = `%%`(s2, base)
-  result = (s2 shl int32(16)) or s1
diff --git a/compiler/docgen.nim b/compiler/docgen.nim
index f8489d825..4b52b1c92 100644
--- a/compiler/docgen.nim
+++ b/compiler/docgen.nim
@@ -18,7 +18,7 @@ import
 
 type
   TSections = array[TSymKind, Rope]
-  TDocumentor = object of rstgen.TRstGenerator
+  TDocumentor = object of rstgen.RstGenerator
     modDesc: Rope           # module description
     id: int                  # for generating IDs
     toc, section: TSections
@@ -29,7 +29,7 @@ type
   PDoc* = ref TDocumentor ## Alias to type less.
 
 proc compilerMsgHandler(filename: string, line, col: int,
-                        msgKind: rst.TMsgKind, arg: string) {.procvar.} =
+                        msgKind: rst.MsgKind, arg: string) {.procvar.} =
   # translate msg kind:
   var k: msgs.TMsgKind
   case msgKind
@@ -53,7 +53,7 @@ proc docgenFindFile(s: string): string {.procvar.} =
 
 proc parseRst(text, filename: string,
               line, column: int, hasToc: var bool,
-              rstOptions: TRstParseOptions): PRstNode =
+              rstOptions: RstParseOptions): PRstNode =
   result = rstParse(text, filename, line, column, hasToc, rstOptions,
                     docgenFindFile, compilerMsgHandler)
 
diff --git a/compiler/extccomp.nim b/compiler/extccomp.nim
index 186a3884d..38427b367 100644
--- a/compiler/extccomp.nim
+++ b/compiler/extccomp.nim
@@ -13,7 +13,8 @@
 # nim files.
 
 import
-  lists, ropes, os, strutils, osproc, platform, condsyms, options, msgs, crc
+  lists, ropes, os, strutils, osproc, platform, condsyms, options, msgs,
+  securehash
 
 type
   TSystemCC* = enum
@@ -572,26 +573,24 @@ proc getCompileCFileCmd*(cfilename: string, isExternal = false): string =
     "nim", quoteShell(getPrefixDir()),
     "lib", quoteShell(libpath)])
 
-proc footprint(filename: string): TCrc32 =
-  # note, '><' further modifies a crc value with a string.
-  result = crcFromFile(filename) ><
-      platform.OS[targetOS].name ><
-      platform.CPU[targetCPU].name ><
-      extccomp.CC[extccomp.cCompiler].name ><
-      getCompileCFileCmd(filename, true)
+proc footprint(filename: string): SecureHash =
+  result = secureHash(
+    $secureHashFile(filename) &
+    platform.OS[targetOS].name &
+    platform.CPU[targetCPU].name &
+    extccomp.CC[extccomp.cCompiler].name &
+    getCompileCFileCmd(filename, true))
 
 proc externalFileChanged(filename: string): bool =
   if gCmd notin {cmdCompileToC, cmdCompileToCpp, cmdCompileToOC, cmdCompileToLLVM}:
     return false
 
   var crcFile = toGeneratedFile(filename.withPackageName, "crc")
-  var currentCrc = int(footprint(filename))
+  var currentCrc = footprint(filename)
   var f: File
   if open(f, crcFile, fmRead):
-    var line = newStringOfCap(40)
-    if not f.readLine(line): line = "0"
+    let oldCrc = parseSecureHash(f.readLine())
     close(f)
-    var oldCrc = parseInt(line)
     result = oldCrc != currentCrc
   else:
     result = true
diff --git a/compiler/forloops.nim b/compiler/forloops.nim
index efe000968..949b7d8c6 100644
--- a/compiler/forloops.nim
+++ b/compiler/forloops.nim
@@ -12,9 +12,9 @@
 import ast, astalgo
 
 const
-  someCmp = {mEqI, mEqI64, mEqF64, mEqEnum, mEqCh, mEqB, mEqRef, mEqProc,
-    mEqUntracedRef, mLeI, mLeI64, mLeF64, mLeU, mLeU64, mLeEnum,
-    mLeCh, mLeB, mLePtr, mLtI, mLtI64, mLtF64, mLtU, mLtU64, mLtEnum, 
+  someCmp = {mEqI, mEqF64, mEqEnum, mEqCh, mEqB, mEqRef, mEqProc,
+    mEqUntracedRef, mLeI, mLeF64, mLeU, mLeU64, mLeEnum,
+    mLeCh, mLeB, mLePtr, mLtI, mLtF64, mLtU, mLtU64, mLtEnum, 
     mLtCh, mLtB, mLtPtr}
 
 proc isCounter(s: PSym): bool {.inline.} =
diff --git a/compiler/guards.nim b/compiler/guards.nim
index df2c1dd75..bc802ae33 100644
--- a/compiler/guards.nim
+++ b/compiler/guards.nim
@@ -13,13 +13,13 @@ import ast, astalgo, msgs, magicsys, nimsets, trees, types, renderer, idents,
   saturate
 
 const
-  someEq = {mEqI, mEqI64, mEqF64, mEqEnum, mEqCh, mEqB, mEqRef, mEqProc,
+  someEq = {mEqI, mEqF64, mEqEnum, mEqCh, mEqB, mEqRef, mEqProc,
     mEqUntracedRef, mEqStr, mEqSet, mEqCString}
 
   # set excluded here as the semantics are vastly different:
-  someLe = {mLeI, mLeI64, mLeF64, mLeU, mLeU64, mLeEnum,
+  someLe = {mLeI, mLeF64, mLeU, mLeU64, mLeEnum,
             mLeCh, mLeB, mLePtr, mLeStr}
-  someLt = {mLtI, mLtI64, mLtF64, mLtU, mLtU64, mLtEnum,
+  someLt = {mLtI, mLtF64, mLtU, mLtU64, mLtEnum,
             mLtCh, mLtB, mLtPtr, mLtStr}
 
   someLen = {mLengthOpenArray, mLengthStr, mLengthArray, mLengthSeq,
@@ -30,11 +30,11 @@ const
   someHigh = {mHigh}
   # we don't list unsigned here because wrap around semantics suck for
   # proving anything:
-  someAdd = {mAddI, mAddI64, mAddF64, mSucc}
-  someSub = {mSubI, mSubI64, mSubF64, mPred}
-  someMul = {mMulI, mMulI64, mMulF64}
-  someDiv = {mDivI, mDivI64, mDivF64}
-  someMod = {mModI, mModI64}
+  someAdd = {mAddI, mAddF64, mSucc}
+  someSub = {mSubI, mSubF64, mPred}
+  someMul = {mMulI, mMulF64}
+  someDiv = {mDivI, mDivF64}
+  someMod = {mModI}
   someMax = {mMaxI, mMaxF64}
   someMin = {mMinI, mMinF64}
 
diff --git a/compiler/idents.nim b/compiler/idents.nim
index 0cca18929..6986800cf 100644
--- a/compiler/idents.nim
+++ b/compiler/idents.nim
@@ -12,7 +12,7 @@
 # id. This module is essential for the compiler's performance.
 
 import 
-  hashes, strutils
+  hashes, strutils, etcpriv
 
 type 
   TIdObj* = object of RootObj
@@ -23,7 +23,7 @@ type
   TIdent*{.acyclic.} = object of TIdObj
     s*: string
     next*: PIdent             # for hash-table chaining
-    h*: THash                 # hash value of s
+    h*: Hash                 # hash value of s
 
 var firstCharIsCS*: bool = true
 var buckets*: array[0..4096 * 2 - 1, PIdent]
@@ -37,6 +37,8 @@ proc cmpIgnoreStyle(a, b: cstring, blen: int): int =
   while j < blen:
     while a[i] == '_': inc(i)
     while b[j] == '_': inc(j)
+    while isMagicIdentSeparatorRune(a, i): inc(i, magicIdentSeparatorRuneByteWidth)
+    while isMagicIdentSeparatorRune(b, j): inc(j, magicIdentSeparatorRuneByteWidth)
     # tolower inlined:
     var aa = a[i]
     var bb = b[j]
@@ -65,7 +67,7 @@ proc cmpExact(a, b: cstring, blen: int): int =
 
 var wordCounter = 1
 
-proc getIdent*(identifier: cstring, length: int, h: THash): PIdent =
+proc getIdent*(identifier: cstring, length: int, h: Hash): PIdent =
   var idx = h and high(buckets)
   result = buckets[idx]
   var last: PIdent = nil
@@ -99,7 +101,7 @@ proc getIdent*(identifier: string): PIdent =
   result = getIdent(cstring(identifier), len(identifier), 
                     hashIgnoreStyle(identifier))
 
-proc getIdent*(identifier: string, h: THash): PIdent = 
+proc getIdent*(identifier: string, h: Hash): PIdent = 
   result = getIdent(cstring(identifier), len(identifier), h)
 
 proc identEq*(id: PIdent, name: string): bool = 
diff --git a/compiler/installer.ini b/compiler/installer.ini
index 821309a34..70df9fd24 100644
--- a/compiler/installer.ini
+++ b/compiler/installer.ini
@@ -99,6 +99,7 @@ Files: "lib/pure/concurrency/*.nim"
 Files: "lib/pure/unidecode/*.nim"
 Files: "lib/pure/concurrency/*.cfg"
 Files: "lib/impure/*.nim"
+Files: "lib/impure/nre/private/*.nim"
 Files: "lib/wrappers/*.nim"
 
 Files: "lib/wrappers/readline/*.nim"
diff --git a/compiler/jsgen.nim b/compiler/jsgen.nim
index 0f6323abc..f6ec256d2 100644
--- a/compiler/jsgen.nim
+++ b/compiler/jsgen.nim
@@ -30,8 +30,8 @@ implements the required case distinction.
 
 
 import
-  ast, astalgo, strutils, hashes, trees, platform, magicsys, extccomp,
-  options, nversion, nimsets, msgs, crc, bitsets, idents, lists, types, os,
+  ast, astalgo, strutils, hashes, trees, platform, magicsys, extccomp, options,
+  nversion, nimsets, msgs, securehash, bitsets, idents, lists, types, os,
   times, ropes, math, passes, ccgutils, wordrecg, renderer, rodread, rodutils,
   intsets, cgmeth, lowerings
 
@@ -258,11 +258,6 @@ const # magic checked op; magic unchecked op; checked op; unchecked op
     ["mulInt", "", "mulInt($1, $2)", "($1 * $2)"], # MulI
     ["divInt", "", "divInt($1, $2)", "Math.floor($1 / $2)"], # DivI
     ["modInt", "", "modInt($1, $2)", "Math.floor($1 % $2)"], # ModI
-    ["addInt64", "", "addInt64($1, $2)", "($1 + $2)"], # AddI64
-    ["subInt64", "", "subInt64($1, $2)", "($1 - $2)"], # SubI64
-    ["mulInt64", "", "mulInt64($1, $2)", "($1 * $2)"], # MulI64
-    ["divInt64", "", "divInt64($1, $2)", "Math.floor($1 / $2)"], # DivI64
-    ["modInt64", "", "modInt64($1, $2)", "Math.floor($1 % $2)"], # ModI64
     ["addInt", "", "addInt($1, $2)", "($1 + $2)"], # Succ
     ["subInt", "", "subInt($1, $2)", "($1 - $2)"], # Pred
     ["", "", "($1 + $2)", "($1 + $2)"], # AddF64
@@ -276,11 +271,6 @@ const # magic checked op; magic unchecked op; checked op; unchecked op
     ["", "", "($1 ^ $2)", "($1 ^ $2)"], # BitxorI
     ["nimMin", "nimMin", "nimMin($1, $2)", "nimMin($1, $2)"], # MinI
     ["nimMax", "nimMax", "nimMax($1, $2)", "nimMax($1, $2)"], # MaxI
-    ["", "", "($1 >>> $2)", "($1 >>> $2)"], # ShrI64
-    ["", "", "($1 << $2)", "($1 << $2)"], # ShlI64
-    ["", "", "($1 & $2)", "($1 & $2)"], # BitandI64
-    ["", "", "($1 | $2)", "($1 | $2)"], # BitorI64
-    ["", "", "($1 ^ $2)", "($1 ^ $2)"], # BitxorI64
     ["nimMin", "nimMin", "nimMin($1, $2)", "nimMin($1, $2)"], # MinF64
     ["nimMax", "nimMax", "nimMax($1, $2)", "nimMax($1, $2)"], # MaxF64
     ["addU", "addU", "addU($1, $2)", "addU($1, $2)"], # addU
@@ -291,9 +281,6 @@ const # magic checked op; magic unchecked op; checked op; unchecked op
     ["", "", "($1 == $2)", "($1 == $2)"], # EqI
     ["", "", "($1 <= $2)", "($1 <= $2)"], # LeI
     ["", "", "($1 < $2)", "($1 < $2)"], # LtI
-    ["", "", "($1 == $2)", "($1 == $2)"], # EqI64
-    ["", "", "($1 <= $2)", "($1 <= $2)"], # LeI64
-    ["", "", "($1 < $2)", "($1 < $2)"], # LtI64
     ["", "", "($1 == $2)", "($1 == $2)"], # EqF64
     ["", "", "($1 <= $2)", "($1 <= $2)"], # LeF64
     ["", "", "($1 < $2)", "($1 < $2)"], # LtF64
@@ -320,11 +307,9 @@ const # magic checked op; magic unchecked op; checked op; unchecked op
     ["negInt", "", "negInt($1)", "-($1)"], # UnaryMinusI
     ["negInt64", "", "negInt64($1)", "-($1)"], # UnaryMinusI64
     ["absInt", "", "absInt($1)", "Math.abs($1)"], # AbsI
-    ["absInt64", "", "absInt64($1)", "Math.abs($1)"], # AbsI64
     ["", "", "!($1)", "!($1)"], # Not
     ["", "", "+($1)", "+($1)"], # UnaryPlusI
     ["", "", "~($1)", "~($1)"], # BitnotI
-    ["", "", "~($1)", "~($1)"], # BitnotI64
     ["", "", "+($1)", "+($1)"], # UnaryPlusF64
     ["", "", "-($1)", "-($1)"], # UnaryMinusF64
     ["", "", "Math.abs($1)", "Math.abs($1)"], # AbsF64
@@ -357,11 +342,6 @@ const # magic checked op; magic unchecked op; checked op; unchecked op
     ["mulInt", "", "mulInt($1, $2)", "($1 * $2)"], # MulI
     ["divInt", "", "divInt($1, $2)", "Math.floor($1 / $2)"], # DivI
     ["modInt", "", "modInt($1, $2)", "Math.floor($1 % $2)"], # ModI
-    ["addInt64", "", "addInt64($1, $2)", "($1 + $2)"], # AddI64
-    ["subInt64", "", "subInt64($1, $2)", "($1 - $2)"], # SubI64
-    ["mulInt64", "", "mulInt64($1, $2)", "($1 * $2)"], # MulI64
-    ["divInt64", "", "divInt64($1, $2)", "Math.floor($1 / $2)"], # DivI64
-    ["modInt64", "", "modInt64($1, $2)", "Math.floor($1 % $2)"], # ModI64
     ["addInt", "", "addInt($1, $2)", "($1 + $2)"], # Succ
     ["subInt", "", "subInt($1, $2)", "($1 - $2)"], # Pred
     ["", "", "($1 + $2)", "($1 + $2)"], # AddF64
@@ -375,11 +355,6 @@ const # magic checked op; magic unchecked op; checked op; unchecked op
     ["", "", "($1 ^ $2)", "($1 ^ $2)"], # BitxorI
     ["nimMin", "nimMin", "nimMin($1, $2)", "nimMin($1, $2)"], # MinI
     ["nimMax", "nimMax", "nimMax($1, $2)", "nimMax($1, $2)"], # MaxI
-    ["", "", "($1 >>> $2)", "($1 >>> $2)"], # ShrI64
-    ["", "", "($1 << $2)", "($1 << $2)"], # ShlI64
-    ["", "", "($1 & $2)", "($1 & $2)"], # BitandI64
-    ["", "", "($1 | $2)", "($1 | $2)"], # BitorI64
-    ["", "", "($1 ^ $2)", "($1 ^ $2)"], # BitxorI64
     ["nimMin", "nimMin", "nimMin($1, $2)", "nimMin($1, $2)"], # MinF64
     ["nimMax", "nimMax", "nimMax($1, $2)", "nimMax($1, $2)"], # MaxF64
     ["addU", "addU", "addU($1, $2)", "addU($1, $2)"], # addU
@@ -390,9 +365,6 @@ const # magic checked op; magic unchecked op; checked op; unchecked op
     ["", "", "($1 == $2)", "($1 == $2)"], # EqI
     ["", "", "($1 <= $2)", "($1 <= $2)"], # LeI
     ["", "", "($1 < $2)", "($1 < $2)"], # LtI
-    ["", "", "($1 == $2)", "($1 == $2)"], # EqI64
-    ["", "", "($1 <= $2)", "($1 <= $2)"], # LeI64
-    ["", "", "($1 < $2)", "($1 < $2)"], # LtI64
     ["", "", "($1 == $2)", "($1 == $2)"], # EqF64
     ["", "", "($1 <= $2)", "($1 <= $2)"], # LeF64
     ["", "", "($1 < $2)", "($1 < $2)"], # LtF64
@@ -419,11 +391,9 @@ const # magic checked op; magic unchecked op; checked op; unchecked op
     ["negInt", "", "negInt($1)", "-($1)"], # UnaryMinusI
     ["negInt64", "", "negInt64($1)", "-($1)"], # UnaryMinusI64
     ["absInt", "", "absInt($1)", "Math.abs($1)"], # AbsI
-    ["absInt64", "", "absInt64($1)", "Math.abs($1)"], # AbsI64
     ["", "", "not ($1)", "not ($1)"], # Not
     ["", "", "+($1)", "+($1)"], # UnaryPlusI
     ["", "", "~($1)", "~($1)"], # BitnotI
-    ["", "", "~($1)", "~($1)"], # BitnotI64
     ["", "", "+($1)", "+($1)"], # UnaryPlusF64
     ["", "", "-($1)", "-($1)"], # UnaryMinusF64
     ["", "", "Math.abs($1)", "Math.abs($1)"], # AbsF64
@@ -817,7 +787,7 @@ proc genAsgnAux(p: PProc, x, y: PNode, noCopyNeeded: bool) =
       addf(p.body, "$1 = $2;$n", [a.rdLoc, b.rdLoc])
     else:
       useMagic(p, "nimCopy")
-      addf(p.body, "$1 = nimCopy($2, $3);$n",
+      addf(p.body, "$1 = nimCopy($1, $2, $3);$n",
            [a.res, b.res, genTypeInfo(p, y.typ)])
   of etyBaseIndex:
     if a.typ != etyBaseIndex or b.typ != etyBaseIndex:
@@ -976,16 +946,28 @@ proc genAddr(p: PProc, n: PNode, r: var TCompRes) =
       genFieldAccess(p, n.sons[0], r)
   of nkBracketExpr:
     var ty = skipTypes(n.sons[0].typ, abstractVarRange)
-    if ty.kind in {tyRef, tyPtr}: ty = skipTypes(ty.lastSon, abstractVarRange)
-    case ty.kind
-    of tyArray, tyArrayConstr, tyOpenArray, tySequence, tyString, tyCString,
-       tyVarargs, tyChar:
-      genArrayAddr(p, n.sons[0], r)
-    of tyTuple:
-      genFieldAddr(p, n.sons[0], r)
-    else: internalError(n.sons[0].info, "expr(nkBracketExpr, " & $ty.kind & ')')
+    if ty.kind in MappedToObject:
+      gen(p, n.sons[0], r)
+    else:
+      let kindOfIndexedExpr = skipTypes(n.sons[0].sons[0].typ, abstractVarRange).kind
+      case kindOfIndexedExpr
+      of tyArray, tyArrayConstr, tyOpenArray, tySequence, tyString, tyCString,
+          tyVarargs:
+        genArrayAddr(p, n.sons[0], r)
+      of tyTuple:
+        genFieldAddr(p, n.sons[0], r)
+      else: internalError(n.sons[0].info, "expr(nkBracketExpr, " & $kindOfIndexedExpr & ')')
   else: internalError(n.sons[0].info, "genAddr")
 
+proc genProcForSymIfNeeded(p: PProc, s: PSym) =
+  if not p.g.generatedSyms.containsOrIncl(s.id):
+    let newp = genProc(p, s)
+    var owner = p
+    while owner != nil and owner.prc != s.owner:
+      owner = owner.up
+    if owner != nil: add(owner.locals, newp)
+    else: add(p.g.code, newp)
+
 proc genSym(p: PProc, n: PNode, r: var TCompRes) =
   var s = n.sym
   case s.kind
@@ -1021,13 +1003,8 @@ proc genSym(p: PProc, n: PNode, r: var TCompRes) =
       discard
     elif sfForward in s.flags:
       p.g.forwarded.add(s)
-    elif not p.g.generatedSyms.containsOrIncl(s.id):
-      let newp = genProc(p, s)
-      var owner = p
-      while owner != nil and owner.prc != s.owner:
-        owner = owner.up
-      if owner != nil: add(owner.locals, newp)
-      else: add(p.g.code, newp)
+    else:
+      genProcForSymIfNeeded(p, s)
   else:
     if s.loc.r == nil:
       internalError(n.info, "symbol has no generated name: " & s.name.s)
@@ -1202,7 +1179,7 @@ proc genVarInit(p: PProc, v: PSym, n: PNode) =
         s = a.res
       else:
         useMagic(p, "nimCopy")
-        s = "nimCopy($1, $2)" % [a.res, genTypeInfo(p, n.typ)]
+        s = "nimCopy(null, $1, $2)" % [a.res, genTypeInfo(p, n.typ)]
     of etyBaseIndex:
       if (a.typ != etyBaseIndex): internalError(n.info, "genVarInit")
       if {sfAddrTaken, sfGlobal} * v.flags != {}:
@@ -1394,6 +1371,9 @@ proc genMagic(p: PProc, n: PNode, r: var TCompRes) =
   of mCopyStrLast: ternaryExpr(p, n, r, "", "($1.slice($2, ($3)+1).concat(0))")
   of mNewString: unaryExpr(p, n, r, "mnewString", "mnewString($1)")
   of mNewStringOfCap: unaryExpr(p, n, r, "mnewString", "mnewString(0)")
+  of mDotDot:
+    genProcForSymIfNeeded(p, n.sons[0].sym)
+    genCall(p, n, r)
   else:
     genCall(p, n, r)
     #else internalError(e.info, 'genMagic: ' + magicToStr[op]);
diff --git a/compiler/lambdalifting.nim b/compiler/lambdalifting.nim
index c68bc352c..69b45c980 100644
--- a/compiler/lambdalifting.nim
+++ b/compiler/lambdalifting.nim
@@ -946,7 +946,11 @@ proc transformOuterProc(o: POuterContext, n: PNode; it: TIter): PNode =
 proc liftLambdas*(fn: PSym, body: PNode): PNode =
   # XXX gCmd == cmdCompileToJS does not suffice! The compiletime stuff needs
   # the transformation even when compiling to JS ...
-  if body.kind == nkEmpty or gCmd == cmdCompileToJS or
+
+  # However we can do lifting for the stuff which is *only* compiletime.
+  let isCompileTime = sfCompileTime in fn.flags or fn.kind == skMacro
+
+  if body.kind == nkEmpty or (gCmd == cmdCompileToJS and not isCompileTime) or
       fn.skipGenericOwner.kind != skModule:
     # ignore forward declaration:
     result = body
diff --git a/compiler/lexer.nim b/compiler/lexer.nim
index 8080e0e8c..cea42ad1e 100644
--- a/compiler/lexer.nim
+++ b/compiler/lexer.nim
@@ -17,7 +17,7 @@
 
 import
   hashes, options, msgs, strutils, platform, idents, nimlexbase, llstream,
-  wordrecg
+  wordrecg, etcpriv
 
 const
   MaxLineLength* = 80         # lines longer than this lead to a warning
@@ -140,10 +140,12 @@ proc isKeyword*(kind: TTokType): bool =
 proc isNimIdentifier*(s: string): bool =
   if s[0] in SymStartChars:
     var i = 1
-    while i < s.len:
+    var sLen = s.len
+    while i < sLen:
       if s[i] == '_':
         inc(i)
-        if s[i] notin SymChars: return
+      elif isMagicIdentSeparatorRune(cstring s, i):
+        inc(i, magicIdentSeparatorRuneByteWidth)
       if s[i] notin SymChars: return
       inc(i)
     result = true
@@ -229,23 +231,6 @@ proc lexMessagePos(L: var TLexer, msg: TMsgKind, pos: int, arg = "") =
   var info = newLineInfo(L.fileIdx, L.lineNumber, pos - L.lineStart)
   L.dispMessage(info, msg, arg)
 
-proc matchUnderscoreChars(L: var TLexer, tok: var TToken, chars: set[char]) =
-  var pos = L.bufpos              # use registers for pos, buf
-  var buf = L.buf
-  while true:
-    if buf[pos] in chars:
-      add(tok.literal, buf[pos])
-      inc(pos)
-    else:
-      break
-    if buf[pos] == '_':
-      if buf[pos+1] notin chars:
-        lexMessage(L, errInvalidToken, "_")
-        break
-      add(tok.literal, '_')
-      inc(pos)
-  L.bufpos = pos
-
 proc matchTwoChars(L: TLexer, first: char, second: set[char]): bool =
   result = (L.buf[L.bufpos] == first) and (L.buf[L.bufpos + 1] in second)
 
@@ -268,136 +253,200 @@ proc unsafeParseUInt(s: string, b: var BiggestInt, start = 0): int =
     result = i - start
 {.pop.} # overflowChecks
 
+
+template eatChar(L: var TLexer, t: var TToken, replacementChar: char) =
+  add(t.literal, replacementChar)
+  inc(L.bufpos)
+
+template eatChar(L: var TLexer, t: var TToken) =
+  add(t.literal, L.buf[L.bufpos])
+  inc(L.bufpos)
+
 proc getNumber(L: var TLexer): TToken =
+  proc matchUnderscoreChars(L: var TLexer, tok: var TToken, chars: set[char]) =
+    var pos = L.bufpos              # use registers for pos, buf
+    var buf = L.buf
+    while true:
+      if buf[pos] in chars:
+        add(tok.literal, buf[pos])
+        inc(pos)
+      else:
+        break
+      if buf[pos] == '_':
+        if buf[pos+1] notin chars:
+          lexMessage(L, errInvalidToken, "_")
+          break
+        add(tok.literal, '_')
+        inc(pos)
+    L.bufpos = pos
+
+  proc matchChars(L: var TLexer, tok: var TToken, chars: set[char]) =
+    var pos = L.bufpos              # use registers for pos, buf
+    var buf = L.buf
+    while buf[pos] in chars:
+      add(tok.literal, buf[pos])
+      inc(pos)
+    L.bufpos = pos
+
+  proc lexMessageLitNum(L: var TLexer, msg: TMsgKind, startpos: int) =
+    # Used to get slightly human friendlier err messages.
+    # Note: the erroneous 'O' char in the character set is intentional
+    const literalishChars = {'A'..'F', 'a'..'f', '0'..'9', 'X', 'x', 'o', 'O',
+      'c', 'C', 'b', 'B', '_', '.', '\'', 'd', 'i', 'u'}
+    var msgPos = L.bufpos
+    var t: TToken
+    t.literal = ""
+    L.bufpos = startpos # Use L.bufpos as pos because of matchChars
+    matchChars(L, t, literalishChars)
+    # We must verify +/- specifically so that we're not past the literal
+    if  L.buf[L.bufpos] in {'+', '-'} and
+        L.buf[L.bufpos - 1] in {'e', 'E'}:
+      add(t.literal, L.buf[L.bufpos])
+      inc(L.bufpos)
+      matchChars(L, t, literalishChars)
+    if L.buf[L.bufpos] in {'\'', 'f', 'F', 'd', 'D', 'i', 'I', 'u', 'U'}:
+      inc(L.bufpos)
+      add(t.literal, L.buf[L.bufpos])
+      matchChars(L, t, {'0'..'9'})
+    L.bufpos = msgPos
+    lexMessage(L, msg, t.literal)
+
   var
-    pos, endpos: int
+    startpos, endpos: int
     xi: BiggestInt
-  # get the base:
+    isBase10 = true
+  const
+    baseCodeChars = {'X', 'x', 'o', 'c', 'C', 'b', 'B'}
+    literalishChars = baseCodeChars + {'A'..'F', 'a'..'f', '0'..'9', '_', '\''}
+    floatTypes = {tkFloatLit, tkFloat32Lit, tkFloat64Lit, tkFloat128Lit}
   result.tokType = tkIntLit   # int literal until we know better
   result.literal = ""
-  result.base = base10        # BUGFIX
-  pos = L.bufpos     # make sure the literal is correct for error messages:
-  var eallowed = false
-  if L.buf[pos] == '0' and L.buf[pos+1] in {'X', 'x'}:
-    matchUnderscoreChars(L, result, {'A'..'F', 'a'..'f', '0'..'9', 'X', 'x'})
+  result.base = base10
+  startpos = L.bufpos
+
+  # First stage: find out base, make verifications, build token literal string
+  if L.buf[L.bufpos] == '0' and L.buf[L.bufpos + 1] in baseCodeChars + {'O'}:
+    isBase10 = false
+    eatChar(L, result, '0')
+    case L.buf[L.bufpos]
+    of 'O':
+      lexMessageLitNum(L, errInvalidNumberOctalCode, startpos)
+    of 'x', 'X':
+      eatChar(L, result, 'x')
+      matchUnderscoreChars(L, result, {'0'..'9', 'a'..'f', 'A'..'F'})
+    of 'o', 'c', 'C':
+      eatChar(L, result, 'c')
+      matchUnderscoreChars(L, result, {'0'..'7'})
+    of 'b', 'B':
+      eatChar(L, result, 'b')
+      matchUnderscoreChars(L, result, {'0'..'1'})
+    else:
+      internalError(getLineInfo(L), "getNumber")
   else:
-    matchUnderscoreChars(L, result, {'0'..'9', 'b', 'B', 'o', 'c', 'C'})
-    eallowed = true
-  if (L.buf[L.bufpos] == '.') and (L.buf[L.bufpos + 1] in {'0'..'9'}):
-    add(result.literal, '.')
-    inc(L.bufpos)
-    matchUnderscoreChars(L, result, {'0'..'9'})
-    eallowed = true
-  if eallowed and L.buf[L.bufpos] in {'e', 'E'}:
-    add(result.literal, 'e')
-    inc(L.bufpos)
-    if L.buf[L.bufpos] in {'+', '-'}:
-      add(result.literal, L.buf[L.bufpos])
-      inc(L.bufpos)
     matchUnderscoreChars(L, result, {'0'..'9'})
+    if (L.buf[L.bufpos] == '.') and (L.buf[L.bufpos + 1] in {'0'..'9'}):
+      result.tokType = tkFloat64Lit
+      eatChar(L, result, '.')
+      matchUnderscoreChars(L, result, {'0'..'9'})
+    if L.buf[L.bufpos] in {'e', 'E'}:
+      result.tokType = tkFloat64Lit
+      eatChar(L, result, 'e')
+      if L.buf[L.bufpos] in {'+', '-'}:
+        eatChar(L, result)
+      matchUnderscoreChars(L, result, {'0'..'9'})
   endpos = L.bufpos
-  if L.buf[endpos] in {'\'', 'f', 'F', 'i', 'I', 'u', 'U'}:
-    if L.buf[endpos] == '\'': inc(endpos)
-    L.bufpos = pos            # restore position
-    case L.buf[endpos]
+
+  # Second stage, find out if there's a datatype suffix and handle it
+  var postPos = endpos
+  if L.buf[postPos] in {'\'', 'f', 'F', 'd', 'D', 'i', 'I', 'u', 'U'}:
+    if L.buf[postPos] == '\'':
+      inc(postPos)
+
+    case L.buf[postPos]
     of 'f', 'F':
-      inc(endpos)
-      if (L.buf[endpos] == '3') and (L.buf[endpos + 1] == '2'):
+      inc(postPos)
+      if (L.buf[postPos] == '3') and (L.buf[postPos + 1] == '2'):
         result.tokType = tkFloat32Lit
-        inc(endpos, 2)
-      elif (L.buf[endpos] == '6') and (L.buf[endpos + 1] == '4'):
+        inc(postPos, 2)
+      elif (L.buf[postPos] == '6') and (L.buf[postPos + 1] == '4'):
         result.tokType = tkFloat64Lit
-        inc(endpos, 2)
-      elif (L.buf[endpos] == '1') and
-           (L.buf[endpos + 1] == '2') and
-           (L.buf[endpos + 2] == '8'):
+        inc(postPos, 2)
+      elif (L.buf[postPos] == '1') and
+           (L.buf[postPos + 1] == '2') and
+           (L.buf[postPos + 2] == '8'):
         result.tokType = tkFloat128Lit
-        inc(endpos, 3)
-      else:
-        lexMessage(L, errInvalidNumber, result.literal & "'f" & L.buf[endpos])
+        inc(postPos, 3)
+      else:   # "f" alone defaults to float32
+        result.tokType = tkFloat32Lit
+    of 'd', 'D':  # ad hoc convenience shortcut for f64
+      inc(postPos)
+      result.tokType = tkFloat64Lit
     of 'i', 'I':
-      inc(endpos)
-      if (L.buf[endpos] == '6') and (L.buf[endpos + 1] == '4'):
+      inc(postPos)
+      if (L.buf[postPos] == '6') and (L.buf[postPos + 1] == '4'):
         result.tokType = tkInt64Lit
-        inc(endpos, 2)
-      elif (L.buf[endpos] == '3') and (L.buf[endpos + 1] == '2'):
+        inc(postPos, 2)
+      elif (L.buf[postPos] == '3') and (L.buf[postPos + 1] == '2'):
         result.tokType = tkInt32Lit
-        inc(endpos, 2)
-      elif (L.buf[endpos] == '1') and (L.buf[endpos + 1] == '6'):
+        inc(postPos, 2)
+      elif (L.buf[postPos] == '1') and (L.buf[postPos + 1] == '6'):
         result.tokType = tkInt16Lit
-        inc(endpos, 2)
-      elif (L.buf[endpos] == '8'):
+        inc(postPos, 2)
+      elif (L.buf[postPos] == '8'):
         result.tokType = tkInt8Lit
-        inc(endpos)
+        inc(postPos)
       else:
-        lexMessage(L, errInvalidNumber, result.literal & "'i" & L.buf[endpos])
+        lexMessageLitNum(L, errInvalidNumber, startpos)
     of 'u', 'U':
-      inc(endpos)
-      if (L.buf[endpos] == '6') and (L.buf[endpos + 1] == '4'):
+      inc(postPos)
+      if (L.buf[postPos] == '6') and (L.buf[postPos + 1] == '4'):
         result.tokType = tkUInt64Lit
-        inc(endpos, 2)
-      elif (L.buf[endpos] == '3') and (L.buf[endpos + 1] == '2'):
+        inc(postPos, 2)
+      elif (L.buf[postPos] == '3') and (L.buf[postPos + 1] == '2'):
         result.tokType = tkUInt32Lit
-        inc(endpos, 2)
-      elif (L.buf[endpos] == '1') and (L.buf[endpos + 1] == '6'):
+        inc(postPos, 2)
+      elif (L.buf[postPos] == '1') and (L.buf[postPos + 1] == '6'):
         result.tokType = tkUInt16Lit
-        inc(endpos, 2)
-      elif (L.buf[endpos] == '8'):
+        inc(postPos, 2)
+      elif (L.buf[postPos] == '8'):
         result.tokType = tkUInt8Lit
-        inc(endpos)
+        inc(postPos)
       else:
         result.tokType = tkUIntLit
-    else: lexMessage(L, errInvalidNumber, result.literal & "'" & L.buf[endpos])
-  else:
-    L.bufpos = pos            # restore position
+    else:
+      lexMessageLitNum(L, errInvalidNumber, startpos)
+
+  # Is there still a literalish char awaiting? Then it's an error!
+  if  L.buf[postPos] in literalishChars or
+     (L.buf[postPos] == '.' and L.buf[postPos + 1] in {'0'..'9'}):
+    lexMessageLitNum(L, errInvalidNumber, startpos)
+
+  # Third stage, extract actual number
+  L.bufpos = startpos            # restore position
+  var pos: int = startpos
   try:
-    if (L.buf[pos] == '0') and
-        (L.buf[pos + 1] in {'x', 'X', 'b', 'B', 'o', 'O', 'c', 'C'}):
+    if (L.buf[pos] == '0') and (L.buf[pos + 1] in baseCodeChars):
       inc(pos, 2)
-      xi = 0                  # it may be a base prefix
-      case L.buf[pos - 1]     # now look at the optional type suffix:
+      xi = 0                  # it is a base prefix
+
+      case L.buf[pos - 1]
       of 'b', 'B':
         result.base = base2
-        while true:
-          case L.buf[pos]
-          of '2'..'9', '.':
-            lexMessage(L, errInvalidNumber, result.literal)
-            inc(pos)
-          of '_':
-            if L.buf[pos+1] notin {'0'..'1'}:
-              lexMessage(L, errInvalidToken, "_")
-              break
-            inc(pos)
-          of '0', '1':
+        while pos < endpos:
+          if L.buf[pos] != '_':
             xi = `shl`(xi, 1) or (ord(L.buf[pos]) - ord('0'))
-            inc(pos)
-          else: break
+          inc(pos)
       of 'o', 'c', 'C':
         result.base = base8
-        while true:
-          case L.buf[pos]
-          of '8'..'9', '.':
-            lexMessage(L, errInvalidNumber, result.literal)
-            inc(pos)
-          of '_':
-            if L.buf[pos+1] notin {'0'..'7'}:
-              lexMessage(L, errInvalidToken, "_")
-              break
-            inc(pos)
-          of '0'..'7':
+        while pos < endpos:
+          if L.buf[pos] != '_':
             xi = `shl`(xi, 3) or (ord(L.buf[pos]) - ord('0'))
-            inc(pos)
-          else: break
-      of 'O':
-        lexMessage(L, errInvalidNumber, result.literal)
+          inc(pos)
       of 'x', 'X':
         result.base = base16
-        while true:
+        while pos < endpos:
           case L.buf[pos]
           of '_':
-            if L.buf[pos+1] notin {'0'..'9', 'a'..'f', 'A'..'F'}:
-              lexMessage(L, errInvalidToken, "_")
-              break
             inc(pos)
           of '0'..'9':
             xi = `shl`(xi, 4) or (ord(L.buf[pos]) - ord('0'))
@@ -408,51 +457,81 @@ proc getNumber(L: var TLexer): TToken =
           of 'A'..'F':
             xi = `shl`(xi, 4) or (ord(L.buf[pos]) - ord('A') + 10)
             inc(pos)
-          else: break
-      else: internalError(getLineInfo(L), "getNumber")
+          else:
+            break
+      else:
+        internalError(getLineInfo(L), "getNumber")
+
       case result.tokType
       of tkIntLit, tkInt64Lit: result.iNumber = xi
       of tkInt8Lit: result.iNumber = BiggestInt(int8(toU8(int(xi))))
-      of tkInt16Lit: result.iNumber = BiggestInt(toU16(int(xi)))
-      of tkInt32Lit: result.iNumber = BiggestInt(toU32(xi))
+      of tkInt16Lit: result.iNumber = BiggestInt(int16(toU16(int(xi))))
+      of tkInt32Lit: result.iNumber = BiggestInt(int32(toU32(int64(xi))))
       of tkUIntLit, tkUInt64Lit: result.iNumber = xi
-      of tkUInt8Lit: result.iNumber = BiggestInt(int8(toU8(int(xi))))
-      of tkUInt16Lit: result.iNumber = BiggestInt(toU16(int(xi)))
-      of tkUInt32Lit: result.iNumber = BiggestInt(toU32(xi))
+      of tkUInt8Lit: result.iNumber = BiggestInt(uint8(toU8(int(xi))))
+      of tkUInt16Lit: result.iNumber = BiggestInt(uint16(toU16(int(xi))))
+      of tkUInt32Lit: result.iNumber = BiggestInt(uint32(toU32(int64(xi))))
       of tkFloat32Lit:
         result.fNumber = (cast[PFloat32](addr(xi)))[]
         # note: this code is endian neutral!
         # XXX: Test this on big endian machine!
       of tkFloat64Lit: result.fNumber = (cast[PFloat64](addr(xi)))[]
       else: internalError(getLineInfo(L), "getNumber")
-    elif isFloatLiteral(result.literal) or (result.tokType == tkFloat32Lit) or
-        (result.tokType == tkFloat64Lit):
-      result.fNumber = parseFloat(result.literal)
-      if result.tokType == tkIntLit: result.tokType = tkFloatLit
-    elif result.tokType == tkUint64Lit:
-      xi = 0
-      let len = unsafeParseUInt(result.literal, xi)
-      if len != result.literal.len or len == 0:
-        raise newException(ValueError, "invalid integer: " & $xi)
-      result.iNumber = xi
+
+      # Bounds checks. Non decimal literals are allowed to overflow the range of
+      # the datatype as long as their pattern don't overflow _bitwise_, hence
+      # below checks of signed sizes against uint*.high is deliberate:
+      # (0x80'u8 = 128, 0x80'i8 = -128, etc == OK)
+      if result.tokType notin floatTypes:
+        let outOfRange = case result.tokType:
+        of tkUInt8Lit, tkUInt16Lit, tkUInt32Lit: result.iNumber != xi
+        of tkInt8Lit: (xi > BiggestInt(uint8.high))
+        of tkInt16Lit: (xi > BiggestInt(uint16.high))
+        of tkInt32Lit: (xi > BiggestInt(uint32.high))
+        else: false
+
+        if outOfRange:
+          #echo "out of range num: ", result.iNumber, " vs ", xi
+          lexMessageLitNum(L, errNumberOutOfRange, startpos)
+
     else:
-      result.iNumber = parseBiggestInt(result.literal)
+      case result.tokType
+      of floatTypes:
+        result.fNumber = parseFloat(result.literal)
+      of tkUint64Lit:
+        xi = 0
+        let len = unsafeParseUInt(result.literal, xi)
+        if len != result.literal.len or len == 0:
+          raise newException(ValueError, "invalid integer: " & $xi)
+        result.iNumber = xi
+      else:
+        result.iNumber = parseBiggestInt(result.literal)
+
+      # Explicit bounds checks
+      let outOfRange = case result.tokType:
+      of tkInt8Lit: (result.iNumber < int8.low or result.iNumber > int8.high)
+      of tkUInt8Lit: (result.iNumber < BiggestInt(uint8.low) or
+                      result.iNumber > BiggestInt(uint8.high))
+      of tkInt16Lit: (result.iNumber < int16.low or result.iNumber > int16.high)
+      of tkUInt16Lit: (result.iNumber < BiggestInt(uint16.low) or
+                      result.iNumber > BiggestInt(uint16.high))
+      of tkInt32Lit: (result.iNumber < int32.low or result.iNumber > int32.high)
+      of tkUInt32Lit: (result.iNumber < BiggestInt(uint32.low) or
+                      result.iNumber > BiggestInt(uint32.high))
+      else: false
+
+      if outOfRange: lexMessageLitNum(L, errNumberOutOfRange, startpos)
+
+    # Promote int literal to int64? Not always necessary, but more consistent
+    if result.tokType == tkIntLit:
       if (result.iNumber < low(int32)) or (result.iNumber > high(int32)):
-        if result.tokType == tkIntLit:
-          result.tokType = tkInt64Lit
-        elif result.tokType in {tkInt8Lit, tkInt16Lit, tkInt32Lit}:
-          lexMessage(L, errNumberOutOfRange, result.literal)
-      elif result.tokType == tkInt8Lit and
-          (result.iNumber < int8.low or result.iNumber > int8.high):
-        lexMessage(L, errNumberOutOfRange, result.literal)
-      elif result.tokType == tkInt16Lit and
-          (result.iNumber < int16.low or result.iNumber > int16.high):
-        lexMessage(L, errNumberOutOfRange, result.literal)
+        result.tokType = tkInt64Lit
+
   except ValueError:
-    lexMessage(L, errInvalidNumber, result.literal)
+    lexMessageLitNum(L, errInvalidNumber, startpos)
   except OverflowError, RangeError:
-    lexMessage(L, errNumberOutOfRange, result.literal)
-  L.bufpos = endpos
+    lexMessageLitNum(L, errNumberOutOfRange, startpos)
+  L.bufpos = postPos
 
 proc handleHexChar(L: var TLexer, xi: var int) =
   case L.buf[L.bufpos]
@@ -625,23 +704,34 @@ proc getCharacter(L: var TLexer, tok: var TToken) =
   inc(L.bufpos)               # skip '
 
 proc getSymbol(L: var TLexer, tok: var TToken) =
-  var h: THash = 0
+  var h: Hash = 0
   var pos = L.bufpos
   var buf = L.buf
   while true:
     var c = buf[pos]
     case c
     of 'a'..'z', '0'..'9', '\x80'..'\xFF':
-      h = h !& ord(c)
+      if  c == '\226' and
+          buf[pos+1] == '\128' and
+          buf[pos+2] == '\147':  # It's a 'magic separator' en-dash Unicode
+        if buf[pos + magicIdentSeparatorRuneByteWidth] notin SymChars:
+          lexMessage(L, errInvalidToken, "–")
+          break
+        inc(pos, magicIdentSeparatorRuneByteWidth)
+      else:
+        h = h !& ord(c)
+        inc(pos)
     of 'A'..'Z':
       c = chr(ord(c) + (ord('a') - ord('A'))) # toLower()
       h = h !& ord(c)
+      inc(pos)
     of '_':
       if buf[pos+1] notin SymChars:
         lexMessage(L, errInvalidToken, "_")
         break
+      inc(pos)
+
     else: break
-    inc(pos)
   h = !$h
   tok.ident = getIdent(addr(L.buf[L.bufpos]), pos - L.bufpos, h)
   L.bufpos = pos
@@ -652,7 +742,7 @@ proc getSymbol(L: var TLexer, tok: var TToken) =
     tok.tokType = TTokType(tok.ident.id + ord(tkSymbol))
 
 proc endOperator(L: var TLexer, tok: var TToken, pos: int,
-                 hash: THash) {.inline.} =
+                 hash: Hash) {.inline.} =
   var h = !$hash
   tok.ident = getIdent(addr(L.buf[L.bufpos]), pos - L.bufpos, h)
   if (tok.ident.id < oprLow) or (tok.ident.id > oprHigh): tok.tokType = tkOpr
@@ -662,7 +752,7 @@ proc endOperator(L: var TLexer, tok: var TToken, pos: int,
 proc getOperator(L: var TLexer, tok: var TToken) =
   var pos = L.bufpos
   var buf = L.buf
-  var h: THash = 0
+  var h: Hash = 0
   while true:
     var c = buf[pos]
     if c notin OpChars: break
diff --git a/compiler/modules.nim b/compiler/modules.nim
index 2fa46f356..dcba5cf3d 100644
--- a/compiler/modules.nim
+++ b/compiler/modules.nim
@@ -10,7 +10,7 @@
 ## implements the module handling
 
 import
-  ast, astalgo, magicsys, crc, rodread, msgs, cgendata, sigmatch, options,
+  ast, astalgo, magicsys, securehash, rodread, msgs, cgendata, sigmatch, options,
   idents, os, lexer, idgen, passes, syntaxes, llstream
 
 type
@@ -19,7 +19,7 @@ type
 
   TModuleInMemory* = object
     compiledAt*: float
-    crc*: TCrc32
+    crc*: SecureHash
     deps*: seq[int32] ## XXX: slurped files are currently not tracked
     needsRecompile*: TNeedRecompile
     crcStatus*: TCrcStatus
@@ -51,19 +51,19 @@ proc crcChanged(fileIdx: int32): bool =
   of crcNotChanged:
     result = false
   of crcCached:
-    let newCrc = crcFromFile(fileIdx.toFilename)
+    let newCrc = secureHashFile(fileIdx.toFullPath)
     result = newCrc != gMemCacheData[fileIdx].crc
     gMemCacheData[fileIdx].crc = newCrc
     updateStatus()
   of crcNotTaken:
-    gMemCacheData[fileIdx].crc = crcFromFile(fileIdx.toFilename)
+    gMemCacheData[fileIdx].crc = secureHashFile(fileIdx.toFullPath)
     result = true
     updateStatus()
 
 proc doCRC(fileIdx: int32) =
   if gMemCacheData[fileIdx].crcStatus == crcNotTaken:
     # echo "FIRST CRC: ", fileIdx.ToFilename
-    gMemCacheData[fileIdx].crc = crcFromFile(fileIdx.toFilename)
+    gMemCacheData[fileIdx].crc = secureHashFile(fileIdx.toFullPath)
 
 proc addDep(x: PSym, dep: int32) =
   growCache gMemCacheData, dep
diff --git a/compiler/msgs.nim b/compiler/msgs.nim
index 041a181be..4df4430d7 100644
--- a/compiler/msgs.nim
+++ b/compiler/msgs.nim
@@ -8,7 +8,7 @@
 #
 
 import
-  options, strutils, os, tables, ropes, platform
+  options, strutils, os, tables, ropes, platform, terminal
 
 type
   TMsgKind* = enum
@@ -17,10 +17,9 @@ type
     errIntLiteralExpected, errInvalidCharacterConstant,
     errClosingTripleQuoteExpected, errClosingQuoteExpected,
     errTabulatorsAreNotAllowed, errInvalidToken, errLineTooLong,
-    errInvalidNumber, errNumberOutOfRange, errNnotAllowedInCharacter,
-    errClosingBracketExpected, errMissingFinalQuote, errIdentifierExpected,
-    errNewlineExpected,
-    errInvalidModuleName,
+    errInvalidNumber, errInvalidNumberOctalCode, errNumberOutOfRange,
+    errNnotAllowedInCharacter, errClosingBracketExpected, errMissingFinalQuote,
+    errIdentifierExpected, errNewlineExpected, errInvalidModuleName,
     errOperatorExpected, errTokenExpected, errStringAfterIncludeExpected,
     errRecursiveDependencyX, errOnOrOffExpected, errNoneSpeedOrSizeExpected,
     errInvalidPragma, errUnknownPragma, errInvalidDirectiveX,
@@ -35,7 +34,9 @@ type
     errNoneSpeedOrSizeExpectedButXFound, errGuiConsoleOrLibExpectedButXFound,
     errUnknownOS, errUnknownCPU, errGenOutExpectedButXFound,
     errArgsNeedRunOption, errInvalidMultipleAsgn, errColonOrEqualsExpected,
-    errExprExpected, errUndeclaredIdentifier, errUseQualifier, errTypeExpected,
+    errExprExpected, errUndeclaredIdentifier, errUndeclaredField,
+    errUndeclaredRoutine, errUseQualifier,
+    errTypeExpected,
     errSystemNeeds, errExecutionOfProgramFailed, errNotOverloadable,
     errInvalidArgForX, errStmtHasNoEffect, errXExpectsTypeOrValue,
     errXExpectsArrayType, errIteratorCannotBeInstantiated, errExprXAmbiguous,
@@ -143,6 +144,7 @@ const
     errInvalidToken: "invalid token: $1",
     errLineTooLong: "line too long",
     errInvalidNumber: "$1 is not a valid number",
+    errInvalidNumberOctalCode: "$1 is not a valid number; did you mean octal? Then use one of '0o', '0c' or '0C'.",
     errNumberOutOfRange: "number $1 out of valid range",
     errNnotAllowedInCharacter: "\\n not allowed in character literal",
     errClosingBracketExpected: "closing ']' expected, but end of file reached",
@@ -190,6 +192,8 @@ const
     errColonOrEqualsExpected: "\':\' or \'=\' expected, but found \'$1\'",
     errExprExpected: "expression expected, but found \'$1\'",
     errUndeclaredIdentifier: "undeclared identifier: \'$1\'",
+    errUndeclaredField: "undeclared field: \'$1\'",
+    errUndeclaredRoutine: "attempting to call undeclared routine: \'$1\'",
     errUseQualifier: "ambiguous identifier: \'$1\' -- use a qualifier",
     errTypeExpected: "type expected",
     errSystemNeeds: "system module needs \'$1\'",
@@ -601,13 +605,13 @@ proc suggestQuit*() =
 # this format is understood by many text editors: it is the same that
 # Borland and Freepascal use
 const
-  PosErrorFormat* = "$1($2, $3) Error: $4"
-  PosWarningFormat* = "$1($2, $3) Warning: $4"
-  PosHintFormat* = "$1($2, $3) Hint: $4"
-  PosContextFormat = "$1($2, $3) Info: $4"
-  RawErrorFormat* = "Error: $1"
-  RawWarningFormat* = "Warning: $1"
-  RawHintFormat* = "Hint: $1"
+  PosErrorFormat* = "$1($2, $3) Error: "
+  PosWarningFormat* = "$1($2, $3) Warning: "
+  PosHintFormat* = "$1($2, $3) Hint: "
+  PosContextFormat = "$1($2, $3) Info: "
+  RawError* = "Error: "
+  RawWarning* = "Warning: "
+  RawHint* = "Hint: "
 
 proc getInfoContextLen*(): int = return msgContext.len
 proc setInfoContextLen*(L: int) = setLen(msgContext, L)
@@ -682,17 +686,27 @@ proc outWriteln*(s: string) =
   ## Writes to stdout. Always.
   if eStdOut in errorOutputs: writeln(stdout, s)
 
-proc msgWriteln*(s: string) =
-  ## Writes to stdout. If --stdout option is given, writes to stderr instead.
+proc msgWriteln*(s: string, color: ForegroundColor = fgWhite, coloredText: string = "") =
+  ## Writes to stdout. If --stderr option is given, writes to stderr instead.
 
   #if gCmd == cmdIdeTools and optCDebug notin gGlobalOptions: return
 
+  var hasColor = optUseColors in gGlobalOptions
   if not isNil(writelnHook):
-    writelnHook(s)
-  elif optStdout in gGlobalOptions:
-    if eStdErr in errorOutputs: writeln(stderr, s)
+    writelnHook(coloredText & s)
   else:
-    if eStdOut in errorOutputs: writeln(stdout, s)
+    if optStdout in gGlobalOptions:
+      if eStdErr in errorOutputs:
+        if hasColor: setForegroundColor(color)
+        write(stderr, coloredText)
+        if hasColor: resetAttributes()
+        writeln(stderr, s)
+    else:
+      if eStdOut in errorOutputs:
+        if hasColor: setForegroundColor(color)
+        write(stdout, coloredText)
+        if hasColor: resetAttributes()
+        writeln(stdout, s)
 
 proc coordToStr(coord: int): string =
   if coord == -1: result = "???"
@@ -714,7 +728,7 @@ proc handleError(msg: TMsgKind, eh: TErrorHandling, s: string) =
       if stackTraceAvailable() and isNil(writelnHook):
         writeStackTrace()
       else:
-        msgWriteln("No stack traceback available\nTo create a stacktrace, rerun compilation with ./koch temp " & options.command & " <file>")
+        msgWriteln("", fgRed, "No stack traceback available\nTo create a stacktrace, rerun compilation with ./koch temp " & options.command & " <file>")
     quit 1
 
   if msg >= fatalMin and msg <= fatalMax:
@@ -737,34 +751,39 @@ proc writeContext(lastinfo: TLineInfo) =
   for i in countup(0, len(msgContext) - 1):
     if msgContext[i] != lastinfo and msgContext[i] != info:
       msgWriteln(PosContextFormat % [toMsgFilename(msgContext[i]),
-                                     coordToStr(msgContext[i].line),
-                                     coordToStr(msgContext[i].col+1),
-                                     getMessageStr(errInstantiationFrom, "")])
+                                   coordToStr(msgContext[i].line),
+                                   coordToStr(msgContext[i].col+1),
+                                   getMessageStr(errInstantiationFrom, "")])
     info = msgContext[i]
 
 proc ignoreMsgBecauseOfIdeTools(msg: TMsgKind): bool =
   msg >= errGenerated and gCmd == cmdIdeTools and optIdeDebug notin gGlobalOptions
 
 proc rawMessage*(msg: TMsgKind, args: openArray[string]) =
-  var frmt: string
+  var
+    frmt: string
+    color: ForegroundColor
   case msg
   of errMin..errMax:
     writeContext(unknownLineInfo())
-    frmt = RawErrorFormat
+    frmt = RawError
+    color = fgRed
   of warnMin..warnMax:
     if optWarns notin gOptions: return
     if msg notin gNotes: return
     writeContext(unknownLineInfo())
-    frmt = RawWarningFormat
+    frmt = RawWarning
     inc(gWarnCounter)
+    color = fgYellow
   of hintMin..hintMax:
     if optHints notin gOptions: return
     if msg notin gNotes: return
-    frmt = RawHintFormat
+    frmt = RawHint
     inc(gHintCounter)
-  let s = `%`(frmt, `%`(msgKindToString(msg), args))
+    color = fgGreen
+  let s = `%`(msgKindToString(msg), args)
   if not ignoreMsgBecauseOfIdeTools(msg):
-    msgWriteln(s)
+    msgWriteln(s, color, frmt)
   handleError(msg, doAbort, s)
 
 proc rawMessage*(msg: TMsgKind, arg: string) =
@@ -785,8 +804,10 @@ proc formatMsg*(info: TLineInfo, msg: TMsgKind, arg: string): string =
 
 proc liMessage(info: TLineInfo, msg: TMsgKind, arg: string,
                eh: TErrorHandling) =
-  var frmt: string
-  var ignoreMsg = false
+  var
+    frmt: string
+    ignoreMsg = false
+    color: ForegroundColor
   case msg
   of errMin..errMax:
     writeContext(info)
@@ -795,22 +816,26 @@ proc liMessage(info: TLineInfo, msg: TMsgKind, arg: string,
     # in the same file and line are produced:
     #ignoreMsg = lastError == info and eh != doAbort
     lastError = info
+    color = fgRed
   of warnMin..warnMax:
     ignoreMsg = optWarns notin gOptions or msg notin gNotes
     if not ignoreMsg: writeContext(info)
     frmt = PosWarningFormat
     inc(gWarnCounter)
+    color = fgYellow
   of hintMin..hintMax:
     ignoreMsg = optHints notin gOptions or msg notin gNotes
     frmt = PosHintFormat
     inc(gHintCounter)
+    color = fgGreen
   # NOTE: currently line info line numbers start with 1,
   # but column numbers start with 0, however most editors expect
   # first column to be 1, so we need to +1 here
-  let s = frmt % [toMsgFilename(info), coordToStr(info.line),
-                  coordToStr(info.col+1), getMessageStr(msg, arg)]
+  let x = frmt % [toMsgFilename(info), coordToStr(info.line),
+                  coordToStr(info.col+1)]
+  let s = getMessageStr(msg, arg)
   if not ignoreMsg and not ignoreMsgBecauseOfIdeTools(msg):
-    msgWriteln(s)
+    msgWriteln(s, color, x)
     if optPrintSurroundingSrc and msg in errMin..errMax:
       info.writeSurroundingSrc
   handleError(msg, eh, s)
diff --git a/compiler/nimfix/nimfix.nim b/compiler/nimfix/nimfix.nim
index 8caa23ee3..3641aec36 100644
--- a/compiler/nimfix/nimfix.nim
+++ b/compiler/nimfix/nimfix.nim
@@ -10,8 +10,10 @@
 ## Nimfix is a tool that helps to convert old-style Nimrod code to Nim code.
 
 import strutils, os, parseopt
-import options, commands, modules, sem, passes, passaux, pretty, msgs, nimconf,
-  extccomp, condsyms, lists
+import compiler/options, compiler/commands, compiler/modules, compiler/sem,
+  compiler/passes, compiler/passaux, compiler/nimfix/pretty,
+  compiler/msgs, compiler/nimconf,
+  compiler/extccomp, compiler/condsyms, compiler/lists
 
 const Usage = """
 Nimfix - Tool to patch Nim code
@@ -24,7 +26,7 @@ Options:
   --wholeProject                   overwrite every processed file.
   --checkExtern:on|off             style check also extern names
   --styleCheck:on|off|auto         performs style checking for identifiers
-                                   and suggests an alternative spelling; 
+                                   and suggests an alternative spelling;
                                    'auto' corrects the spelling.
   --bestEffort                     try to fix the code even when there
                                    are errors.
@@ -48,11 +50,11 @@ proc processCmdLine*(pass: TCmdLinePass, cmd: string) =
   var p = parseopt.initOptParser(cmd)
   var argsCount = 0
   gOnlyMainfile = true
-  while true: 
+  while true:
     parseopt.next(p)
     case p.kind
-    of cmdEnd: break 
-    of cmdLongoption, cmdShortOption: 
+    of cmdEnd: break
+    of cmdLongoption, cmdShortOption:
       case p.key.normalize
       of "overwritefiles":
         case p.val.normalize
diff --git a/compiler/nimfix/pretty.nim b/compiler/nimfix/pretty.nim
index d2d5b5e83..1123afb9e 100644
--- a/compiler/nimfix/pretty.nim
+++ b/compiler/nimfix/pretty.nim
@@ -10,9 +10,11 @@
 ## This module implements the code "prettifier". This is part of the toolchain
 ## to convert Nim code into a consistent style.
 
-import 
-  strutils, os, options, ast, astalgo, msgs, ropes, idents,
-  intsets, strtabs, semdata, prettybase
+import
+  strutils, os, intsets, strtabs
+
+import compiler/options, compiler/ast, compiler/astalgo, compiler/msgs,
+  compiler/semdata, compiler/nimfix/prettybase, compiler/ropes, compiler/idents
 
 type
   StyleCheck* {.pure.} = enum None, Warn, Auto
@@ -92,7 +94,7 @@ proc beautifyName(s: string, k: TSymKind): string =
 
 proc replaceInFile(info: TLineInfo; newName: string) =
   loadFile(info)
-  
+
   let line = gSourceFiles[info.fileIndex].lines[info.line-1]
   var first = min(info.col.int, line.len)
   if first < 0: return
@@ -100,18 +102,18 @@ proc replaceInFile(info: TLineInfo; newName: string) =
   while first > 0 and line[first-1] in prettybase.Letters: dec first
   if first < 0: return
   if line[first] == '`': inc first
-  
+
   let last = first+identLen(line, first)-1
   if differ(line, first, last, newName):
-    # last-first+1 != newName.len or 
-    var x = line.substr(0, first-1) & newName & line.substr(last+1)    
+    # last-first+1 != newName.len or
+    var x = line.substr(0, first-1) & newName & line.substr(last+1)
     system.shallowCopy(gSourceFiles[info.fileIndex].lines[info.line-1], x)
     gSourceFiles[info.fileIndex].dirty = true
 
 proc checkStyle(info: TLineInfo, s: string, k: TSymKind; sym: PSym) =
   let beau = beautifyName(s, k)
   if s != beau:
-    if gStyleCheck == StyleCheck.Auto: 
+    if gStyleCheck == StyleCheck.Auto:
       sym.name = getIdent(beau)
       replaceInFile(info, beau)
     else:
@@ -137,7 +139,7 @@ proc styleCheckUseImpl(info: TLineInfo; s: PSym) =
   if info.fileIndex < 0: return
   # we simply convert it to what it looks like in the definition
   # for consistency
-  
+
   # operators stay as they are:
   if s.kind in {skResult, skTemp} or s.name.s[0] notin prettybase.Letters:
     return
diff --git a/compiler/nimfix/prettybase.nim b/compiler/nimfix/prettybase.nim
index 5130d1863..0f17cbcb1 100644
--- a/compiler/nimfix/prettybase.nim
+++ b/compiler/nimfix/prettybase.nim
@@ -7,7 +7,8 @@
 #    distribution, for details about the copyright.
 #
 
-import ast, msgs, strutils, idents, lexbase, streams
+import strutils, lexbase, streams
+import compiler/ast, compiler/msgs, compiler/idents
 from os import splitFile
 
 type
@@ -39,7 +40,7 @@ proc loadFile*(info: TLineInfo) =
     var pos = lex.bufpos
     while true:
       case lex.buf[pos]
-      of '\c': 
+      of '\c':
         gSourceFiles[i].newline = "\c\L"
         break
       of '\L', '\0':
@@ -70,7 +71,7 @@ proc replaceDeprecated*(info: TLineInfo; oldSym, newSym: PIdent) =
   while first > 0 and line[first-1] in Letters: dec first
   if first < 0: return
   if line[first] == '`': inc first
-  
+
   let last = first+identLen(line, first)-1
   if cmpIgnoreStyle(line[first..last], oldSym.s) == 0:
     var x = line.substr(0, first-1) & newSym.s & line.substr(last+1)
diff --git a/compiler/nimsuggest/nimsuggest.nim b/compiler/nimsuggest/nimsuggest.nim
index 2c785d118..2be368d68 100644
--- a/compiler/nimsuggest/nimsuggest.nim
+++ b/compiler/nimsuggest/nimsuggest.nim
@@ -7,330 +7,6 @@
 #    distribution, for details about the copyright.
 #
 
-## Nimsuggest is a tool that helps to give editors IDE like capabilities.
+## Nimsuggest has been moved to https://github.com/nim-lang/nimsuggest
 
-import strutils, os, parseopt, parseutils, sequtils, net
-# Do NOT import suggest. It will lead to wierd bugs with
-# suggestionResultHook, because suggest.nim is included by sigmatch.
-# So we import that one instead.
-import options, commands, modules, sem, passes, passaux, msgs, nimconf,
-  extccomp, condsyms, lists, net, rdstdin, sexp, sigmatch, ast
-
-when defined(windows):
-  import winlean
-else:
-  import posix
-
-const Usage = """
-Nimsuggest - Tool to give every editor IDE like capabilities for Nim
-Usage:
-  nimsuggest [options] projectfile.nim
-
-Options:
-  --port:PORT             port, by default 6000
-  --address:HOST          binds to that address, by default ""
-  --stdin                 read commands from stdin and write results to
-                          stdout instead of using sockets
-  --epc                   use emacs epc mode
-
-The server then listens to the connection and takes line-based commands.
-
-In addition, all command line options of Nim that do not affect code generation
-are supported.
-"""
-type
-  Mode = enum mstdin, mtcp, mepc
-
-var
-  gPort = 6000.Port
-  gAddress = ""
-  gMode: Mode
-
-const
-  seps = {':', ';', ' ', '\t'}
-  Help = "usage: sug|con|def|use file.nim[;dirtyfile.nim]:line:col\n"&
-         "type 'quit' to quit\n" &
-         "type 'debug' to toggle debug mode on/off\n" &
-         "type 'terse' to toggle terse mode on/off"
-
-type
-  EUnexpectedCommand = object of Exception
-
-proc parseQuoted(cmd: string; outp: var string; start: int): int =
-  var i = start
-  i += skipWhitespace(cmd, i)
-  if cmd[i] == '"':
-    i += parseUntil(cmd, outp, '"', i+1)+2
-  else:
-    i += parseUntil(cmd, outp, seps, i)
-  result = i
-
-proc sexp(s: IdeCmd): SexpNode = sexp($s)
-
-proc sexp(s: TSymKind): SexpNode = sexp($s)
-
-proc sexp(s: Suggest): SexpNode =
-  # If you change the oder here, make sure to change it over in
-  # nim-mode.el too.
-  result = convertSexp([
-    s.section,
-    s.symkind,
-    s.qualifiedPath.map(newSString),
-    s.filePath,
-    s.forth,
-    s.line,
-    s.column,
-    s.doc
-  ])
-
-proc sexp(s: seq[Suggest]): SexpNode =
-  result = newSList()
-  for sug in s:
-    result.add(sexp(sug))
-
-proc listEPC(): SexpNode =
-  let
-    argspecs = sexp("file line column dirtyfile".split(" ").map(newSSymbol))
-    docstring = sexp("line starts at 1, column at 0, dirtyfile is optional")
-  result = newSList()
-  for command in ["sug", "con", "def", "use"]:
-    let
-      cmd = sexp(command)
-      methodDesc = newSList()
-    methodDesc.add(cmd)
-    methodDesc.add(argspecs)
-    methodDesc.add(docstring)
-    result.add(methodDesc)
-
-proc execute(cmd: IdeCmd, file, dirtyfile: string, line, col: int) =
-  gIdeCmd = cmd
-  if cmd == ideUse:
-    modules.resetAllModules()
-  var isKnownFile = true
-  let dirtyIdx = file.fileInfoIdx(isKnownFile)
-
-  if dirtyfile.len != 0: msgs.setDirtyFile(dirtyIdx, dirtyfile)
-  else: msgs.setDirtyFile(dirtyIdx, nil)
-
-  resetModule dirtyIdx
-  if dirtyIdx != gProjectMainIdx:
-    resetModule gProjectMainIdx
-
-  gTrackPos = newLineInfo(dirtyIdx, line, col)
-  gErrorCounter = 0
-  if not isKnownFile:
-    compileProject()
-  compileProject(dirtyIdx)
-
-proc executeEPC(cmd: IdeCmd, args: SexpNode) =
-  let
-    file = args[0].getStr
-    line = args[1].getNum
-    column = args[2].getNum
-  var dirtyfile = ""
-  if len(args) > 3:
-    dirtyfile = args[3].getStr(nil)
-  execute(cmd, file, dirtyfile, int(line), int(column))
-
-proc returnEPC(socket: var Socket, uid: BiggestInt, s: SexpNode, return_symbol = "return") =
-  let response = $convertSexp([newSSymbol(return_symbol), uid, s])
-  socket.send(toHex(len(response), 6))
-  socket.send(response)
-
-proc connectToNextFreePort(server: Socket, host: string, start = 30000): int =
-  result = start
-  while true:
-    try:
-      server.bindaddr(Port(result), host)
-      return
-    except OsError:
-      when defined(windows):
-        let checkFor = WSAEADDRINUSE.OSErrorCode
-      else:
-        let checkFor = EADDRINUSE.OSErrorCode
-      if osLastError() != checkFor:
-        raise getCurrentException()
-      else:
-        result += 1
-
-proc parseCmdLine(cmd: string) =
-  template toggle(sw) =
-    if sw in gGlobalOptions:
-      excl(gGlobalOptions, sw)
-    else:
-      incl(gGlobalOptions, sw)
-    return
-
-  template err() =
-    echo Help
-    return
-
-  var opc = ""
-  var i = parseIdent(cmd, opc, 0)
-  case opc.normalize
-  of "sug": gIdeCmd = ideSug
-  of "con": gIdeCmd = ideCon
-  of "def": gIdeCmd = ideDef
-  of "use": gIdeCmd = ideUse
-  of "quit": quit()
-  of "debug": toggle optIdeDebug
-  of "terse": toggle optIdeTerse
-  else: err()
-  var dirtyfile = ""
-  var orig = ""
-  i = parseQuoted(cmd, orig, i)
-  if cmd[i] == ';':
-    i = parseQuoted(cmd, dirtyfile, i+1)
-  i += skipWhile(cmd, seps, i)
-  var line = -1
-  var col = 0
-  i += parseInt(cmd, line, i)
-  i += skipWhile(cmd, seps, i)
-  i += parseInt(cmd, col, i)
-
-  execute(gIdeCmd, orig, dirtyfile, line, col-1)
-
-proc serve() =
-  case gMode:
-  of mstdin:
-    echo Help
-    var line = ""
-    while readLineFromStdin("> ", line):
-      parseCmdLine line
-      echo ""
-      flushFile(stdout)
-  of mtcp:
-    var server = newSocket()
-    server.bindAddr(gPort, gAddress)
-    var inp = "".TaintedString
-    server.listen()
-
-    while true:
-      var stdoutSocket = newSocket()
-      msgs.writelnHook = proc (line: string) =
-        stdoutSocket.send(line & "\c\L")
-
-      accept(server, stdoutSocket)
-
-      stdoutSocket.readLine(inp)
-      parseCmdLine inp.string
-
-      stdoutSocket.send("\c\L")
-      stdoutSocket.close()
-  of mepc:
-    var server = newSocket()
-    let port = connectToNextFreePort(server, "localhost")
-    var inp = "".TaintedString
-    server.listen()
-    echo(port)
-    var client = newSocket()
-    # Wait for connection
-    accept(server, client)
-    while true:
-      var sizeHex = ""
-      if client.recv(sizeHex, 6) != 6:
-        raise newException(ValueError, "didn't get all the hexbytes")
-      var size = 0
-      if parseHex(sizeHex, size) == 0:
-        raise newException(ValueError, "invalid size hex: " & $sizeHex)
-      var messageBuffer = ""
-      if client.recv(messageBuffer, size) != size:
-        raise newException(ValueError, "didn't get all the bytes")
-      let
-        message = parseSexp($messageBuffer)
-        messageType = message[0].getSymbol
-      case messageType:
-      of "call":
-        var results: seq[Suggest] = @[]
-        suggestionResultHook = proc (s: Suggest) =
-          results.add(s)
-
-        let
-          uid = message[1].getNum
-          cmd = parseIdeCmd(message[2].getSymbol)
-          args = message[3]
-        executeEPC(cmd, args)
-        returnEPC(client, uid, sexp(results))
-      of "return":
-        raise newException(EUnexpectedCommand, "no return expected")
-      of "return-error":
-        raise newException(EUnexpectedCommand, "no return expected")
-      of "epc-error":
-        stderr.writeln("recieved epc error: " & $messageBuffer)
-        raise newException(IOError, "epc error")
-      of "methods":
-        returnEPC(client, message[1].getNum, listEPC())
-      else:
-        raise newException(EUnexpectedCommand, "unexpected call: " & messageType)
-
-proc mainCommand =
-  registerPass verbosePass
-  registerPass semPass
-  gCmd = cmdIdeTools
-  incl gGlobalOptions, optCaasEnabled
-  isServing = true
-  wantMainModule()
-  appendStr(searchPaths, options.libpath)
-  if gProjectFull.len != 0:
-    # current path is always looked first for modules
-    prependStr(searchPaths, gProjectPath)
-
-  # do not stop after the first error:
-  msgs.gErrorMax = high(int)
-  compileProject()
-  serve()
-
-proc processCmdLine*(pass: TCmdLinePass, cmd: string) =
-  var p = parseopt.initOptParser(cmd)
-  while true: 
-    parseopt.next(p)
-    case p.kind
-    of cmdEnd: break 
-    of cmdLongoption, cmdShortOption: 
-      case p.key.normalize
-      of "port":
-        gPort = parseInt(p.val).Port
-        gMode = mtcp
-      of "address":
-        gAddress = p.val
-        gMode = mtcp
-      of "stdin": gMode = mstdin
-      of "epc":
-        gMode = mepc
-        gVerbosity = 0          # Port number gotta be first.
-      else: processSwitch(pass, p)
-    of cmdArgument:
-      options.gProjectName = unixToNativePath(p.key)
-      # if processArgument(pass, p, argsCount): break
-
-proc handleCmdLine() =
-  if paramCount() == 0:
-    stdout.writeln(Usage)
-  else:
-    processCmdLine(passCmd1, "")
-    if gProjectName != "":
-      try:
-        gProjectFull = canonicalizePath(gProjectName)
-      except OSError:
-        gProjectFull = gProjectName
-      var p = splitFile(gProjectFull)
-      gProjectPath = p.dir
-      gProjectName = p.name
-    else:
-      gProjectPath = getCurrentDir()
-    loadConfigs(DefaultConfig) # load all config files
-    # now process command line arguments again, because some options in the
-    # command line can overwite the config file's settings
-    extccomp.initVars()
-    processCmdLine(passCmd2, "")
-    mainCommand()
-
-when false:
-  proc quitCalled() {.noconv.} =
-    writeStackTrace()
-
-  addQuitProc(quitCalled)
-
-condsyms.initDefines()
-defineSymbol "nimsuggest"
-handleCmdline()
+{.error: "This project has moved to the following repo: https://github.com/nim-lang/nimsuggest".}
diff --git a/compiler/nimsuggest/nimsuggest.nim.cfg b/compiler/nimsuggest/nimsuggest.nim.cfg
deleted file mode 100644
index acca17396..000000000
--- a/compiler/nimsuggest/nimsuggest.nim.cfg
+++ /dev/null
@@ -1,17 +0,0 @@
-# Special configuration file for the Nim project
-
-gc:markAndSweep
-
-hint[XDeclaredButNotUsed]:off
-path:"$projectPath/../.."
-
-path:"$lib/packages/docutils"
-path:"../../compiler"
-
-define:useStdoutAsStdmsg
-define:nimsuggest
-
-cs:partial
-#define:useNodeIds
-define:booting
-#define:noDocgen
diff --git a/compiler/nodejs.nim b/compiler/nodejs.nim
index e2b79df19..7f9f28aaf 100644
--- a/compiler/nodejs.nim
+++ b/compiler/nodejs.nim
@@ -4,3 +4,5 @@ proc findNodeJs*(): string =
   result = findExe("nodejs")
   if result == "":
     result = findExe("node")
+  if result == "":
+    result = findExe("iojs")
diff --git a/compiler/options.nim b/compiler/options.nim
index b0e711a44..f3277f855 100644
--- a/compiler/options.nim
+++ b/compiler/options.nim
@@ -54,6 +54,7 @@ type                          # please make sure we have under 32 options
     optSkipUserConfigFile,    # skip the users's config file
     optSkipParentConfigFiles, # skip parent dir's config files
     optNoMain,                # do not generate a "main" proc
+    optUseColors,             # use colors for hints, warnings, and errors
     optThreads,               # support for multi-threading
     optStdout,                # output to stdout
     optThreadAnalysis,        # thread analysis pass
@@ -145,6 +146,7 @@ const
 var
   gConfigVars* = newStringTable(modeStyleInsensitive)
   gDllOverrides = newStringTable(modeCaseInsensitive)
+  gPrefixDir* = "" # Overrides the default prefix dir in getPrefixDir proc.
   libpath* = ""
   gProjectName* = "" # holds a name like 'nimrod'
   gProjectPath* = "" # holds a path like /home/alice/projects/nimrod/compiler/
@@ -183,8 +185,13 @@ proc getOutFile*(filename, ext: string): string =
   else: result = changeFileExt(filename, ext)
 
 proc getPrefixDir*(): string =
-  ## gets the application directory
-  result = splitPath(getAppDir()).head
+  ## Gets the prefix dir, usually the parent directory where the binary resides.
+  ##
+  ## This is overrided by some tools (namely nimsuggest) via the ``gPrefixDir``
+  ## global.
+  if gPrefixDir != "": result = gPrefixDir
+  else:
+    result = splitPath(getAppDir()).head
 
 proc canonicalizePath*(path: string): string =
   when not FileSystemCaseSensitive: result = path.expandFilename.toLower
diff --git a/compiler/parser.nim b/compiler/parser.nim
index 0d2ba7cfc..05b4df13d 100644
--- a/compiler/parser.nim
+++ b/compiler/parser.nim
@@ -64,6 +64,7 @@ proc setBaseFlags*(n: PNode, base: TNumericalBase)
 proc parseSymbol*(p: var TParser, allowNil = false): PNode
 proc parseTry(p: var TParser; isExpr: bool): PNode
 proc parseCase(p: var TParser): PNode
+proc parseStmtPragma(p: var TParser): PNode
 # implementation
 
 proc getTok(p: var TParser) =
@@ -499,10 +500,13 @@ proc parsePar(p: var TParser): PNode =
   #| parKeyw = 'discard' | 'include' | 'if' | 'while' | 'case' | 'try'
   #|         | 'finally' | 'except' | 'for' | 'block' | 'const' | 'let'
   #|         | 'when' | 'var' | 'mixin'
-  #| par = '(' optInd (&parKeyw complexOrSimpleStmt ^+ ';'
-  #|                  | simpleExpr ('=' expr (';' complexOrSimpleStmt ^+ ';' )? )?
-  #|                             | (':' expr)? (',' (exprColonEqExpr comma?)*)?  )?
-  #|         optPar ')'
+  #| par = '(' optInd
+  #|           ( &parKeyw complexOrSimpleStmt ^+ ';'
+  #|           | ';' complexOrSimpleStmt ^+ ';'
+  #|           | pragmaStmt
+  #|           | simpleExpr ( ('=' expr (';' complexOrSimpleStmt ^+ ';' )? )
+  #|                        | (':' expr (',' exprColonEqExpr     ^+ ',' )? ) ) )
+  #|           optPar ')'
   #
   # unfortunately it's ambiguous: (expr: expr) vs (exprStmt); however a
   # leading ';' could be used to enforce a 'stmt' context ...
@@ -521,6 +525,8 @@ proc parsePar(p: var TParser): PNode =
     getTok(p)
     optInd(p, result)
     semiStmtList(p, result)
+  elif p.tok.tokType == tkCurlyDotLe:
+    result.add(parseStmtPragma(p))
   elif p.tok.tokType != tkParRi:
     var a = simpleExpr(p)
     if p.tok.tokType == tkEquals:
diff --git a/compiler/patterns.nim b/compiler/patterns.nim
index 368b0b37b..3f8b05940 100644
--- a/compiler/patterns.nim
+++ b/compiler/patterns.nim
@@ -130,7 +130,9 @@ proc matchNested(c: PPatternContext, p, n: PNode, rpn: bool): bool =
 
 proc matches(c: PPatternContext, p, n: PNode): bool =
   # hidden conversions (?)
-  if isPatternParam(c, p):
+  if nfNoRewrite in n.flags:
+    result = false
+  elif isPatternParam(c, p):
     result = bindOrCheck(c, p.sym, n)
   elif n.kind == nkSym and p.kind == nkIdent:
     result = p.ident.id == n.sym.name.id
diff --git a/compiler/plugins/locals/locals.nim b/compiler/plugins/locals/locals.nim
index d89149f33..59e3d677d 100644
--- a/compiler/plugins/locals/locals.nim
+++ b/compiler/plugins/locals/locals.nim
@@ -9,7 +9,8 @@
 
 ## The builtin 'system.locals' implemented as a plugin.
 
-import plugins, ast, astalgo, magicsys, lookups, semdata, lowerings
+import compiler/plugins, compiler/ast, compiler/astalgo, compiler/magicsys,
+  compiler/lookups, compiler/semdata, compiler/lowerings
 
 proc semLocals(c: PContext, n: PNode): PNode =
   var counter = 0
diff --git a/compiler/pragmas.nim b/compiler/pragmas.nim
index c048d78e9..6f37fe756 100644
--- a/compiler/pragmas.nim
+++ b/compiler/pragmas.nim
@@ -37,7 +37,7 @@ const
     wImportc, wExportc, wNodecl, wMagic, wDeprecated, wBorrow, wExtern,
     wImportCpp, wImportObjC, wError, wDiscardable, wGensym, wInject, wRaises,
     wTags, wLocks, wGcSafe}
-  exprPragmas* = {wLine, wLocks}
+  exprPragmas* = {wLine, wLocks, wNoRewrite}
   stmtPragmas* = {wChecks, wObjChecks, wFieldChecks, wRangechecks,
     wBoundchecks, wOverflowchecks, wNilchecks, wAssertions, wWarnings, wHints,
     wLinedir, wStacktrace, wLinetrace, wOptimization, wHint, wWarning, wError,
@@ -859,6 +859,8 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: int,
             c.module.flags.incl sfExperimental
           else:
             localError(it.info, "'experimental' pragma only valid as toplevel statement")
+        of wNoRewrite:
+          noVal(it)
         else: invalidPragma(it)
       else: invalidPragma(it)
   else: processNote(c, it)
diff --git a/compiler/rodread.nim b/compiler/rodread.nim
index e92f7ecfa..dad7d111e 100644
--- a/compiler/rodread.nim
+++ b/compiler/rodread.nim
@@ -90,7 +90,7 @@
 
 import 
   os, options, strutils, nversion, ast, astalgo, msgs, platform, condsyms, 
-  ropes, idents, crc, idgen, types, rodutils, memfiles
+  ropes, idents, securehash, idgen, types, rodutils, memfiles
 
 type 
   TReasonForRecompile* = enum ## all the reasons that can trigger recompilation
@@ -538,10 +538,11 @@ proc cmdChangeTriggersRecompilation(old, new: TCommands): bool =
   # else: trigger recompilation:
   result = true
   
-proc processRodFile(r: PRodReader, crc: TCrc32) = 
+proc processRodFile(r: PRodReader, crc: SecureHash) = 
   var 
     w: string
-    d, inclCrc: int
+    d: int
+  var inclCrc: SecureHash
   while r.s[r.pos] != '\0': 
     var section = rdWord(r)
     if r.reason != rrNone: 
@@ -549,7 +550,8 @@ proc processRodFile(r: PRodReader, crc: TCrc32) =
     case section 
     of "CRC": 
       inc(r.pos)              # skip ':'
-      if int(crc) != decodeVInt(r.s, r.pos): r.reason = rrCrcChange
+      if crc != parseSecureHash(decodeStr(r.s, r.pos)):
+        r.reason = rrCrcChange
     of "ID": 
       inc(r.pos)              # skip ':'
       r.moduleID = decodeVInt(r.s, r.pos)
@@ -596,9 +598,9 @@ proc processRodFile(r: PRodReader, crc: TCrc32) =
       while r.s[r.pos] != ')': 
         w = r.files[decodeVInt(r.s, r.pos)].toFullPath
         inc(r.pos)            # skip ' '
-        inclCrc = decodeVInt(r.s, r.pos)
+        inclCrc = parseSecureHash(decodeStr(r.s, r.pos))
         if r.reason == rrNone: 
-          if not existsFile(w) or (inclCrc != int(crcFromFile(w))): 
+          if not existsFile(w) or (inclCrc != secureHashFile(w)): 
             r.reason = rrInclDeps
         if r.s[r.pos] == '\x0A': 
           inc(r.pos)
@@ -649,7 +651,7 @@ proc startsWith(buf: cstring, token: string, pos = 0): bool =
   while s < token.len and buf[pos+s] == token[s]: inc s
   result = s == token.len
 
-proc newRodReader(modfilename: string, crc: TCrc32, 
+proc newRodReader(modfilename: string, crc: SecureHash,
                   readerIndex: int): PRodReader = 
   new(result)
   try:
@@ -701,7 +703,7 @@ type
     filename*: string
     reason*: TReasonForRecompile
     rd*: PRodReader
-    crc*: TCrc32
+    crc*: SecureHash
     crcDone*: bool
 
   TFileModuleMap = seq[TFileModuleRec]
@@ -794,13 +796,13 @@ proc loadMethods(r: PRodReader) =
     r.methods.add(rrGetSym(r, d, unknownLineInfo()))
     if r.s[r.pos] == ' ': inc(r.pos)
 
-proc getCRC*(fileIdx: int32): TCrc32 =
+proc getCRC*(fileIdx: int32): SecureHash =
   internalAssert fileIdx >= 0 and fileIdx < gMods.len
 
   if gMods[fileIdx].crcDone:
     return gMods[fileIdx].crc
   
-  result = crcFromFile(fileIdx.toFilename)
+  result = secureHashFile(fileIdx.toFilename)
   gMods[fileIdx].crc = result
 
 template growCache*(cache, pos) =
@@ -1017,7 +1019,7 @@ proc writeType(f: File; t: PType) =
   f.write("]\n")
 
 proc viewFile(rodfile: string) =
-  var r = newRodReader(rodfile, 0, 0)
+  var r = newRodReader(rodfile, secureHash(""), 0)
   if r == nil:
     rawMessage(errGenerated, "cannot open file (or maybe wrong version):" &
        rodfile)
diff --git a/compiler/rodwrite.nim b/compiler/rodwrite.nim
index e178b7ce6..737387597 100644
--- a/compiler/rodwrite.nim
+++ b/compiler/rodwrite.nim
@@ -13,14 +13,15 @@
 
 import 
   intsets, os, options, strutils, nversion, ast, astalgo, msgs, platform,
-  condsyms, ropes, idents, crc, rodread, passes, importer, idgen, rodutils
+  condsyms, ropes, idents, securehash, rodread, passes, importer, idgen,
+  rodutils
 
 # implementation
 
 type 
   TRodWriter = object of TPassContext
     module: PSym
-    crc: TCrc32
+    crc: SecureHash
     options: TOptions
     defines: string
     inclDeps: string
@@ -38,7 +39,7 @@ type
 
   PRodWriter = ref TRodWriter
 
-proc newRodWriter(crc: TCrc32, module: PSym): PRodWriter
+proc newRodWriter(crc: SecureHash, module: PSym): PRodWriter
 proc addModDep(w: PRodWriter, dep: string)
 proc addInclDep(w: PRodWriter, dep: string)
 proc addInterfaceSym(w: PRodWriter, s: PSym)
@@ -62,7 +63,7 @@ proc fileIdx(w: PRodWriter, filename: string): int =
 template filename*(w: PRodWriter): string =
   w.module.filename
 
-proc newRodWriter(crc: TCrc32, module: PSym): PRodWriter = 
+proc newRodWriter(crc: SecureHash, module: PSym): PRodWriter = 
   new(result)
   result.sstack = @[]
   result.tstack = @[]
@@ -96,7 +97,7 @@ proc addInclDep(w: PRodWriter, dep: string) =
   var resolved = dep.findModule(w.module.info.toFullPath)
   encodeVInt(fileIdx(w, dep), w.inclDeps)
   add(w.inclDeps, " ")
-  encodeVInt(crcFromFile(resolved), w.inclDeps)
+  encodeStr($secureHashFile(resolved), w.inclDeps)
   add(w.inclDeps, rodNL)
 
 proc pushType(w: PRodWriter, t: PType) =
@@ -440,7 +441,7 @@ proc writeRod(w: PRodWriter) =
   f.write(rodNL)
   
   var crc = "CRC:"
-  encodeVInt(w.crc, crc)
+  encodeStr($w.crc, crc)
   f.write(crc)
   f.write(rodNL)
   
diff --git a/compiler/securehash.nim b/compiler/securehash.nim
new file mode 100644
index 000000000..8ac6acb0e
--- /dev/null
+++ b/compiler/securehash.nim
@@ -0,0 +1,199 @@
+#
+#
+#           The Nim Compiler
+#        (c) Copyright 2015 Nim Contributers
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+import
+  strutils, unsigned
+
+const Sha1DigestSize = 20
+
+type
+  Sha1Digest = array[0 .. Sha1DigestSize-1, uint8]
+  SecureHash* = distinct Sha1Digest
+
+proc sha1(src: string) : Sha1Digest
+
+proc secureHash*(str: string): SecureHash = SecureHash(sha1(str))
+proc secureHashFile*(filename: string): SecureHash = secureHash(readFile(filename))
+proc `$`*(self: SecureHash): string =
+  result = ""
+  for v in Sha1Digest(self):
+    result.add(toHex(int(v), 2))
+
+proc parseSecureHash*(hash: string): SecureHash =
+  for i in 0.. <Sha1DigestSize:
+    Sha1Digest(result)[i] = uint8(parseHexInt(hash[i*2] & hash[i*2 + 1]))
+
+proc `==`*(a, b: SecureHash): bool =
+  # Not a constant-time comparison, but that's acceptable in this context
+  Sha1Digest(a) == Sha1Digest(b)
+
+
+when isMainModule:
+  let hash1 = secureHash("a93tgj0p34jagp9[agjp98ajrhp9aej]")
+  doAssert hash1 == hash1
+  doAssert parseSecureHash($hash1) == hash1
+
+
+# Copyright (c) 2011, Micael Hildenborg
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+# * Redistributions of source code must retain the above copyright
+#   notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright
+#   notice, this list of conditions and the following disclaimer in the
+#   documentation and/or other materials provided with the distribution.
+# * Neither the name of Micael Hildenborg nor the
+#   names of its contributors may be used to endorse or promote products
+#   derived from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY Micael Hildenborg ''AS IS'' AND ANY
+# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL Micael Hildenborg BE LIABLE FOR ANY
+# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+# Ported to Nim by Erik O'Leary
+
+type
+  Sha1State = array[0 .. 5-1, uint32]
+  Sha1Buffer = array[0 .. 80-1, uint32]
+
+template clearBuffer(w: Sha1Buffer, len = 16) =
+  zeroMem(addr(w), len * sizeof(uint32))
+
+proc init(result: var Sha1State) =
+  result[0] = 0x67452301'u32
+  result[1] = 0xefcdab89'u32
+  result[2] = 0x98badcfe'u32
+  result[3] = 0x10325476'u32
+  result[4] = 0xc3d2e1f0'u32
+
+proc innerHash(state: var Sha1State, w: var Sha1Buffer) =
+  var
+    a = state[0]
+    b = state[1]
+    c = state[2]
+    d = state[3]
+    e = state[4]
+
+  var round = 0
+
+  template rot(value, bits: uint32): uint32 {.immediate.} =
+    (value shl bits) or (value shr (32 - bits))
+
+  template sha1(fun, val: uint32): stmt =
+    let t = rot(a, 5) + fun + e + val + w[round]
+    e = d
+    d = c
+    c = rot(b, 30)
+    b = a
+    a = t
+
+  template process(body: stmt): stmt =
+    w[round] = rot(w[round - 3] xor w[round - 8] xor w[round - 14] xor w[round - 16], 1)
+    body
+    inc(round)
+
+  template wrap(dest, value: expr): stmt {.immediate.} =
+    let v = dest + value
+    dest = v
+
+  while round < 16:
+    sha1((b and c) or (not b and d), 0x5a827999'u32)
+    inc(round)
+
+  while round < 20:
+    process:
+      sha1((b and c) or (not b and d), 0x5a827999'u32)
+
+  while round < 40:
+    process:
+      sha1(b xor c xor d, 0x6ed9eba1'u32)
+
+  while round < 60:
+    process:
+      sha1((b and c) or (b and d) or (c and d), 0x8f1bbcdc'u32)
+
+  while round < 80:
+    process:
+      sha1(b xor c xor d, 0xca62c1d6'u32)
+
+  wrap state[0], a
+  wrap state[1], b
+  wrap state[2], c
+  wrap state[3], d
+  wrap state[4], e
+
+template computeInternal(src: expr): stmt {.immediate.} =
+  #Initialize state
+  var state: Sha1State
+  init(state)
+
+  #Create w buffer
+  var w: Sha1Buffer
+
+  #Loop through all complete 64byte blocks.
+  let byteLen         = src.len
+  let endOfFullBlocks = byteLen - 64
+  var endCurrentBlock = 0
+  var currentBlock    = 0
+
+  while currentBlock <= endOfFullBlocks:
+    endCurrentBlock = currentBlock + 64
+
+    var i = 0
+    while currentBlock < endCurrentBlock:
+      w[i] = uint32(src[currentBlock+3]) or
+             uint32(src[currentBlock+2]) shl 8'u32 or
+             uint32(src[currentBlock+1]) shl 16'u32 or
+             uint32(src[currentBlock])   shl 24'u32
+      currentBlock += 4
+      inc(i)
+
+    innerHash(state, w)
+
+  #Handle last and not full 64 byte block if existing
+  endCurrentBlock = byteLen - currentBlock
+  clearBuffer(w)
+  var lastBlockBytes = 0
+
+  while lastBlockBytes < endCurrentBlock:
+
+    var value = uint32(src[lastBlockBytes + currentBlock]) shl
+                ((3'u32 - (lastBlockBytes and 3)) shl 3)
+
+    w[lastBlockBytes shr 2] = w[lastBlockBytes shr 2] or value
+    inc(lastBlockBytes)
+
+  w[lastBlockBytes shr 2] = w[lastBlockBytes shr 2] or (
+    0x80'u32 shl ((3'u32 - (lastBlockBytes and 3)) shl 3)
+  )
+
+  if endCurrentBlock >= 56:
+    innerHash(state, w)
+    clearBuffer(w)
+
+  w[15] = uint32(byteLen) shl 3
+  innerHash(state, w)
+
+  # Store hash in result pointer, and make sure we get in in the correct order
+  # on both endian models.
+  for i in 0 .. Sha1DigestSize-1:
+    result[i] = uint8((int(state[i shr 2]) shr ((3-(i and 3)) * 8)) and 255)
+
+proc sha1(src: string) : Sha1Digest =
+  ## Calculate SHA1 from input string
+  computeInternal(src)
diff --git a/compiler/semcall.nim b/compiler/semcall.nim
index c48e761e3..571504c3a 100644
--- a/compiler/semcall.nim
+++ b/compiler/semcall.nim
@@ -209,7 +209,10 @@ proc resolveOverloads(c: PContext, n, orig: PNode,
       pickBest(callOp)
 
     if overloadsState == csEmpty and result.state == csEmpty:
-      localError(n.info, errUndeclaredIdentifier, considerQuotedIdent(f).s)
+      if nfDotField in n.flags and nfExplicitCall notin n.flags:
+        localError(n.info, errUndeclaredField, considerQuotedIdent(f).s)
+      else:
+        localError(n.info, errUndeclaredRoutine, considerQuotedIdent(f).s)
       return
     elif result.state != csMatch:
       if nfExprCall in n.flags:
diff --git a/compiler/semfold.nim b/compiler/semfold.nim
index da24005c2..b83641706 100644
--- a/compiler/semfold.nim
+++ b/compiler/semfold.nim
@@ -179,7 +179,7 @@ proc getIntervalType*(m: TMagic, n: PNode): PType =
       else:
         result = makeRangeF(a, abs(getFloat(a.n.sons[1])),
                                abs(getFloat(a.n.sons[0])))
-  of mAbsI, mAbsI64:
+  of mAbsI:
     let a = n.sons[1].typ
     if isIntRange(a):
       if a.n[0].intVal <= 0:
@@ -200,13 +200,13 @@ proc getIntervalType*(m: TMagic, n: PNode): PType =
     if isIntRange(a) and isIntLit(b):
       result = makeRange(a, pickMinInt(n.sons[1]) |-| pickMinInt(n.sons[2]),
                             pickMaxInt(n.sons[1]) |-| pickMaxInt(n.sons[2]))
-  of mAddI, mAddI64, mAddU:
+  of mAddI, mAddU:
     commutativeOp(`|+|`)
-  of mMulI, mMulI64, mMulU:
+  of mMulI, mMulU:
     commutativeOp(`|*|`)
-  of mSubI, mSubI64, mSubU:
+  of mSubI, mSubU:
     binaryOp(`|-|`)
-  of mBitandI, mBitandI64:
+  of mBitandI:
     # since uint64 is still not even valid for 'range' (since it's no ordinal
     # yet), we exclude it from the list (see bug #1638) for now:
     var a = n.sons[1]
@@ -225,7 +225,7 @@ proc getIntervalType*(m: TMagic, n: PNode): PType =
         result = makeRange(a.typ, 0, b.intVal-1)
       else:
         result = makeRange(a.typ, b.intVal+1, 0)
-  of mModI, mModI64:
+  of mModI:
     # so ... if you ever wondered about modulo's signedness; this defines it:
     let a = n.sons[1]
     let b = n.sons[2]
@@ -234,7 +234,7 @@ proc getIntervalType*(m: TMagic, n: PNode): PType =
         result = makeRange(a.typ, -(b.intVal-1), b.intVal-1)
       else:
         result = makeRange(a.typ, b.intVal+1, -(b.intVal+1))
-  of mDivI, mDivI64, mDivU:
+  of mDivI, mDivU:
     binaryOp(`|div|`)
   of mMinI:
     commutativeOp(min)
@@ -243,8 +243,8 @@ proc getIntervalType*(m: TMagic, n: PNode): PType =
   else: discard
 
 discard """
-  mShlI, mShlI64,
-  mShrI, mShrI64, mAddF64, mSubF64, mMulF64, mDivF64, mMaxF64, mMinF64
+  mShlI,
+  mShrI, mAddF64, mSubF64, mMulF64, mDivF64, mMaxF64, mMinF64
 """
 
 proc evalIs(n, a: PNode): PNode =
@@ -285,7 +285,7 @@ proc evalOp(m: TMagic, n, a, b, c: PNode): PNode =
   of mUnaryMinusF64: result = newFloatNodeT(- getFloat(a), n)
   of mNot: result = newIntNodeT(1 - getInt(a), n)
   of mCard: result = newIntNodeT(nimsets.cardSet(a), n)
-  of mBitnotI, mBitnotI64: result = newIntNodeT(not getInt(a), n)
+  of mBitnotI: result = newIntNodeT(not getInt(a), n)
   of mLengthStr, mXLenStr:
     if a.kind == nkNilLit: result = newIntNodeT(0, n)
     else: result = newIntNodeT(len(getStr(a)), n)
@@ -298,7 +298,7 @@ proc evalOp(m: TMagic, n, a, b, c: PNode): PNode =
     result = newFloatNodeT(toFloat(int(getInt(a))), n)
   of mToInt, mToBiggestInt: result = newIntNodeT(system.toInt(getFloat(a)), n)
   of mAbsF64: result = newFloatNodeT(abs(getFloat(a)), n)
-  of mAbsI, mAbsI64:
+  of mAbsI:
     if getInt(a) >= 0: result = a
     else: result = newIntNodeT(- getInt(a), n)
   of mZe8ToI, mZe8ToI64, mZe16ToI, mZe16ToI64, mZe32ToI64, mZeIToI64:
@@ -310,16 +310,16 @@ proc evalOp(m: TMagic, n, a, b, c: PNode): PNode =
   of mUnaryLt: result = newIntNodeT(getOrdValue(a) - 1, n)
   of mSucc: result = newIntNodeT(getOrdValue(a) + getInt(b), n)
   of mPred: result = newIntNodeT(getOrdValue(a) - getInt(b), n)
-  of mAddI, mAddI64: result = newIntNodeT(getInt(a) + getInt(b), n)
-  of mSubI, mSubI64: result = newIntNodeT(getInt(a) - getInt(b), n)
-  of mMulI, mMulI64: result = newIntNodeT(getInt(a) * getInt(b), n)
+  of mAddI: result = newIntNodeT(getInt(a) + getInt(b), n)
+  of mSubI: result = newIntNodeT(getInt(a) - getInt(b), n)
+  of mMulI: result = newIntNodeT(getInt(a) * getInt(b), n)
   of mMinI:
     if getInt(a) > getInt(b): result = newIntNodeT(getInt(b), n)
     else: result = newIntNodeT(getInt(a), n)
   of mMaxI:
     if getInt(a) > getInt(b): result = newIntNodeT(getInt(a), n)
     else: result = newIntNodeT(getInt(b), n)
-  of mShlI, mShlI64:
+  of mShlI:
     case skipTypes(n.typ, abstractRange).kind
     of tyInt8: result = newIntNodeT(int8(getInt(a)) shl int8(getInt(b)), n)
     of tyInt16: result = newIntNodeT(int16(getInt(a)) shl int16(getInt(b)), n)
@@ -327,7 +327,7 @@ proc evalOp(m: TMagic, n, a, b, c: PNode): PNode =
     of tyInt64, tyInt, tyUInt..tyUInt64:
       result = newIntNodeT(`shl`(getInt(a), getInt(b)), n)
     else: internalError(n.info, "constant folding for shl")
-  of mShrI, mShrI64:
+  of mShrI:
     case skipTypes(n.typ, abstractRange).kind
     of tyInt8: result = newIntNodeT(int8(getInt(a)) shr int8(getInt(b)), n)
     of tyInt16: result = newIntNodeT(int16(getInt(a)) shr int16(getInt(b)), n)
@@ -335,11 +335,11 @@ proc evalOp(m: TMagic, n, a, b, c: PNode): PNode =
     of tyInt64, tyInt, tyUInt..tyUInt64:
       result = newIntNodeT(`shr`(getInt(a), getInt(b)), n)
     else: internalError(n.info, "constant folding for shr")
-  of mDivI, mDivI64:
+  of mDivI:
     let y = getInt(b)
     if y != 0:
       result = newIntNodeT(getInt(a) div y, n)
-  of mModI, mModI64:
+  of mModI:
     let y = getInt(b)
     if y != 0:
       result = newIntNodeT(getInt(a) mod y, n)
@@ -359,11 +359,11 @@ proc evalOp(m: TMagic, n, a, b, c: PNode): PNode =
     if getFloat(a) > getFloat(b): result = newFloatNodeT(getFloat(b), n)
     else: result = newFloatNodeT(getFloat(a), n)
   of mIsNil: result = newIntNodeT(ord(a.kind == nkNilLit), n)
-  of mLtI, mLtI64, mLtB, mLtEnum, mLtCh:
+  of mLtI, mLtB, mLtEnum, mLtCh:
     result = newIntNodeT(ord(getOrdValue(a) < getOrdValue(b)), n)
-  of mLeI, mLeI64, mLeB, mLeEnum, mLeCh:
+  of mLeI, mLeB, mLeEnum, mLeCh:
     result = newIntNodeT(ord(getOrdValue(a) <= getOrdValue(b)), n)
-  of mEqI, mEqI64, mEqB, mEqEnum, mEqCh:
+  of mEqI, mEqB, mEqEnum, mEqCh:
     result = newIntNodeT(ord(getOrdValue(a) == getOrdValue(b)), n)
   of mLtF64: result = newIntNodeT(ord(getFloat(a) < getFloat(b)), n)
   of mLeF64: result = newIntNodeT(ord(getFloat(a) <= getFloat(b)), n)
@@ -375,9 +375,9 @@ proc evalOp(m: TMagic, n, a, b, c: PNode): PNode =
     result = newIntNodeT(ord(`<%`(getOrdValue(a), getOrdValue(b))), n)
   of mLeU, mLeU64:
     result = newIntNodeT(ord(`<=%`(getOrdValue(a), getOrdValue(b))), n)
-  of mBitandI, mBitandI64, mAnd: result = newIntNodeT(a.getInt and b.getInt, n)
-  of mBitorI, mBitorI64, mOr: result = newIntNodeT(getInt(a) or getInt(b), n)
-  of mBitxorI, mBitxorI64, mXor: result = newIntNodeT(a.getInt xor b.getInt, n)
+  of mBitandI, mAnd: result = newIntNodeT(a.getInt and b.getInt, n)
+  of mBitorI, mOr: result = newIntNodeT(getInt(a) or getInt(b), n)
+  of mBitxorI, mXor: result = newIntNodeT(a.getInt xor b.getInt, n)
   of mAddU: result = newIntNodeT(`+%`(getInt(a), getInt(b)), n)
   of mSubU: result = newIntNodeT(`-%`(getInt(a), getInt(b)), n)
   of mMulU: result = newIntNodeT(`*%`(getInt(a), getInt(b)), n)
diff --git a/compiler/sempass2.nim b/compiler/sempass2.nim
index adf03be64..12c4a7c7b 100644
--- a/compiler/sempass2.nim
+++ b/compiler/sempass2.nim
@@ -207,9 +207,9 @@ proc markGcUnsafe(a: PEffects; reason: PNode) =
       a.owner.gcUnsafetyReason = newSym(skUnknown, getIdent("<unknown>"),
                                         a.owner, reason.info)
 
-proc listGcUnsafety(s: PSym; onlyWarning: bool) =
+proc listGcUnsafety(s: PSym; onlyWarning: bool; cycleCheck: var IntSet) =
   let u = s.gcUnsafetyReason
-  if u != nil:
+  if u != nil and not cycleCheck.containsOrIncl(u.id):
     let msgKind = if onlyWarning: warnGcUnsafe2 else: errGenerated
     if u.kind in {skLet, skVar}:
       message(s.info, msgKind,
@@ -218,7 +218,7 @@ proc listGcUnsafety(s: PSym; onlyWarning: bool) =
     elif u.kind in routineKinds:
       # recursive call *always* produces only a warning so the full error
       # message is printed:
-      listGcUnsafety(u, true)
+      listGcUnsafety(u, true, cycleCheck)
       message(s.info, msgKind,
         "'$#' is not GC-safe as it calls '$#'" %
         [s.name.s, u.name.s])
@@ -227,6 +227,10 @@ proc listGcUnsafety(s: PSym; onlyWarning: bool) =
       message(u.info, msgKind,
         "'$#' is not GC-safe as it performs an indirect call here" % s.name.s)
 
+proc listGcUnsafety(s: PSym; onlyWarning: bool) =
+  var cycleCheck = initIntSet()
+  listGcUnsafety(s, onlyWarning, cycleCheck)
+
 proc useVar(a: PEffects, n: PNode) =
   let s = n.sym
   if isLocalVar(a, s):
diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim
index c355a5bf1..43cdca866 100644
--- a/compiler/semstmts.nim
+++ b/compiler/semstmts.nim
@@ -1268,6 +1268,8 @@ proc semPragmaBlock(c: PContext, n: PNode): PNode =
     of wLocks:
       result = n
       result.typ = n.sons[1].typ
+    of wNoRewrite:
+      incl(result.flags, nfNoRewrite)
     else: discard
 
 proc semStaticStmt(c: PContext, n: PNode): PNode =
diff --git a/compiler/treetab.nim b/compiler/treetab.nim
index 8d66d56c7..adfc7b2ce 100644
--- a/compiler/treetab.nim
+++ b/compiler/treetab.nim
@@ -12,7 +12,7 @@
 import 
   hashes, ast, astalgo, types
 
-proc hashTree(n: PNode): THash = 
+proc hashTree(n: PNode): Hash = 
   if n == nil: return 
   result = ord(n.kind)
   case n.kind
@@ -53,8 +53,8 @@ proc treesEquivalent(a, b: PNode): bool =
         result = true
     if result: result = sameTypeOrNil(a.typ, b.typ)
   
-proc nodeTableRawGet(t: TNodeTable, k: THash, key: PNode): int = 
-  var h: THash = k and high(t.data)
+proc nodeTableRawGet(t: TNodeTable, k: Hash, key: PNode): int = 
+  var h: Hash = k and high(t.data)
   while t.data[h].key != nil: 
     if (t.data[h].h == k) and treesEquivalent(t.data[h].key, key): 
       return h
@@ -66,9 +66,9 @@ proc nodeTableGet*(t: TNodeTable, key: PNode): int =
   if index >= 0: result = t.data[index].val
   else: result = low(int)
   
-proc nodeTableRawInsert(data: var TNodePairSeq, k: THash, key: PNode, 
+proc nodeTableRawInsert(data: var TNodePairSeq, k: Hash, key: PNode, 
                         val: int) = 
-  var h: THash = k and high(data)
+  var h: Hash = k and high(data)
   while data[h].key != nil: h = nextTry(h, high(data))
   assert(data[h].key == nil)
   data[h].h = k
@@ -77,7 +77,7 @@ proc nodeTableRawInsert(data: var TNodePairSeq, k: THash, key: PNode,
 
 proc nodeTablePut*(t: var TNodeTable, key: PNode, val: int) = 
   var n: TNodePairSeq
-  var k: THash = hashTree(key)
+  var k: Hash = hashTree(key)
   var index = nodeTableRawGet(t, k, key)
   if index >= 0: 
     assert(t.data[index].key != nil)
@@ -94,7 +94,7 @@ proc nodeTablePut*(t: var TNodeTable, key: PNode, val: int) =
 
 proc nodeTableTestOrSet*(t: var TNodeTable, key: PNode, val: int): int = 
   var n: TNodePairSeq
-  var k: THash = hashTree(key)
+  var k: Hash = hashTree(key)
   var index = nodeTableRawGet(t, k, key)
   if index >= 0: 
     assert(t.data[index].key != nil)
diff --git a/compiler/vm.nim b/compiler/vm.nim
index e49bed522..9f0d0bfce 100644
--- a/compiler/vm.nim
+++ b/compiler/vm.nim
@@ -682,11 +682,15 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
     of opcLtu:
       decodeBC(rkInt)
       regs[ra].intVal = ord(regs[rb].intVal <% regs[rc].intVal)
-    of opcEqRef, opcEqNimrodNode:
+    of opcEqRef:
       decodeBC(rkInt)
       regs[ra].intVal = ord((regs[rb].node.kind == nkNilLit and
                              regs[rc].node.kind == nkNilLit) or
                              regs[rb].node == regs[rc].node)
+    of opcEqNimrodNode:
+      decodeBC(rkInt)
+      regs[ra].intVal =
+        ord(exprStructuralEquivalent(regs[rb].node, regs[rc].node))
     of opcXor:
       decodeBC(rkInt)
       regs[ra].intVal = ord(regs[rb].intVal != regs[rc].intVal)
diff --git a/compiler/vmgen.nim b/compiler/vmgen.nim
index 0743a4502..c68282fde 100644
--- a/compiler/vmgen.nim
+++ b/compiler/vmgen.nim
@@ -710,9 +710,9 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) =
     if dest < 0: dest = c.getTemp(n.typ)
     c.gABI(n, opcSubImmInt, dest, tmp, 1)
     c.freeTemp(tmp)
-  of mPred, mSubI, mSubI64:
+  of mPred, mSubI:
     c.genAddSubInt(n, dest, opcSubInt)
-  of mSucc, mAddI, mAddI64:
+  of mSucc, mAddI:
     c.genAddSubInt(n, dest, opcAddInt)
   of mInc, mDec:
     unused(n, dest)
@@ -759,28 +759,28 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) =
     c.freeTemp(d)
     c.freeTemp(tmp)
   of mCard: genCard(c, n, dest)
-  of mMulI, mMulI64: genBinaryABCnarrow(c, n, dest, opcMulInt)
-  of mDivI, mDivI64: genBinaryABCnarrow(c, n, dest, opcDivInt)
-  of mModI, mModI64: genBinaryABCnarrow(c, n, dest, opcModInt)
+  of mMulI: genBinaryABCnarrow(c, n, dest, opcMulInt)
+  of mDivI: genBinaryABCnarrow(c, n, dest, opcDivInt)
+  of mModI: genBinaryABCnarrow(c, n, dest, opcModInt)
   of mAddF64: genBinaryABC(c, n, dest, opcAddFloat)
   of mSubF64: genBinaryABC(c, n, dest, opcSubFloat)
   of mMulF64: genBinaryABC(c, n, dest, opcMulFloat)
   of mDivF64: genBinaryABC(c, n, dest, opcDivFloat)
-  of mShrI, mShrI64: genBinaryABCnarrowU(c, n, dest, opcShrInt)
-  of mShlI, mShlI64: genBinaryABCnarrowU(c, n, dest, opcShlInt)
-  of mBitandI, mBitandI64: genBinaryABCnarrowU(c, n, dest, opcBitandInt)
-  of mBitorI, mBitorI64: genBinaryABCnarrowU(c, n, dest, opcBitorInt)
-  of mBitxorI, mBitxorI64: genBinaryABCnarrowU(c, n, dest, opcBitxorInt)
+  of mShrI: genBinaryABCnarrowU(c, n, dest, opcShrInt)
+  of mShlI: genBinaryABCnarrowU(c, n, dest, opcShlInt)
+  of mBitandI: genBinaryABCnarrowU(c, n, dest, opcBitandInt)
+  of mBitorI: genBinaryABCnarrowU(c, n, dest, opcBitorInt)
+  of mBitxorI: genBinaryABCnarrowU(c, n, dest, opcBitxorInt)
   of mAddU: genBinaryABCnarrowU(c, n, dest, opcAddu)
   of mSubU: genBinaryABCnarrowU(c, n, dest, opcSubu)
   of mMulU: genBinaryABCnarrowU(c, n, dest, opcMulu)
   of mDivU: genBinaryABCnarrowU(c, n, dest, opcDivu)
   of mModU: genBinaryABCnarrowU(c, n, dest, opcModu)
-  of mEqI, mEqI64, mEqB, mEqEnum, mEqCh:
+  of mEqI, mEqB, mEqEnum, mEqCh:
     genBinaryABC(c, n, dest, opcEqInt)
-  of mLeI, mLeI64, mLeEnum, mLeCh, mLeB:
+  of mLeI, mLeEnum, mLeCh, mLeB:
     genBinaryABC(c, n, dest, opcLeInt)
-  of mLtI, mLtI64, mLtEnum, mLtCh, mLtB:
+  of mLtI, mLtEnum, mLtCh, mLtB:
     genBinaryABC(c, n, dest, opcLtInt)
   of mEqF64: genBinaryABC(c, n, dest, opcEqFloat)
   of mLeF64: genBinaryABC(c, n, dest, opcLeFloat)
@@ -796,7 +796,7 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) =
     genNarrow(c, n, dest)
   of mUnaryMinusF64: genUnaryABC(c, n, dest, opcUnaryMinusFloat)
   of mUnaryPlusI, mUnaryPlusF64: gen(c, n.sons[1], dest)
-  of mBitnotI, mBitnotI64:
+  of mBitnotI:
     genUnaryABC(c, n, dest, opcBitnotInt)
     genNarrowU(c, n, dest)
   of mZe8ToI, mZe8ToI64, mZe16ToI, mZe16ToI64, mZe32ToI64, mZeIToI64,
@@ -1013,7 +1013,7 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) =
     c.gABC(n, opcCallSite, dest)
   of mNGenSym: genBinaryABC(c, n, dest, opcGenSym)
   of mMinI, mMaxI, mAbsF64, mMinF64, mMaxF64, mAbsI,
-     mAbsI64, mDotDot:
+     mDotDot:
     c.genCall(n, dest)
   of mExpandToAst:
     if n.len != 2:
diff --git a/compiler/wordrecg.nim b/compiler/wordrecg.nim
index 63fd995c4..deb12536f 100644
--- a/compiler/wordrecg.nim
+++ b/compiler/wordrecg.nim
@@ -55,7 +55,7 @@ type
     wFloatchecks, wNanChecks, wInfChecks,
     wAssertions, wPatterns, wWarnings,
     wHints, wOptimization, wRaises, wWrites, wReads, wSize, wEffects, wTags,
-    wDeadCodeElim, wSafecode, wNoForward,
+    wDeadCodeElim, wSafecode, wNoForward, wNoRewrite,
     wPragma,
     wCompileTime, wNoInit,
     wPassc, wPassl, wBorrow, wDiscardable,
@@ -139,7 +139,7 @@ const
 
     "assertions", "patterns", "warnings", "hints",
     "optimization", "raises", "writes", "reads", "size", "effects", "tags",
-    "deadcodeelim", "safecode", "noforward",
+    "deadcodeelim", "safecode", "noforward", "norewrite",
     "pragma",
     "compiletime", "noinit",
     "passc", "passl", "borrow", "discardable", "fieldchecks",