summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorMichał Zieliński <michal@zielinscy.org.pl>2014-02-09 15:34:18 +0100
committerMichał Zieliński <michal@zielinscy.org.pl>2014-02-09 15:34:18 +0100
commit820fdd634870686082ad01896327f67cf45cd96f (patch)
treeffe146b77359f616d25a28b85ab2ba8efd604f4c
parent11053afff83e00bb04be05590a169ed79ce5f0d3 (diff)
parente6a50307bb505304b37147417ba2a93586d59a51 (diff)
downloadNim-820fdd634870686082ad01896327f67cf45cd96f.tar.gz
Merge branch 'devel' of https://github.com/Araq/Nimrod into devel
-rw-r--r--compiler/ast.nim6
-rw-r--r--compiler/astalgo.nim33
-rw-r--r--compiler/ccgexprs.nim4
-rw-r--r--compiler/evalffi.nim56
-rw-r--r--compiler/lambdalifting.nim53
-rw-r--r--compiler/lookups.nim14
-rw-r--r--compiler/main.nim7
-rw-r--r--compiler/parser.nim50
-rw-r--r--compiler/sem.nim4
-rw-r--r--compiler/semdata.nim3
-rw-r--r--compiler/semexprs.nim20
-rw-r--r--compiler/semgnrc.nim11
-rw-r--r--compiler/semstmts.nim17
-rw-r--r--compiler/semthreads.nim2
-rw-r--r--compiler/semtypes.nim41
-rw-r--r--compiler/semtypinst.nim2
-rw-r--r--compiler/sigmatch.nim20
-rw-r--r--compiler/types.nim7
-rw-r--r--compiler/vm.nim27
-rw-r--r--compiler/vmdef.nim2
-rw-r--r--compiler/vmgen.nim146
-rw-r--r--config/nimdoc.cfg2
-rw-r--r--config/nimdoc.tex.cfg2
-rw-r--r--copying.txt2
-rw-r--r--devel/logging.nim210
-rw-r--r--doc/gc.txt17
-rw-r--r--doc/grammar.txt3
-rw-r--r--doc/lib.txt3
-rw-r--r--doc/manual.txt233
-rw-r--r--doc/tut1.txt24
-rw-r--r--doc/tut2.txt4
-rw-r--r--koch.nim5
-rw-r--r--lib/core/macros.nim28
-rw-r--r--lib/impure/db_mongo.nim4
-rw-r--r--lib/impure/db_sqlite.nim6
-rw-r--r--lib/packages/docutils/highlite.nim8
-rw-r--r--lib/posix/posix.nim12
-rw-r--r--lib/pure/algorithm.nim33
-rw-r--r--lib/pure/asyncio.nim2
-rw-r--r--lib/pure/collections/sequtils.nim39
-rw-r--r--lib/pure/collections/sets.nim17
-rw-r--r--lib/pure/collections/tables.nim10
-rw-r--r--lib/pure/dynlib.nim20
-rw-r--r--lib/pure/htmlparser.nim4
-rw-r--r--lib/pure/irc.nim4
-rw-r--r--lib/pure/logging.nim267
-rw-r--r--lib/pure/matchers.nim2
-rw-r--r--lib/pure/oids.nim2
-rw-r--r--lib/pure/os.nim80
-rw-r--r--lib/pure/osproc.nim6
-rw-r--r--lib/pure/parsecsv.nim2
-rw-r--r--lib/pure/parsesql.nim6
-rw-r--r--lib/pure/smtp.nim4
-rw-r--r--lib/pure/sockets.nim7
-rw-r--r--lib/pure/strutils.nim10
-rw-r--r--lib/pure/times.nim8
-rw-r--r--lib/pure/xmlparser.nim4
-rw-r--r--lib/system.nim38
-rw-r--r--lib/system/excpt.nim2
-rw-r--r--lib/system/gc.nim2
-rw-r--r--lib/system/gc_ms.nim28
-rw-r--r--lib/windows/winlean.nim24
-rw-r--r--lib/wrappers/mongo.nim52
-rw-r--r--lib/wrappers/openssl.nim24
-rw-r--r--readme.md2
-rw-r--r--readme.txt2
-rw-r--r--tests/collections/ttables.nim22
-rw-r--r--tests/exprs/tstmtexprs.nim19
-rw-r--r--tests/gc/gcleak4.nim2
-rw-r--r--tests/gc/gcleak5.nim25
-rw-r--r--tests/generics/tgenericrefs.nim12
-rw-r--r--tests/iter/tanoniter1.nim4
-rw-r--r--tests/macros/tdebugstmt.nim29
-rw-r--r--tests/macros/tdumpast.nim2
-rw-r--r--tests/macros/tdumpast2.nim2
-rw-r--r--tests/macros/tmacrogenerics.nim6
-rw-r--r--tests/macros/tmacrotypes.nim4
-rw-r--r--tests/macros/tmemit.nim2
-rw-r--r--tests/macros/tstringinterp.nim6
-rw-r--r--tests/parser/tcommand_as_expr.nim21
-rw-r--r--tests/sets/testequivalence.nim15
-rw-r--r--tests/specials.nim238
-rw-r--r--tests/stdlib/talgorithm.nim8
-rw-r--r--tests/template/tprefer_immediate.nim17
-rw-r--r--tests/testament/backend.nim12
-rw-r--r--tests/testament/categories.nim5
-rw-r--r--tests/testament/htmlgen.nim19
-rw-r--r--tests/testament/tester.nim15
-rw-r--r--tests/tester.nim457
-rw-r--r--todo.txt11
-rw-r--r--web/nimrod.ini2
91 files changed, 1373 insertions, 1371 deletions
diff --git a/compiler/ast.nim b/compiler/ast.nim
index 7138b5f52..cd002eef1 100644
--- a/compiler/ast.nim
+++ b/compiler/ast.nim
@@ -1129,7 +1129,7 @@ proc newType(kind: TTypeKind, owner: PSym): PType =
   result.align = 2            # default alignment
   result.id = getID()
   when debugIds:
-    RegisterId(result)
+    registerId(result)
   #if result.id < 2000 then
   #  MessageOut(typeKindToStr[kind] & ' has id: ' & toString(result.id))
   
@@ -1166,7 +1166,7 @@ proc copyType(t: PType, owner: PSym, keepId: bool): PType =
   if keepId: 
     result.id = t.id
   else: 
-    when debugIds: RegisterId(result)
+    when debugIds: registerId(result)
   result.sym = t.sym          # backend-info should not be copied
   
 proc copySym(s: PSym, keepId: bool = false): PSym = 
@@ -1177,7 +1177,7 @@ proc copySym(s: PSym, keepId: bool = false): PSym =
     result.id = s.id
   else: 
     result.id = getID()
-    when debugIds: RegisterId(result)
+    when debugIds: registerId(result)
   result.flags = s.flags
   result.magic = s.magic
   if s.kind == skModule:
diff --git a/compiler/astalgo.nim b/compiler/astalgo.nim
index 2505bc687..64c1b717c 100644
--- a/compiler/astalgo.nim
+++ b/compiler/astalgo.nim
@@ -561,14 +561,31 @@ proc strTableContains(t: TStrTable, n: PSym): bool =
 
 proc strTableRawInsert(data: var TSymSeq, n: PSym) = 
   var h: THash = n.name.h and high(data)
-  while data[h] != nil: 
-    if data[h] == n:
-      # allowed for 'export' feature:
-      #InternalError(n.info, "StrTableRawInsert: " & n.name.s)
-      return
-    h = nextTry(h, high(data))
-  assert(data[h] == nil)
-  data[h] = n
+  if sfImmediate notin n.flags:
+    # fast path:
+    while data[h] != nil:
+      if data[h] == n:
+        # allowed for 'export' feature:
+        #InternalError(n.info, "StrTableRawInsert: " & n.name.s)
+        return
+      h = nextTry(h, high(data))
+    assert(data[h] == nil)
+    data[h] = n
+  else:
+    # slow path; we have to ensure immediate symbols are preferred for
+    # symbol lookups.
+    # consider the chain: foo (immediate), foo, bar, bar (immediate)
+    # then bar (immediate) gets replaced with foo (immediate) and the non
+    # immediate foo is picked! Thus we need to replace it with the first
+    # slot that has in fact the same identifier stored in it!
+    var favPos = -1
+    while data[h] != nil:
+      if data[h] == n: return
+      if favPos < 0 and data[h].name.id == n.name.id: favPos = h
+      h = nextTry(h, high(data))
+    assert(data[h] == nil)
+    data[h] = n
+    if favPos >= 0: swap data[h], data[favPos]
 
 proc symTabReplaceRaw(data: var TSymSeq, prevSym: PSym, newSym: PSym) =
   assert prevSym.name.h == newSym.name.h
diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim
index ba543039e..031ab8d70 100644
--- a/compiler/ccgexprs.nim
+++ b/compiler/ccgexprs.nim
@@ -343,7 +343,7 @@ proc genAssignment(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) =
   of tyPtr, tyPointer, tyChar, tyBool, tyEnum, tyCString,
      tyInt..tyUInt64, tyRange, tyVar:
     linefmt(p, cpsStmts, "$1 = $2;$n", rdLoc(dest), rdLoc(src))
-  else: internalError("genAssignment(" & $ty.kind & ')')
+  else: internalError("genAssignment: " & $ty.kind)
 
 proc getDestLoc(p: BProc, d: var TLoc, typ: PType) =
   if d.k == locNone: getTemp(p, typ, d)
@@ -1049,7 +1049,7 @@ proc genObjConstr(p: BProc, e: PNode, d: var TLoc) =
     app(tmp2.r, field.loc.r)
     tmp2.k = locTemp
     tmp2.t = field.loc.t
-    tmp2.s = OnHeap
+    tmp2.s = if isRef: OnHeap else: OnStack
     tmp2.heapRoot = tmp.r
     expr(p, it.sons[1], tmp2)
   if d.k == locNone:
diff --git a/compiler/evalffi.nim b/compiler/evalffi.nim
index 74f0663f3..54be0ccb2 100644
--- a/compiler/evalffi.nim
+++ b/compiler/evalffi.nim
@@ -1,7 +1,7 @@
 #
 #
 #           The Nimrod Compiler
-#        (c) Copyright 2012 Andreas Rumpf
+#        (c) Copyright 2014 Andreas Rumpf
 #
 #    See the file "copying.txt", included in this
 #    distribution, for details about the copyright.
@@ -102,7 +102,7 @@ proc mapCallConv(cc: TCallingConvention, info: TLineInfo): TABI =
   of ccStdCall: result = when defined(windows): STDCALL else: DEFAULT_ABI
   of ccCDecl: result = DEFAULT_ABI
   else:
-    GlobalError(info, "cannot map calling convention to FFI")
+    globalError(info, "cannot map calling convention to FFI")
 
 template rd(T, p: expr): expr {.immediate.} = (cast[ptr T](p))[]
 template wr(T, p, v: expr) {.immediate.} = (cast[ptr T](p))[] = v
@@ -164,7 +164,7 @@ proc packObject(x: PNode, typ: PType, res: pointer) =
       let field = getField(typ.n, i)
       pack(it, field.typ, res +! field.offset)
     else:
-      GlobalError(x.info, "cannot pack unnamed tuple")
+      globalError(x.info, "cannot pack unnamed tuple")
 
 const maxPackDepth = 20
 var packRecCheck = 0
@@ -193,7 +193,7 @@ proc pack(v: PNode, typ: PType, res: pointer) =
     of 4: awr(int32, v.intVal.int32)
     of 8: awr(int64, v.intVal.int64)
     else:
-      GlobalError(v.info, "cannot map value to FFI (tyEnum, tySet)")
+      globalError(v.info, "cannot map value to FFI (tyEnum, tySet)")
   of tyFloat: awr(float, v.floatVal)
   of tyFloat32: awr(float32, v.floatVal)
   of tyFloat64: awr(float64, v.floatVal)
@@ -207,7 +207,7 @@ proc pack(v: PNode, typ: PType, res: pointer) =
     elif v.kind in {nkStrLit..nkTripleStrLit}:
       awr(cstring, cstring(v.strVal))
     else:
-      GlobalError(v.info, "cannot map pointer/proc value to FFI")
+      globalError(v.info, "cannot map pointer/proc value to FFI")
   of tyPtr, tyRef, tyVar:
     if v.kind == nkNilLit:
       # nothing to do since the memory is 0 initialized anyway
@@ -217,7 +217,7 @@ proc pack(v: PNode, typ: PType, res: pointer) =
     else:
       if packRecCheck > maxPackDepth:
         packRecCheck = 0
-        GlobalError(v.info, "cannot map value to FFI " & typeToString(v.typ))
+        globalError(v.info, "cannot map value to FFI " & typeToString(v.typ))
       inc packRecCheck
       pack(v.sons[0], typ.sons[0], res +! sizeof(pointer))
       dec packRecCheck
@@ -233,7 +233,7 @@ proc pack(v: PNode, typ: PType, res: pointer) =
   of tyDistinct, tyGenericInst:
     pack(v, typ.sons[0], res)
   else:
-    GlobalError(v.info, "cannot map value to FFI " & typeToString(v.typ))
+    globalError(v.info, "cannot map value to FFI " & typeToString(v.typ))
 
 proc unpack(x: pointer, typ: PType, n: PNode): PNode
 
@@ -243,7 +243,7 @@ proc unpackObjectAdd(x: pointer, n, result: PNode) =
     for i in countup(0, sonsLen(n) - 1):
       unpackObjectAdd(x, n.sons[i], result)
   of nkRecCase:
-    GlobalError(result.info, "case objects cannot be unpacked")
+    globalError(result.info, "case objects cannot be unpacked")
   of nkSym:
     var pair = newNodeI(nkExprColonExpr, result.info, 2)
     pair.sons[0] = n
@@ -262,14 +262,14 @@ proc unpackObject(x: pointer, typ: PType, n: PNode): PNode =
     result = newNode(nkPar)
     result.typ = typ
     if typ.n.isNil:
-      InternalError("cannot unpack unnamed tuple")
+      internalError("cannot unpack unnamed tuple")
     unpackObjectAdd(x, typ.n, result)
   else:
     result = n
     if result.kind notin {nkObjConstr, nkPar}:
-      GlobalError(n.info, "cannot map value from FFI")
+      globalError(n.info, "cannot map value from FFI")
     if typ.n.isNil:
-      GlobalError(n.info, "cannot unpack unnamed tuple")
+      globalError(n.info, "cannot unpack unnamed tuple")
     for i in countup(ord(n.kind == nkObjConstr), sonsLen(n) - 1):
       var it = n.sons[i]
       if it.kind == nkExprColonExpr:
@@ -288,7 +288,7 @@ proc unpackArray(x: pointer, typ: PType, n: PNode): PNode =
   else:
     result = n
     if result.kind != nkBracket:
-      GlobalError(n.info, "cannot map value from FFI")
+      globalError(n.info, "cannot map value from FFI")
   let baseSize = typ.sons[1].getSize
   for i in 0 .. < result.len:
     result.sons[i] = unpack(x +! i * baseSize, typ.sons[1], result.sons[i])
@@ -312,7 +312,7 @@ proc unpack(x: pointer, typ: PType, n: PNode): PNode =
         #echo "expected ", k, " but got ", result.kind
         #debug result
         return newNodeI(nkExceptBranch, n.info)
-        #GlobalError(n.info, "cannot map value from FFI")
+        #globalError(n.info, "cannot map value from FFI")
     result.field = v
 
   template setNil() =
@@ -337,19 +337,19 @@ proc unpack(x: pointer, typ: PType, n: PNode): PNode =
   of tyInt16: awi(nkInt16Lit, rd(int16, x))
   of tyInt32: awi(nkInt32Lit, rd(int32, x))
   of tyInt64: awi(nkInt64Lit, rd(int64, x))
-  of tyUInt: awi(nkUIntLit, rd(uint, x).biggestInt)
-  of tyUInt8: awi(nkUInt8Lit, rd(uint8, x).biggestInt)
-  of tyUInt16: awi(nkUInt16Lit, rd(uint16, x).biggestInt)
-  of tyUInt32: awi(nkUInt32Lit, rd(uint32, x).biggestInt)
-  of tyUInt64: awi(nkUInt64Lit, rd(uint64, x).biggestInt)
+  of tyUInt: awi(nkUIntLit, rd(uint, x).BiggestInt)
+  of tyUInt8: awi(nkUInt8Lit, rd(uint8, x).BiggestInt)
+  of tyUInt16: awi(nkUInt16Lit, rd(uint16, x).BiggestInt)
+  of tyUInt32: awi(nkUInt32Lit, rd(uint32, x).BiggestInt)
+  of tyUInt64: awi(nkUInt64Lit, rd(uint64, x).BiggestInt)
   of tyEnum:
     case typ.getSize
-    of 1: awi(nkIntLit, rd(uint8, x).biggestInt)
-    of 2: awi(nkIntLit, rd(uint16, x).biggestInt)
-    of 4: awi(nkIntLit, rd(int32, x).biggestInt)
-    of 8: awi(nkIntLit, rd(int64, x).biggestInt)
+    of 1: awi(nkIntLit, rd(uint8, x).BiggestInt)
+    of 2: awi(nkIntLit, rd(uint16, x).BiggestInt)
+    of 4: awi(nkIntLit, rd(int32, x).BiggestInt)
+    of 8: awi(nkIntLit, rd(int64, x).BiggestInt)
     else:
-      GlobalError(n.info, "cannot map value from FFI (tyEnum, tySet)")
+      globalError(n.info, "cannot map value from FFI (tyEnum, tySet)")
   of tyFloat: awf(nkFloatLit, rd(float, x))
   of tyFloat32: awf(nkFloat32Lit, rd(float32, x))
   of tyFloat64: awf(nkFloat64Lit, rd(float64, x))
@@ -374,7 +374,7 @@ proc unpack(x: pointer, typ: PType, n: PNode): PNode =
       n.sons[0] = unpack(p, typ.sons[0], n.sons[0])
       result = n
     else:
-      GlobalError(n.info, "cannot map value from FFI " & typeToString(typ))
+      globalError(n.info, "cannot map value from FFI " & typeToString(typ))
   of tyObject, tyTuple:
     result = unpackObject(x, typ, n)
   of tyArray, tyArrayConstr:
@@ -391,7 +391,7 @@ proc unpack(x: pointer, typ: PType, n: PNode): PNode =
     result = unpack(x, typ.sons[0], n)
   else:
     # XXX what to do with 'array' here?
-    GlobalError(n.info, "cannot map value from FFI " & typeToString(typ))
+    globalError(n.info, "cannot map value from FFI " & typeToString(typ))
 
 proc fficast*(x: PNode, destTyp: PType): PNode =
   if x.kind == nkPtrLit and x.typ.kind in {tyPtr, tyRef, tyVar, tyPointer, 
@@ -414,7 +414,7 @@ proc fficast*(x: PNode, destTyp: PType): PNode =
     dealloc a
 
 proc callForeignFunction*(call: PNode): PNode =
-  InternalAssert call.sons[0].kind == nkPtrLit
+  internalAssert call.sons[0].kind == nkPtrLit
   
   var cif: TCif
   var sig: TParamList
@@ -422,12 +422,12 @@ proc callForeignFunction*(call: PNode): PNode =
   for i in 1..call.len-1:
     sig[i-1] = mapType(call.sons[i].typ)
     if sig[i-1].isNil:
-      GlobalError(call.info, "cannot map FFI type")
+      globalError(call.info, "cannot map FFI type")
   
   let typ = call.sons[0].typ
   if prep_cif(cif, mapCallConv(typ.callConv, call.info), cuint(call.len-1),
               mapType(typ.sons[0]), sig) != OK:
-    GlobalError(call.info, "error in FFI call")
+    globalError(call.info, "error in FFI call")
   
   var args: TArgList
   let fn = cast[pointer](call.sons[0].intVal)
diff --git a/compiler/lambdalifting.nim b/compiler/lambdalifting.nim
index 00fa04556..ebb4aeac4 100644
--- a/compiler/lambdalifting.nim
+++ b/compiler/lambdalifting.nim
@@ -637,6 +637,22 @@ proc outerProcSons(o: POuterContext, n: PNode) =
     let x = transformOuterProc(o, n.sons[i])
     if x != nil: n.sons[i] = x
 
+proc liftIterSym*(n: PNode): PNode =
+  # transforms  (iter)  to  (let env = newClosure[iter](); (iter, env)) 
+  let iter = n.sym
+  assert iter.kind == skIterator
+
+  result = newNodeIT(nkStmtListExpr, n.info, n.typ)
+  
+  var env = copySym(getHiddenParam(iter))
+  env.kind = skLet
+  var v = newNodeI(nkVarSection, n.info)
+  addVar(v, newSymNode(env))
+  result.add(v)
+  # add 'new' statement:
+  result.add(newCall(getSysSym"internalNew", env))
+  result.add makeClosure(iter, env, n.info)
+
 proc transformOuterProc(o: POuterContext, n: PNode): PNode =
   if n == nil: return nil
   case n.kind
@@ -649,17 +665,22 @@ proc transformOuterProc(o: POuterContext, n: PNode): PNode =
       return indirectAccess(newSymNode(o.closureParam), local, n.info)
 
     var closure = PEnv(idTableGet(o.lambdasToEnv, local))
-    if closure != nil:
-      # we need to replace the lambda with '(lambda, env)':
-      if local.kind == skIterator and local.typ.callConv == ccClosure:
-        # consider: [i1, i2, i1]  Since we merged the iterator's closure
-        # with the captured owning variables, we need to generate the
-        # closure generation code again:
-        #if local == o.fn: message(n.info, errRecursiveDependencyX, local.name.s)
-        # XXX why doesn't this work?
+
+    if local.kind == skIterator and local.typ.callConv == ccClosure:
+      # consider: [i1, i2, i1]  Since we merged the iterator's closure
+      # with the captured owning variables, we need to generate the
+      # closure generation code again:
+      if local == o.fn: message(n.info, errRecursiveDependencyX, local.name.s)
+      # XXX why doesn't this work?
+      if closure.isNil:
+        return liftIterSym(n)
+      else:
         let createdVar = generateIterClosureCreation(o, closure,
                                                      closure.attachedNode)
         return makeClosure(local, createdVar, n.info)
+
+    if closure != nil:
+      # we need to replace the lambda with '(lambda, env)':
       
       let a = closure.createdVar
       if a != nil:
@@ -773,22 +794,6 @@ proc liftLambdasForTopLevel*(module: PSym, body: PNode): PNode =
 
 # ------------------- iterator transformation --------------------------------
 
-proc liftIterSym*(n: PNode): PNode =
-  # transforms  (iter)  to  (let env = newClosure[iter](); (iter, env)) 
-  let iter = n.sym
-  assert iter.kind == skIterator
-
-  result = newNodeIT(nkStmtListExpr, n.info, n.typ)
-  
-  var env = copySym(getHiddenParam(iter))
-  env.kind = skLet
-  var v = newNodeI(nkVarSection, n.info)
-  addVar(v, newSymNode(env))
-  result.add(v)
-  # add 'new' statement:
-  result.add(newCall(getSysSym"internalNew", env))
-  result.add makeClosure(iter, env, n.info)
-
 proc liftForLoop*(body: PNode): PNode =
   # problem ahead: the iterator could be invoked indirectly, but then
   # we don't know what environment to create here: 
diff --git a/compiler/lookups.nim b/compiler/lookups.nim
index 6dfd25968..c31eb3121 100644
--- a/compiler/lookups.nim
+++ b/compiler/lookups.nim
@@ -339,4 +339,16 @@ proc nextOverloadIter*(o: var TOverloadIter, c: PContext, n: PNode): PSym =
                                    n.sons[0].sym.name, o.inSymChoice)
   
   if result != nil and result.kind == skStub: loadStub(result)
-  
+
+when false:
+  proc qualifiedLookUpPreferImmediate*(c: PContext, n: PNode,
+                                       flags = {checkUndeclared}): PSym =
+    var o: TOverloadIter
+    result = initOverloadIter(o, c, n)
+    var a = result
+    while a != nil:
+      if sfImmediate in a.flags: return a
+      a = nextOverloadIter(o, c, n)
+    if result == nil and checkUndeclared in flags: 
+      localError(n.info, errUndeclaredIdentifier, n.considerAcc.s)
+      result = errorSym(c, n)
diff --git a/compiler/main.nim b/compiler/main.nim
index cdea7b5ca..f6d11d960 100644
--- a/compiler/main.nim
+++ b/compiler/main.nim
@@ -135,7 +135,7 @@ proc interactivePasses =
   #setTarget(osNimrodVM, cpuNimrodVM)
   initDefines()
   defineSymbol("nimrodvm")
-  when hasFFI: DefineSymbol("nimffi")
+  when hasFFI: defineSymbol("nimffi")
   registerPass(verbosePass)
   registerPass(semPass)
   registerPass(evalPass)
@@ -324,7 +324,7 @@ proc mainCommand* =
     wantMainModule()
     when hasTinyCBackend:
       extccomp.setCC("tcc")
-      CommandCompileToC()
+      commandCompileToC()
     else:
       rawMessage(errInvalidCommandX, command)
   of "js", "compiletojs":
@@ -450,7 +450,8 @@ proc mainCommand* =
     echo "  tries : ", gCacheTries
     echo "  misses: ", gCacheMisses
     echo "  int tries: ", gCacheIntTries
-    echo "  efficiency: ", formatFloat(1-(gCacheMisses.float/gCacheTries.float), ffDecimal, 3)
+    echo "  efficiency: ", formatFloat(1-(gCacheMisses.float/gCacheTries.float),
+                                       ffDecimal, 3)
 
   when SimiluateCaasMemReset:
     resetMemory()
diff --git a/compiler/parser.nim b/compiler/parser.nim
index 3765557b9..ff3324b47 100644
--- a/compiler/parser.nim
+++ b/compiler/parser.nim
@@ -35,6 +35,7 @@ type
     lex*: TLexer              # the lexer that is used for parsing
     tok*: TToken              # the current token
     inPragma: int
+    inSemiStmtList: int
 
 proc parseAll*(p: var TParser): PNode
 proc openParser*(p: var TParser, filename: string, inputstream: PLLStream)
@@ -455,11 +456,13 @@ proc complexOrSimpleStmt(p: var TParser): PNode
 proc simpleExpr(p: var TParser, mode = pmNormal): PNode
 
 proc semiStmtList(p: var TParser, result: PNode) =
+  inc p.inSemiStmtList
   result.add(complexOrSimpleStmt(p))
   while p.tok.tokType == tkSemiColon:
     getTok(p)
     optInd(p, result)
     result.add(complexOrSimpleStmt(p))
+  dec p.inSemiStmtList
   result.kind = nkStmtListExpr
 
 proc parsePar(p: var TParser): PNode =
@@ -642,8 +645,7 @@ proc primarySuffix(p: var TParser, r: PNode): PNode =
   #|               | '.' optInd ('type' | 'addr' | symbol) generalizedLit?
   #|               | '[' optInd indexExprList optPar ']'
   #|               | '{' optInd indexExprList optPar '}'
-  #|               | &( '`'|IDENT|literal|'cast') expr ^+ ',' # command syntax
-  #|                      (doBlock | macroColon)?
+  #|               | &( '`'|IDENT|literal|'cast') expr # command syntax
   result = r
   while p.tok.indent < 0:
     case p.tok.tokType
@@ -672,16 +674,18 @@ proc primarySuffix(p: var TParser, r: PNode): PNode =
         let a = result
         result = newNodeP(nkCommand, p)
         addSon(result, a)
-        while p.tok.tokType != tkEof:
-          let a = parseExpr(p)
-          addSon(result, a)
-          if p.tok.tokType != tkComma: break
-          getTok(p)
-          optInd(p, a)
-        if p.tok.tokType == tkDo:
-          parseDoBlocks(p, result)
-        else:
-          result = parseMacroColon(p, result)
+        addSon result, parseExpr(p)
+        when false:
+          while p.tok.tokType != tkEof:
+            let a = parseExpr(p)
+            addSon(result, a)
+            if p.tok.tokType != tkComma: break
+            getTok(p)
+            optInd(p, a)
+          if p.tok.tokType == tkDo:
+            parseDoBlocks(p, result)
+          else:
+            result = parseMacroColon(p, result)
       break
     else:
       break
@@ -1103,7 +1107,9 @@ proc parseExprStmt(p: var TParser): PNode =
   #|              doBlocks
   #|               / macroColon
   #|            ))?
+  inc p.inPragma
   var a = simpleExpr(p)
+  dec p.inPragma
   if p.tok.tokType == tkEquals: 
     getTok(p)
     optInd(p, result)
@@ -1878,14 +1884,18 @@ proc parseStmt(p: var TParser): PNode =
       parMessage(p, errComplexStmtRequiresInd)
       result = ast.emptyNode
     else:
-      result = newNodeP(nkStmtList, p)
-      while true:
-        if p.tok.indent >= 0: parMessage(p, errInvalidIndentation)     
-        let a = simpleStmt(p)
-        if a.kind == nkEmpty: parMessage(p, errExprExpected, p.tok)
-        result.add(a)
-        if p.tok.tokType != tkSemiColon: break
-        getTok(p)
+      if p.inSemiStmtList > 0:
+        result = simpleStmt(p)
+        if result.kind == nkEmpty: parMessage(p, errExprExpected, p.tok)
+      else:
+        result = newNodeP(nkStmtList, p)
+        while true:
+          if p.tok.indent >= 0: parMessage(p, errInvalidIndentation)     
+          let a = simpleStmt(p)
+          if a.kind == nkEmpty: parMessage(p, errExprExpected, p.tok)
+          result.add(a)
+          if p.tok.tokType != tkSemiColon: break
+          getTok(p)
   
 proc parseAll(p: var TParser): PNode = 
   result = newNodeP(nkStmtList, p)
diff --git a/compiler/sem.nim b/compiler/sem.nim
index e89e32f4e..00ac79716 100644
--- a/compiler/sem.nim
+++ b/compiler/sem.nim
@@ -83,7 +83,9 @@ proc commonType*(x, y: PType): PType =
   elif a.kind == tyTypeDesc:
     # turn any concrete typedesc into the abstract typedesc type
     if a.sons == nil: result = a
-    else: result = newType(tyTypeDesc, a.owner)
+    else:
+      result = newType(tyTypeDesc, a.owner)
+      rawAddSon(result, newType(tyNone, a.owner))
   elif b.kind in {tyArray, tyArrayConstr, tySet, tySequence} and 
       a.kind == b.kind:
     # check for seq[empty] vs. seq[int]
diff --git a/compiler/semdata.nim b/compiler/semdata.nim
index 980abb865..c9d95e1bf 100644
--- a/compiler/semdata.nim
+++ b/compiler/semdata.nim
@@ -42,7 +42,7 @@ type
 
   TExprFlag* = enum 
     efLValue, efWantIterator, efInTypeof, efWantStmt, efDetermineType,
-    efAllowDestructor
+    efAllowDestructor, efWantValue
   TExprFlags* = set[TExprFlag]
 
   PContext* = ref TContext
@@ -211,6 +211,7 @@ proc makeTypeDesc*(c: PContext, typ: PType): PType =
 
 proc makeTypeSymNode*(c: PContext, typ: PType, info: TLineInfo): PNode =
   let typedesc = makeTypeDesc(c, typ)
+  rawAddSon(typedesc, newTypeS(tyNone, c))
   let sym = newSym(skType, idAnon, getCurrOwner(), info).linkTo(typedesc)
   return newSymNode(sym, info)
 
diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim
index 84303b6cd..a8a16672d 100644
--- a/compiler/semexprs.nim
+++ b/compiler/semexprs.nim
@@ -35,7 +35,7 @@ proc semOperand(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
     result.typ = errorType(c)
 
 proc semExprWithType(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
-  result = semExpr(c, n, flags)
+  result = semExpr(c, n, flags+{efWantValue})
   if result.isNil or result.kind == nkEmpty: 
     # do not produce another redundant error message:
     #raiseRecoverableError("")
@@ -1706,8 +1706,8 @@ proc semObjConstr(c: PContext, n: PNode, flags: TExprFlags): PNode =
   result = n
   result.typ = t
   result.kind = nkObjConstr
-  t = skipTypes(t, abstractInst)
-  if t.kind == tyRef: t = skipTypes(t.sons[0], abstractInst)
+  t = skipTypes(t, {tyGenericInst})
+  if t.kind == tyRef: t = skipTypes(t.sons[0], {tyGenericInst})
   if t.kind != tyObject:
     localError(n.info, errGenerated, "object constructor needs an object type")
     return
@@ -1819,6 +1819,10 @@ proc semExport(c: PContext, n: PNode): PNode =
   c.module.ast.add x
   result = n
 
+proc setGenericParams(c: PContext, n: PNode) =
+  for i in 1 .. <n.len:
+    n[i].typ = semTypeNode(c, n[i], nil)
+
 proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode = 
   result = n
   if gCmd == cmdIdeTools: suggestExpr(c, n)
@@ -1924,10 +1928,12 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
       else:
         #liMessage(n.info, warnUser, renderTree(n));
         result = semIndirectOp(c, n, flags)
-    elif isSymChoice(n.sons[0]) or n[0].kind == nkBracketExpr and 
-        isSymChoice(n[0][0]):
+    elif n[0].kind == nkBracketExpr and isSymChoice(n[0][0]):
+      # indirectOp can deal with explicit instantiations; the fixes
+      # the 'newSeq[T](x)' bug
+      setGenericParams(c, n.sons[0])
       result = semDirectOp(c, n, flags)
-    elif nfDelegate in n.flags:
+    elif isSymChoice(n.sons[0]) or nfDelegate in n.flags:
       result = semDirectOp(c, n, flags)
     else:
       result = semIndirectOp(c, n, flags)
@@ -1993,7 +1999,7 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
     result = semStaticExpr(c, n)
   of nkAsgn: result = semAsgn(c, n)
   of nkBlockStmt, nkBlockExpr: result = semBlock(c, n)
-  of nkStmtList, nkStmtListExpr: result = semStmtList(c, n)
+  of nkStmtList, nkStmtListExpr: result = semStmtList(c, n, flags)
   of nkRaiseStmt: result = semRaise(c, n)
   of nkVarSection: result = semVarOrLet(c, n, skVar)
   of nkLetSection: result = semVarOrLet(c, n, skLet)
diff --git a/compiler/semgnrc.nim b/compiler/semgnrc.nim
index 89a167b96..b21d851c9 100644
--- a/compiler/semgnrc.nim
+++ b/compiler/semgnrc.nim
@@ -1,7 +1,7 @@
 #
 #
 #           The Nimrod Compiler
-#        (c) Copyright 2012 Andreas Rumpf
+#        (c) Copyright 2014 Andreas Rumpf
 #
 #    See the file "copying.txt", included in this
 #    distribution, for details about the copyright.
@@ -215,8 +215,7 @@ proc semGenericStmt(c: PContext, n: PNode,
       if (a.kind != nkIdentDefs) and (a.kind != nkVarTuple): illFormedAst(a)
       checkMinSonsLen(a, 3)
       var L = sonsLen(a)
-      a.sons[L-2] = semGenericStmt(c, a.sons[L-2], flags+{withinTypeDesc}, 
-                                   ctx)
+      a.sons[L-2] = semGenericStmt(c, a.sons[L-2], flags+{withinTypeDesc}, ctx)
       a.sons[L-1] = semGenericStmt(c, a.sons[L-1], flags, ctx)
       for j in countup(0, L-3):
         addPrelimDecl(c, newSymS(skUnknown, getIdentNode(a.sons[j]), c))
@@ -226,8 +225,7 @@ proc semGenericStmt(c: PContext, n: PNode,
       if (a.kind != nkIdentDefs): illFormedAst(a)
       checkMinSonsLen(a, 3)
       var L = sonsLen(a)
-      a.sons[L-2] = semGenericStmt(c, a.sons[L-2], flags+{withinTypeDesc}, 
-                                   ctx) 
+      a.sons[L-2] = semGenericStmt(c, a.sons[L-2], flags+{withinTypeDesc}, ctx) 
       # do not perform symbol lookup for default expressions 
       for j in countup(0, L-3): 
         addPrelimDecl(c, newSymS(skUnknown, getIdentNode(a.sons[j]), c))
@@ -281,8 +279,7 @@ proc semGenericStmt(c: PContext, n: PNode,
       if (a.kind != nkIdentDefs): illFormedAst(a)
       checkMinSonsLen(a, 3)
       var L = sonsLen(a)
-      a.sons[L-2] = semGenericStmt(c, a.sons[L-2], flags+{withinTypeDesc}, 
-                                   ctx)
+      a.sons[L-2] = semGenericStmt(c, a.sons[L-2], flags+{withinTypeDesc}, ctx)
       a.sons[L-1] = semGenericStmt(c, a.sons[L-1], flags, ctx)
       for j in countup(0, L-3): 
         addPrelimDecl(c, newSymS(skUnknown, getIdentNode(a.sons[j]), c))
diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim
index caa719c7e..0871b7fb7 100644
--- a/compiler/semstmts.nim
+++ b/compiler/semstmts.nim
@@ -740,7 +740,7 @@ proc typeSectionRightSidePass(c: PContext, n: PNode) =
       # we fill it out later. For magic generics like 'seq', it won't be filled
       # so we use tyEmpty instead of nil to not crash for strange conversions
       # like: mydata.seq
-      rawAddSon(s.typ, newTypeS(tyEmpty, c))
+      rawAddSon(s.typ, newTypeS(tyNone, c))
       s.ast = a
       inc c.inGenericContext
       var body = semTypeNode(c, a.sons[2], nil)
@@ -748,7 +748,7 @@ proc typeSectionRightSidePass(c: PContext, n: PNode) =
       if body != nil:
         body.sym = s
         body.size = -1 # could not be computed properly
-      s.typ.sons[sonsLen(s.typ) - 1] = body
+        s.typ.sons[sonsLen(s.typ) - 1] = body
       popOwner()
       closeScope(c)
     elif a.sons[2].kind != nkEmpty: 
@@ -972,6 +972,9 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
   else:
     s = n[namePos].sym
     typeIsDetermined = s.typ == nil
+    s.ast = n
+    s.scope = c.currentScope
+
     # if typeIsDetermined: assert phase == stepCompileBody
     # else: assert phase == stepDetermineType
   # before compiling the proc body, set as current the scope
@@ -1206,7 +1209,7 @@ proc usesResult(n: PNode): bool =
       for c in n:
         if usesResult(c): return true
 
-proc semStmtList(c: PContext, n: PNode): PNode =
+proc semStmtList(c: PContext, n: PNode, flags: TExprFlags): PNode =
   # these must be last statements in a block:
   const
     LastBlockStmts = {nkRaiseStmt, nkReturnStmt, nkBreakStmt, nkContinueStmt}
@@ -1247,12 +1250,14 @@ proc semStmtList(c: PContext, n: PNode): PNode =
       if n.sons[i].typ == enforceVoidContext or usesResult(n.sons[i]):
         voidContext = true
         n.typ = enforceVoidContext
-      if i != last or voidContext or c.inTypeClass > 0:
+      if i == last and efWantValue in flags:
+        n.typ = n.sons[i].typ
+        if not isEmptyType(n.typ): n.kind = nkStmtListExpr
+      elif i != last or voidContext or c.inTypeClass > 0:
         discardCheck(c, n.sons[i])
       else:
         n.typ = n.sons[i].typ
-        if not isEmptyType(n.typ):
-          n.kind = nkStmtListExpr
+        if not isEmptyType(n.typ): n.kind = nkStmtListExpr
       case n.sons[i].kind
       of nkVarSection, nkLetSection:
         let (outer, inner) = insertDestructors(c, n.sons[i])
diff --git a/compiler/semthreads.nim b/compiler/semthreads.nim
index f7322db80..d3426ca3e 100644
--- a/compiler/semthreads.nim
+++ b/compiler/semthreads.nim
@@ -358,7 +358,7 @@ proc analyse(c: PProcCtx, n: PNode): TThreadOwner =
   of nkConstSection: result = analyseConstSection(c, n)
   of nkTypeSection, nkCommentStmt: result = toVoid
   of nkIfStmt, nkWhileStmt, nkTryStmt, nkCaseStmt, nkStmtList, nkBlockStmt, 
-     nkElifBranch, nkElse, nkExceptBranch, nkOfBranch:
+     nkElifBranch, nkElse, nkExceptBranch, nkOfBranch, nkFinally:
     for i in 0 .. <n.len: discard analyse(c, n[i])
     result = toVoid
   of nkBreakStmt, nkContinueStmt: result = toVoid
diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim
index 408b1b62e..44e414e9c 100644
--- a/compiler/semtypes.nim
+++ b/compiler/semtypes.nim
@@ -681,12 +681,12 @@ proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode,
   of tySequence, tySet, tyArray, tyOpenArray,
      tyVar, tyPtr, tyRef, tyProc:
     # XXX: this is a bit strange, but proc(s: seq)
-    # produces tySequence(tyGenericParam, null).
+    # produces tySequence(tyGenericParam, tyNone).
     # This also seems to be true when creating aliases
     # like: type myseq = distinct seq.
     # Maybe there is another better place to associate
     # the seq type class with the seq identifier.
-    if paramType.kind == tySequence and paramType.lastSon == nil:
+    if paramType.kind == tySequence and paramType.lastSon.kind == tyNone:
       let typ = c.newTypeWithSons(tyBuiltInTypeClass,
                                   @[newTypeS(paramType.kind, c)])
       result = addImplicitGeneric(typ)
@@ -885,8 +885,12 @@ proc semGeneric(c: PContext, n: PNode, s: PSym, prev: PType): PType =
     for i in countup(1, sonsLen(n)-1):
       var elem = semGenericParamInInvokation(c, n.sons[i])
       addToResult(elem)
+  elif s.typ.kind != tyGenericBody:
+    #we likely got code of the form TypeA[TypeB] where TypeA is
+    #not generic.
+    localError(n.info, errNoGenericParamsAllowedForX, s.name.s)
+    return newOrPrevType(tyError, prev, c)
   else:
-    internalAssert s.typ.kind == tyGenericBody
 
     var m = newCandidate(c, s, n)
     matches(c, n, copyTree(n), m)
@@ -1133,15 +1137,26 @@ proc processMagicType(c: PContext, m: PSym) =
   of mNil: setMagicType(m, tyNil, ptrSize)
   of mExpr: setMagicType(m, tyExpr, 0)
   of mStmt: setMagicType(m, tyStmt, 0)
-  of mTypeDesc: setMagicType(m, tyTypeDesc, 0)
+  of mTypeDesc: 
+    setMagicType(m, tyTypeDesc, 0)
+    rawAddSon(m.typ, newTypeS(tyNone, c))
   of mVoidType: setMagicType(m, tyEmpty, 0)
-  of mArray: setMagicType(m, tyArray, 0)
-  of mOpenArray: setMagicType(m, tyOpenArray, 0)
-  of mVarargs: setMagicType(m, tyVarargs, 0)
-  of mRange: setMagicType(m, tyRange, 0)
-  of mSet: setMagicType(m, tySet, 0) 
-  of mSeq: setMagicType(m, tySequence, 0)
-  of mOrdinal: setMagicType(m, tyOrdinal, 0)
+  of mArray:
+    setMagicType(m, tyArray, 0)
+  of mOpenArray:
+    setMagicType(m, tyOpenArray, 0)
+  of mVarargs:
+    setMagicType(m, tyVarargs, 0)
+  of mRange:
+    setMagicType(m, tyRange, 0)
+    rawAddSon(m.typ, newTypeS(tyNone, c))
+  of mSet:
+    setMagicType(m, tySet, 0) 
+  of mSeq: 
+    setMagicType(m, tySequence, 0)
+  of mOrdinal:
+    setMagicType(m, tyOrdinal, 0)
+    rawAddSon(m.typ, newTypeS(tyNone, c))
   of mPNimrodNode: discard
   else: localError(m.info, errTypeExpected)
   
@@ -1165,8 +1180,8 @@ proc semGenericParamList(c: PContext, n: PNode, father: PType = nil): PNode =
       typ = semTypeNode(c, constraint, nil)
       if typ.kind != tyStatic or typ.len == 0:
         if typ.kind == tyTypeDesc:
-          if typ.len == 0:
-            typ = newTypeS(tyTypeDesc, c)
+          if typ.sons[0].kind == tyNone:
+            typ = newTypeWithSons(c, tyTypeDesc, @[newTypeS(tyNone, c)])
         else:
           typ = semGenericConstraints(c, typ)
     
diff --git a/compiler/semtypinst.nim b/compiler/semtypinst.nim
index 1158335a8..a07d91241 100644
--- a/compiler/semtypinst.nim
+++ b/compiler/semtypinst.nim
@@ -358,7 +358,7 @@ proc replaceTypeVarsTAux(cl: var TReplTypeVars, t: PType): PType =
     if lookup != nil:
       result = lookup
       if tfUnresolved in t.flags: result = result.base
-    elif t.sonsLen > 0:
+    elif t.sons[0].kind != tyNone:
       result = makeTypeDesc(cl.c, replaceTypeVarsT(cl, t.sons[0]))
  
   of tyUserTypeClass:
diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim
index d269e9e69..335ceafeb 100644
--- a/compiler/sigmatch.nim
+++ b/compiler/sigmatch.nim
@@ -105,6 +105,7 @@ proc initCandidate*(ctx: PContext, c: var TCandidate, callee: PSym,
       var bound = binding[i].typ
       if bound != nil and formalTypeParam.kind != tyTypeDesc:
         bound = bound.skipTypes({tyTypeDesc})
+      assert bound != nil
       put(c.bindings, formalTypeParam, bound)
 
 proc newCandidate*(ctx: PContext, callee: PSym,
@@ -562,10 +563,11 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
       #if result < isGeneric: result = isNone
       if result notin {isNone, isGeneric}:
         result = typeRangeRel(f, a)
-    elif skipTypes(f, {tyRange}).kind == a.kind:
-      result = isIntConv
-    elif isConvertibleToRange(skipTypes(f, {tyRange}), a):
-      result = isConvertible  # a convertible to f
+    else:
+      if skipTypes(f, {tyRange}).kind == a.kind:
+        result = isIntConv
+      elif isConvertibleToRange(skipTypes(f, {tyRange}), a):
+        result = isConvertible  # a convertible to f
   of tyInt:      result = handleRange(f, a, tyInt8, tyInt32)
   of tyInt8:     result = handleRange(f, a, tyInt8, tyInt8)
   of tyInt16:    result = handleRange(f, a, tyInt8, tyInt16)
@@ -636,7 +638,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
   of tyOrdinal:
     if isOrdinalType(a):
       var x = if a.kind == tyOrdinal: a.sons[0] else: a
-      if f.sonsLen == 0:
+      if f.sons[0].kind == tyNone:
         result = isGeneric
       else:
         result = typeRel(c, f.sons[0], x)
@@ -736,7 +738,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
   of tyGenericInst:
     let roota = a.skipGenericAlias
     let rootf = f.skipGenericAlias
-    if a.kind == tyGenericInst and roota.base == rootf.base :
+    if a.kind == tyGenericInst and roota.base == rootf.base:
       for i in 1 .. rootf.sonsLen-2:
         let ff = rootf.sons[i]
         let aa = roota.sons[i]
@@ -845,7 +847,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
         # by a tyTypeDesc params. Unfortunately, this requires more substantial
         # changes in semtypinst and elsewhere.
         if a.kind == tyTypeDesc:
-          if f.sons == nil or f.sons.len == 0:
+          if f.sonsLen == 0:
             result = isGeneric
           else:
             internalAssert a.sons != nil and a.sons.len > 0
@@ -854,7 +856,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
         else:
           result = isNone
       else:
-        if f.sonsLen > 0:
+        if f.sonsLen > 0 and f.sons[0].kind != tyNone:
           result = typeRel(c, f.lastSon, a)
         else:
           result = isGeneric
@@ -883,7 +885,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
     var prev = PType(idTableGet(c.bindings, f))
     if prev == nil:
       if a.kind == tyTypeDesc:
-        if f.sonsLen == 0:
+        if f.sons[0].kind == tyNone:
           result = isGeneric
         else:
           result = typeRel(c, f.sons[0], a.sons[0])
diff --git a/compiler/types.nim b/compiler/types.nim
index 4a53a84c9..db75cd3c0 100644
--- a/compiler/types.nim
+++ b/compiler/types.nim
@@ -47,7 +47,8 @@ proc equalParams*(a, b: PNode): TParamsEquality
   # returns whether the parameter lists of the procs a, b are exactly the same
 proc isOrdinalType*(t: PType): bool
 proc enumHasHoles*(t: PType): bool
-const 
+
+const
   abstractPtrs* = {tyVar, tyPtr, tyRef, tyGenericInst, tyDistinct, tyOrdinal,
                    tyConst, tyMutable, tyTypeDesc}
   abstractVar* = {tyVar, tyGenericInst, tyDistinct, tyOrdinal,
@@ -451,7 +452,7 @@ proc typeToString(typ: PType, prefer: TPreferedDesc = preferName): string =
       of tyProc: "proc"
       of tyObject: "object"
       of tyTuple: "tuple"
-      else: (internalAssert false; "")
+      else: (internalAssert(false); "")
   of tyUserTypeClassInst:
     let body = t.base
     result = body.sym.name.s & "["
@@ -1257,7 +1258,7 @@ proc containsGenericTypeIter(t: PType, closure: PObject): bool =
     return true
 
   if t.kind == tyTypeDesc:
-    if t.sonsLen == 0: return true
+    if t.sons[0].kind == tyNone: return true
     if containsGenericTypeIter(t.base, closure): return true
     return false
   
diff --git a/compiler/vm.nim b/compiler/vm.nim
index deca288b5..10ac7aaaf 100644
--- a/compiler/vm.nim
+++ b/compiler/vm.nim
@@ -14,7 +14,7 @@ import ast except getstr
 
 import
   strutils, astalgo, msgs, vmdef, vmgen, nimsets, types, passes, unsigned,
-  parser, vmdeps, idents, trees, renderer, options
+  parser, vmdeps, idents, trees, renderer, options, transf
 
 from semfold import leValueConv, ordinalValToString
 from evaltempl import evalTemplate
@@ -337,7 +337,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): PNode =
       asgnRef(c.globals.sons[instr.regBx-wordExcess-1], regs[ra])
     of opcWrGlobal:
       asgnComplex(c.globals.sons[instr.regBx-wordExcess-1], regs[ra])
-    of opcLdArr:
+    of opcLdArr, opcLdArrRef:
       # a = b[c]
       let rb = instr.regB
       let rc = instr.regC
@@ -348,7 +348,11 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): PNode =
       assert regs[rb].kind != nkMetaNode
       let src = regs[rb]
       if src.kind notin {nkEmpty..nkNilLit} and idx <% src.len:
-        asgnComplex(regs[ra], src.sons[idx])
+        if instr.opcode == opcLdArrRef and false:
+          # XXX activate when seqs are fixed
+          asgnRef(regs[ra], src.sons[idx])
+        else:
+          asgnComplex(regs[ra], src.sons[idx])
       else:
         stackTrace(c, tos, pc, errIndexOutOfBounds)
     of opcLdStrIdx:
@@ -379,9 +383,15 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): PNode =
       # a = b.c
       let rb = instr.regB
       let rc = instr.regC
-      # XXX this creates a wrong alias
       #Message(c.debug[pc], warnUser, $regs[rb].safeLen & " " & $rc)
       asgnComplex(regs[ra], regs[rb].sons[rc])
+    of opcLdObjRef:
+      # a = b.c
+      let rb = instr.regB
+      let rc = instr.regC
+      # XXX activate when seqs are fixed
+      asgnComplex(regs[ra], regs[rb].sons[rc])
+      #asgnRef(regs[ra], regs[rb].sons[rc])
     of opcWrObj:
       # a.b = c
       let rb = instr.regB
@@ -1037,7 +1047,9 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): PNode =
       # XXX only supports 'name' for now; we can use regC to encode the
       # type trait operation
       decodeB(nkStrLit)
-      let typ = regs[rb].sym.typ.skipTypes({tyTypeDesc})
+      var typ = regs[rb].typ
+      internalAssert typ != nil
+      while typ.kind == tyTypeDesc and typ.len > 0: typ = typ.sons[0]
       regs[ra].strVal = typ.typeToString(preferExported)
     of opcGlobalOnce:
       let rb = instr.regBx
@@ -1066,6 +1078,7 @@ proc execute(c: PCtx, start: int): PNode =
   result = rawExecute(c, start, tos)
 
 proc evalStmt*(c: PCtx, n: PNode) =
+  let n = transformExpr(c.module, n)
   let start = genStmt(c, n)
   # execute new instructions; this redundant opcEof check saves us lots
   # of allocations in 'execute':
@@ -1073,6 +1086,7 @@ proc evalStmt*(c: PCtx, n: PNode) =
     discard execute(c, start)
 
 proc evalExpr*(c: PCtx, n: PNode): PNode =
+  let n = transformExpr(c.module, n)
   let start = genExpr(c, n)
   assert c.code[start].opcode != opcEof
   result = execute(c, start)
@@ -1115,6 +1129,7 @@ proc myProcess(c: PPassContext, n: PNode): PNode =
 const evalPass* = makePass(myOpen, nil, myProcess, myProcess)
 
 proc evalConstExprAux(module, prc: PSym, n: PNode, mode: TEvalMode): PNode =
+  let n = transformExpr(module, n)
   setupGlobalCtx(module)
   var c = globalCtx
   c.mode = mode
@@ -1168,7 +1183,7 @@ proc evalMacroCall*(module: PSym, n, nOrig: PNode, sym: PSym): PNode =
   # doesn't end up in the parameter:
   #InternalAssert tos.slots.len >= L
   # return value:
-  tos.slots[0] = newNodeIT(nkNilLit, n.info, sym.typ.sons[0])
+  tos.slots[0] = newNodeIT(nkEmpty, n.info, sym.typ.sons[0])
   # setup parameters:
   for i in 1 .. < min(tos.slots.len, L):
     tos.slots[i] = setupMacroParam(n.sons[i])
diff --git a/compiler/vmdef.nim b/compiler/vmdef.nim
index 480c7f31b..87159c813 100644
--- a/compiler/vmdef.nim
+++ b/compiler/vmdef.nim
@@ -34,9 +34,11 @@ type
     opcAsgnComplex,
 
     opcLdArr,  # a = b[c]
+    opcLdArrRef,
     opcWrArr,  # a[b] = c
     opcWrArrRef,
     opcLdObj,  # a = b.c
+    opcLdObjRef,
     opcWrObj,  # a.b = c
     opcWrObjRef,
     opcAddr,
diff --git a/compiler/vmgen.nim b/compiler/vmgen.nim
index a41e60e7d..d0e8dacf3 100644
--- a/compiler/vmgen.nim
+++ b/compiler/vmgen.nim
@@ -1,7 +1,7 @@
 #
 #
 #           The Nimrod Compiler
-#        (c) Copyright 2013 Andreas Rumpf
+#        (c) Copyright 2014 Andreas Rumpf
 #
 #    See the file "copying.txt", included in this
 #    distribution, for details about the copyright.
@@ -13,9 +13,18 @@ import
   unsigned, strutils, ast, astalgo, types, msgs, renderer, vmdef, 
   trees, intsets, rodread, magicsys, options
 
+from os import splitFile
+
 when hasFFI:
   import evalffi
 
+type
+  TGenFlag = enum gfNone, gfAddrOf
+  TGenFlags = set[TGenFlag]
+
+proc debugInfo(info: TLineInfo): string =
+  result = info.toFilename.splitFile.name & ":" & $info.line
+
 proc codeListing(c: PCtx, result: var string, start=0) =
   # first iteration: compute all necessary labels:
   var jumpTargets = initIntSet()
@@ -44,7 +53,7 @@ proc codeListing(c: PCtx, result: var string, start=0) =
     else:
       result.addf("\t$#\tr$#, $#", ($opc).substr(3), x.regA, x.regBx-wordExcess)
     result.add("\t#")
-    result.add(toFileLine(c.debug[i]))
+    result.add(debugInfo(c.debug[i]))
     result.add("\n")
     inc i
 
@@ -100,7 +109,7 @@ proc patch(c: PCtx, p: TPosition) =
                uint32(diff+wordExcess) shl 16'u32).TInstr
 
 proc getSlotKind(t: PType): TSlotKind =
-  case t.skipTypes(abstractRange).kind
+  case t.skipTypes(abstractRange-{tyTypeDesc}).kind
   of tyBool, tyChar, tyEnum, tyOrdinal, tyInt..tyInt64, tyUInt..tyUInt64:
     slotTempInt
   of tyString, tyCString:
@@ -190,20 +199,20 @@ template withBlock(labl: PSym; body: stmt) {.immediate, dirty.} =
   body
   popBlock(c, oldLen)
 
-proc gen(c: PCtx; n: PNode; dest: var TDest)
-proc gen(c: PCtx; n: PNode; dest: TRegister) =
+proc gen(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags = {})
+proc gen(c: PCtx; n: PNode; dest: TRegister; flags: TGenFlags = {}) =
   var d: TDest = dest
-  gen(c, n, d)
+  gen(c, n, d, flags)
   internalAssert d == dest
 
-proc gen(c: PCtx; n: PNode) =
+proc gen(c: PCtx; n: PNode; flags: TGenFlags = {}) =
   var tmp: TDest = -1
-  gen(c, n, tmp)
+  gen(c, n, tmp, flags)
   #if n.typ.isEmptyType: InternalAssert tmp < 0
 
-proc genx(c: PCtx; n: PNode): TRegister =
+proc genx(c: PCtx; n: PNode; flags: TGenFlags = {}): TRegister =
   var tmp: TDest = -1
-  gen(c, n, tmp)
+  gen(c, n, tmp, flags)
   internalAssert tmp >= 0
   result = TRegister(tmp)
 
@@ -400,7 +409,7 @@ proc genTry(c: PCtx; n: PNode; dest: var TDest) =
       let endExcept = c.xjmp(it, opcExcept, 0)
       for j in countup(0, blen - 2): 
         assert(it.sons[j].kind == nkType)
-        let typ = it.sons[j].typ.skipTypes(abstractPtrs)
+        let typ = it.sons[j].typ.skipTypes(abstractPtrs-{tyTypeDesc})
         c.gABx(it, opcExcept, 0, c.genType(typ))
       if blen == 1: 
         # general except section:
@@ -470,15 +479,16 @@ proc genNew(c: PCtx; n: PNode) =
   # we use the ref's base type here as the VM conflates 'ref object' 
   # and 'object' since internally we already have a pointer.
   c.gABx(n, opcNew, dest, 
-         c.genType(n.sons[1].typ.skipTypes(abstractVar).sons[0]))
+         c.genType(n.sons[1].typ.skipTypes(abstractVar-{tyTypeDesc}).sons[0]))
   c.genAsgnPatch(n.sons[1], dest)
   c.freeTemp(dest)
 
 proc genNewSeq(c: PCtx; n: PNode) =
   let dest = if needsAsgnPatch(n.sons[1]): c.getTemp(n.sons[1].typ)
              else: c.genx(n.sons[1])
-  c.gABx(n, opcNewSeq, dest, c.genType(n.sons[1].typ.skipTypes(abstractVar)))
   let tmp = c.genx(n.sons[2])
+  c.gABx(n, opcNewSeq, dest, c.genType(n.sons[1].typ.skipTypes(
+                                                  abstractVar-{tyTypeDesc})))
   c.gABx(n, opcNewSeq, tmp, 0)
   c.freeTemp(tmp)
   c.genAsgnPatch(n.sons[1], dest)
@@ -506,7 +516,7 @@ proc genBinaryABC(c: PCtx; n: PNode; dest: var TDest; opc: TOpcode) =
   c.freeTemp(tmp2)
 
 proc genSetType(c: PCtx; n: PNode; dest: TRegister) =
-  let t = skipTypes(n.typ, abstractInst)
+  let t = skipTypes(n.typ, abstractInst-{tyTypeDesc})
   if t.kind == tySet:
     c.gABx(n, opcSetType, dest, c.genType(t))
 
@@ -528,6 +538,14 @@ proc genBinaryStmt(c: PCtx; n: PNode; opc: TOpcode) =
   c.gABC(n, opc, dest, tmp, 0)
   c.freeTemp(tmp)
 
+proc genBinaryStmtVar(c: PCtx; n: PNode; opc: TOpcode) =
+  let
+    dest = c.genx(n.sons[1], {gfAddrOf})
+    tmp = c.genx(n.sons[2])
+  c.gABC(n, opc, dest, tmp, 0)
+  #c.genAsgnPatch(n.sons[1], dest)
+  c.freeTemp(tmp)
+
 proc genUnaryStmt(c: PCtx; n: PNode; opc: TOpcode) =
   let tmp = c.genx(n.sons[1])
   c.gABC(n, opc, tmp, 0, 0)
@@ -729,7 +747,7 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest) =
     var tmp = c.genx(n.sons[1])
     var idx = c.getTemp(getSysType(tyInt))
     var typ = n.sons[2].typ
-    if m == mOf: typ = typ.skipTypes(abstractPtrs)
+    if m == mOf: typ = typ.skipTypes(abstractPtrs-{tyTypeDesc})
     c.gABx(n, opcLdImmInt, idx, c.genType(typ))
     c.gABC(n, if m == mOf: opcOf else: opcIs, dest, tmp, idx)
     c.freeTemp(tmp)
@@ -739,7 +757,7 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest) =
   of mHigh:
     if dest < 0: dest = c.getTemp(n.typ)
     let tmp = c.genx(n.sons[1])
-    if n.sons[1].typ.skipTypes(abstractVar).kind == tyString:
+    if n.sons[1].typ.skipTypes(abstractVar-{tyTypeDesc}).kind == tyString:
       c.gABI(n, opcLenStr, dest, tmp, 1)
     else:
       c.gABI(n, opcLenSeq, dest, tmp, 1)
@@ -754,13 +772,13 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest) =
     c.freeTempRange(x, n.len-1)
   of mAppendStrCh:
     unused(n, dest)
-    genBinaryStmt(c, n, opcAddStrCh)
+    genBinaryStmtVar(c, n, opcAddStrCh)
   of mAppendStrStr: 
     unused(n, dest)
-    genBinaryStmt(c, n, opcAddStrStr)
+    genBinaryStmtVar(c, n, opcAddStrStr)
   of mAppendSeqElem:
     unused(n, dest)
-    genBinaryStmt(c, n, opcAddSeqElem)
+    genBinaryStmtVar(c, n, opcAddSeqElem)
   of mParseExprToAst:
     genUnaryABC(c, n, dest, opcParseExprToAst)
   of mParseStmtToAst:
@@ -874,7 +892,7 @@ const
     tyUInt, tyUInt8, tyUInt16, tyUInt32, tyUInt64}
 
 proc requiresCopy(n: PNode): bool =
-  if n.typ.skipTypes(abstractInst).kind in atomicTypes:
+  if n.typ.skipTypes(abstractInst-{tyTypeDesc}).kind in atomicTypes:
     result = false
   elif n.kind in ({nkCurly, nkBracket, nkPar, nkObjConstr}+nkCallKinds):
     result = false
@@ -882,7 +900,7 @@ proc requiresCopy(n: PNode): bool =
     result = true
 
 proc unneededIndirection(n: PNode): bool =
-  n.typ.skipTypes(abstractInst).kind == tyRef
+  n.typ.skipTypes(abstractInst-{tyTypeDesc}).kind == tyRef
 
 proc skipDeref(n: PNode): PNode =
   if n.kind in {nkDerefExpr, nkHiddenDeref} and unneededIndirection(n.sons[0]):
@@ -890,18 +908,20 @@ proc skipDeref(n: PNode): PNode =
   else:
     result = n
 
-proc genAddrDeref(c: PCtx; n: PNode; dest: var TDest; opc: TOpcode) = 
+proc genAddrDeref(c: PCtx; n: PNode; dest: var TDest; opc: TOpcode;
+                  flags: TGenFlags) = 
   # a nop for certain types
+  let flags = if opc == opcAddr: flags+{gfAddrOf} else: flags
   if unneededIndirection(n.sons[0]):
-    gen(c, n.sons[0], dest)
+    gen(c, n.sons[0], dest, flags)
   else:
-    let tmp = c.genx(n.sons[0])
+    let tmp = c.genx(n.sons[0], flags)
     if dest < 0: dest = c.getTemp(n.typ)
     gABC(c, n, opc, dest, tmp)
     c.freeTemp(tmp)
 
 proc whichAsgnOpc(n: PNode): TOpcode =
-  case n.typ.skipTypes(abstractRange).kind
+  case n.typ.skipTypes(abstractRange-{tyTypeDesc}).kind
   of tyBool, tyChar, tyEnum, tyOrdinal, tyInt..tyInt64, tyUInt..tyUInt64:
     opcAsgnInt
   of tyString, tyCString:
@@ -913,7 +933,7 @@ proc whichAsgnOpc(n: PNode): TOpcode =
   else:
     opcAsgnComplex
 
-proc isRef(t: PType): bool = t.skipTypes(abstractRange).kind == tyRef
+proc isRef(t: PType): bool = t.skipTypes(abstractRange-{tyTypeDesc}).kind == tyRef
 
 proc whichAsgnOpc(n: PNode; opc: TOpcode): TOpcode =
   if isRef(n.typ): succ(opc) else: opc
@@ -926,13 +946,22 @@ proc genAsgn(c: PCtx; dest: TDest; ri: PNode; requiresCopy: bool) =
 
 template isGlobal(s: PSym): bool = sfGlobal in s.flags and s.kind != skForVar
 
+proc setSlot(c: PCtx; v: PSym) =
+  # XXX generate type initialization here?
+  if v.position == 0:
+    v.position = c.prc.maxSlots
+    c.prc.slots[v.position] = (inUse: true,
+        kind: if v.kind == skLet: slotFixedLet else: slotFixedVar)
+    inc c.prc.maxSlots
+
 proc genAsgn(c: PCtx; le, ri: PNode; requiresCopy: bool) =
   case le.kind
   of nkBracketExpr:
     let dest = c.genx(le.sons[0])
     let idx = c.genx(le.sons[1])
     let tmp = c.genx(ri)
-    if le.sons[0].typ.skipTypes(abstractVarRange).kind in {tyString, tyCString}:
+    if le.sons[0].typ.skipTypes(abstractVarRange-{tyTypeDesc}).kind in {
+        tyString, tyCString}:
       c.gABC(le, opcWrStrIdx, dest, idx, tmp)
     else:
       c.gABC(le, whichAsgnOpc(le, opcWrArr), dest, idx, tmp)
@@ -952,8 +981,9 @@ proc genAsgn(c: PCtx; le, ri: PNode; requiresCopy: bool) =
         gen(c, ri, tmp)
         c.gABx(le, whichAsgnOpc(le, opcWrGlobal), tmp, s.position)
     else:
+      if s.kind == skForVar and c.mode == emRepl: c.setSlot s
       internalAssert s.position > 0 or (s.position == 0 and
-                                        s.kind in {skParam,skResult,skForVar})
+                                        s.kind in {skParam,skResult})
       var dest: TRegister = s.position + ord(s.kind == skParam)
       gen(c, ri, dest)
   else:
@@ -1003,7 +1033,7 @@ proc genRdVar(c: PCtx; n: PNode; dest: var TDest) =
   if s.isGlobal:
     if sfCompileTime in s.flags or c.mode == emRepl:
       discard
-    else:
+    elif s.position == 0:
       cannotEval(n)
     if s.position == 0:
       if sfImportc in s.flags: c.importcSym(n.info, s)
@@ -1014,8 +1044,9 @@ proc genRdVar(c: PCtx; n: PNode; dest: var TDest) =
     else:
       c.gABx(n, opcLdGlobal, dest, s.position)
   else:
+    if s.kind == skForVar and c.mode == emRepl: c.setSlot s
     if s.position > 0 or (s.position == 0 and
-                          s.kind in {skParam,skResult,skForVar}):
+                          s.kind in {skParam,skResult}):
       if dest < 0:
         dest = s.position + ord(s.kind == skParam)
       else:
@@ -1024,28 +1055,29 @@ proc genRdVar(c: PCtx; n: PNode; dest: var TDest) =
     else:
       # see tests/t99bott for an example that triggers it:
       cannotEval(n)
-      #InternalError(n.info, s.name.s & " " & $s.position)
 
-proc genAccess(c: PCtx; n: PNode; dest: var TDest; opc: TOpcode) =
-  let a = c.genx(n.sons[0])
-  let b = c.genx(n.sons[1])
+proc genAccess(c: PCtx; n: PNode; dest: var TDest; opc: TOpcode;
+               flags: TGenFlags) =
+  let a = c.genx(n.sons[0], flags)
+  let b = c.genx(n.sons[1], {})
   if dest < 0: dest = c.getTemp(n.typ)
-  c.gABC(n, opc, dest, a, b)
+  c.gABC(n, (if gfAddrOf in flags: succ(opc) else: opc), dest, a, b)
   c.freeTemp(a)
   c.freeTemp(b)
 
-proc genObjAccess(c: PCtx; n: PNode; dest: var TDest) =
-  genAccess(c, n, dest, opcLdObj)
+proc genObjAccess(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags) =
+  genAccess(c, n, dest, opcLdObj, flags)
 
-proc genCheckedObjAccess(c: PCtx; n: PNode; dest: var TDest) =
+proc genCheckedObjAccess(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags) =
   # XXX implement field checks!
-  genAccess(c, n.sons[0], dest, opcLdObj)
+  genAccess(c, n.sons[0], dest, opcLdObj, flags)
 
-proc genArrAccess(c: PCtx; n: PNode; dest: var TDest) =
-  if n.sons[0].typ.skipTypes(abstractVarRange).kind in {tyString, tyCString}:
-    genAccess(c, n, dest, opcLdStrIdx)
+proc genArrAccess(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags) =
+  if n.sons[0].typ.skipTypes(abstractVarRange-{tyTypeDesc}).kind in {
+      tyString, tyCString}:
+    genAccess(c, n, dest, opcLdStrIdx, {})
   else:
-    genAccess(c, n, dest, opcLdArr)
+    genAccess(c, n, dest, opcLdArr, flags)
 
 proc getNullValue*(typ: PType, info: TLineInfo): PNode
 proc getNullValueAux(obj: PNode, result: PNode) = 
@@ -1100,14 +1132,6 @@ proc getNullValue(typ: PType, info: TLineInfo): PNode =
     result = newNodeIT(nkCurly, info, t)
   else: internalError("getNullValue: " & $t.kind)
 
-proc setSlot(c: PCtx; v: PSym) =
-  # XXX generate type initialization here?
-  if v.position == 0:
-    v.position = c.prc.maxSlots
-    c.prc.slots[v.position] = (inUse: true,
-        kind: if v.kind == skLet: slotFixedLet else: slotFixedVar)
-    inc c.prc.maxSlots
-
 proc genVarSection(c: PCtx; n: PNode) =
   for a in n:
     if a.kind == nkCommentStmt: continue
@@ -1187,7 +1211,7 @@ proc genSetConstr(c: PCtx, n: PNode, dest: var TDest) =
 
 proc genObjConstr(c: PCtx, n: PNode, dest: var TDest) =
   if dest < 0: dest = c.getTemp(n.typ)
-  let t = n.typ.skipTypes(abstractRange)
+  let t = n.typ.skipTypes(abstractRange-{tyTypeDesc})
   if t.kind == tyRef:
     c.gABx(n, opcNew, dest, c.genType(t.sons[0]))
   else:
@@ -1222,7 +1246,7 @@ proc genTupleConstr(c: PCtx, n: PNode, dest: var TDest) =
 
 proc genProc*(c: PCtx; s: PSym): int
 
-proc gen(c: PCtx; n: PNode; dest: var TDest) =
+proc gen(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags = {}) =
   case n.kind
   of nkSym:
     let s = n.sym
@@ -1271,11 +1295,11 @@ proc gen(c: PCtx; n: PNode; dest: var TDest) =
   of nkAsgn, nkFastAsgn: 
     unused(n, dest)
     genAsgn(c, n.sons[0], n.sons[1], n.kind == nkAsgn)
-  of nkDotExpr: genObjAccess(c, n, dest)
-  of nkCheckedFieldExpr: genCheckedObjAccess(c, n, dest)
-  of nkBracketExpr: genArrAccess(c, n, dest)
-  of nkDerefExpr, nkHiddenDeref: genAddrDeref(c, n, dest, opcDeref)
-  of nkAddr, nkHiddenAddr: genAddrDeref(c, n, dest, opcAddr)
+  of nkDotExpr: genObjAccess(c, n, dest, flags)
+  of nkCheckedFieldExpr: genCheckedObjAccess(c, n, dest, flags)
+  of nkBracketExpr: genArrAccess(c, n, dest, flags)
+  of nkDerefExpr, nkHiddenDeref: genAddrDeref(c, n, dest, opcDeref, flags)
+  of nkAddr, nkHiddenAddr: genAddrDeref(c, n, dest, opcAddr, flags)
   of nkWhenStmt, nkIfStmt, nkIfExpr: genIf(c, n, dest)
   of nkCaseStmt: genCase(c, n, dest)
   of nkWhileStmt:
@@ -1298,7 +1322,7 @@ proc gen(c: PCtx; n: PNode; dest: var TDest) =
   of nkStmtListExpr:
     let L = n.len-1
     for i in 0 .. <L: gen(c, n.sons[i])
-    gen(c, n.sons[L], dest)
+    gen(c, n.sons[L], dest, flags)
   of nkDiscardStmt:
     unused(n, dest)
     gen(c, n.sons[0])
@@ -1460,9 +1484,9 @@ proc genProc(c: PCtx; s: PSym): int =
     c.gABC(body, opcEof, eofInstr.regA)
     c.optimizeJumps(result)
     s.offset = c.prc.maxSlots
-    #if s.name.s == "rawGet":
+    #if s.name.s == "concatStyleInterpolation":
     #  c.echoCode(result)
-    #  echo renderTree(body)
+    # echo renderTree(body)
     c.prc = oldPrc
   else:
     c.prc.maxSlots = s.offset
diff --git a/config/nimdoc.cfg b/config/nimdoc.cfg
index d47dccb63..63a3c30c4 100644
--- a/config/nimdoc.cfg
+++ b/config/nimdoc.cfg
@@ -76,7 +76,7 @@ span.LongStringLit {color: blue}
 span.CharLit {color: blue}
 span.EscapeSequence {color: black}
 span.Operator {color: black}
-span.Punctation {color: black}
+span.Punctuation {color: black}
 span.Comment, span.LongComment {font-style:italic; color: green}
 span.RegularExpression  {color: DarkViolet}
 span.TagStart {color: DarkViolet}
diff --git a/config/nimdoc.tex.cfg b/config/nimdoc.tex.cfg
index 8b59f2ee9..599ede345 100644
--- a/config/nimdoc.tex.cfg
+++ b/config/nimdoc.tex.cfg
@@ -98,7 +98,7 @@ doc.file = """
 \newcommand{\spanCharLit}[1]{#1}
 \newcommand{\spanEscapeSequence}[1]{#1}
 \newcommand{\spanOperator}[1]{#1}
-\newcommand{\spanPunctation}[1]{#1}
+\newcommand{\spanPunctuation}[1]{#1}
 \newcommand{\spanComment}[1]{\emph{#1}}
 \newcommand{\spanLongComment}[1]{\emph{#1}}
 \newcommand{\spanRegularExpression}[1]{#1}
diff --git a/copying.txt b/copying.txt
index 0ff6b7d87..4041ca027 100644
--- a/copying.txt
+++ b/copying.txt
@@ -1,7 +1,7 @@
 ===============================================================================
 Nimrod -- a Compiler for Nimrod. http://nimrod-code.org/
  
-Copyright (C) 2004-2013 Andreas Rumpf. All rights reserved.
+Copyright (C) 2004-2014 Andreas Rumpf. All rights reserved.
  
 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
diff --git a/devel/logging.nim b/devel/logging.nim
deleted file mode 100644
index a10478dab..000000000
--- a/devel/logging.nim
+++ /dev/null
@@ -1,210 +0,0 @@
-#
-#
-#            Nimrod's Runtime Library
-#        (c) Copyright 2012 Andreas Rumpf
-#
-#    See the file "copying.txt", included in this
-#    distribution, for details about the copyright.
-#
-
-## This module implements a simple logger. It is based on the following design:
-## * Runtime log formating is a bug: Sooner or later every log file is parsed.
-## * Keep it simple: If this library does not fullfill your needs, write your 
-##   own. Trying to support every logging feature just leads to bloat.
-## 
-## Format is:: 
-##
-##   DEBUG|INFO|... (2009-11-02 00:00:00)? (Component: )? Message
-##
-## 
-
-import strutils, os, times
-
-type
-  TLevel* = enum  ## logging level
-    lvlAll,       ## all levels active
-    lvlDebug,     ## debug level (and any above) active
-    lvlInfo,      ## info level (and any above) active
-    lvlWarn,      ## warn level (and any above) active
-    lvlError,     ## error level (and any above) active
-    lvlFatal,     ## fatal level (and any above) active
-    lvlNone
-
-const
-  LevelNames*: array [TLevel, string] = [
-    "DEBUG", "DEBUG", "INFO", "WARN", "ERROR", "FATAL", "NONE"
-  ]
-
-  defaultFmtStr = "" ## default string between log level and message per logger
-  verboseFmtStr = "$date $time "
-
-type
-  TLogger* = object of TObject ## abstract logger; the base type of all loggers
-    levelThreshold*: TLevel    ## only messages of level >= levelThreshold 
-                               ## should be processed
-    fmtStr: string ## = defaultFmtStr by default, see substituteLog for $date etc.
-    
-  TConsoleLogger* = object of TLogger ## logger that writes the messages to the
-                                      ## console
-  
-  TFileLogger* = object of TLogger ## logger that writes the messages to a file
-    f: TFile
-  
-  # TODO: implement rolling log, will produce filename.1, filename.2 etc.
-  TRollingFileLogger* = object of TFileLogger ## logger that writes the 
-                                              ## message to a file
-    maxLines: int # maximum number of lines    
-    curLine : int
-    baseName: string # initial filename
-    logFiles: int # how many log files already created, e.g. basename.1, basename.2...
-    
-    
-
-
-proc substituteLog*(frmt: string): string = 
-  ## converts $date to the current date
-  ## converts $time to the current time
-  ## converts $app to getAppFilename()
-  ## converts 
-  result = newStringOfCap(frmt.len + 20)
-  var i = 0
-  while i < frmt.len: 
-    if frmt[i] != '$': 
-      result.add(frmt[i])
-      inc(i)
-    else:
-      inc(i)
-      var v = ""
-      var app = getAppFilename()
-      while frmt[i] in IdentChars: 
-        v.add(toLower(frmt[i]))
-        inc(i)
-      case v
-      of "date": result.add(getDateStr())
-      of "time": result.add(getClockStr())
-      of "app":  result.add(app)
-      of "appdir": result.add(app.splitFile.dir)
-      of "appname": result.add(app.splitFile.name)
-
-
-
-method log*(L: ref TLogger, level: TLevel,
-            frmt: string, args: varargs[string, `$`]) =
-  ## override this method in custom loggers. Default implementation does
-  ## nothing.
-  nil
-  
-method log*(L: ref TConsoleLogger, level: TLevel,
-            frmt: string, args: varargs[string, `$`]) = 
-    Writeln(stdout, LevelNames[level], " ", substituteLog(L.fmtStr), frmt % args)
-
-method log*(L: ref TFileLogger, level: TLevel, 
-            frmt: string, args: varargs[string, `$`]) = 
-    Writeln(L.f, LevelNames[level], " ", substituteLog(L.fmtStr), frmt % args)
-
-proc defaultFilename*(): string = 
-  ## returns the default filename for a logger
-  var (path, name, ext) = splitFile(getAppFilename())
-  result = changeFileExt(path / name & "_" & getDateStr(), "log")
-
-      
-
-
-proc newConsoleLogger*(levelThreshold = lvlAll) : ref TConsoleLogger =
-  new result
-  result.fmtStr = defaultFmtStr
-  result.levelThreshold = levelThreshold
-
-proc newFileLogger*(filename = defaultFilename(), 
-                    mode: TFileMode = fmAppend,
-                    levelThreshold = lvlAll): ref TFileLogger = 
-  new(result)
-  result.levelThreshold = levelThreshold
-  result.f = open(filename, mode)
-  result.fmtStr = defaultFmtStr
-
-# ------
-
-proc readLogLines(logger : ref TRollingFileLogger) = nil
-  #f.readLine # TODO read all lines, update curLine
-
-
-proc newRollingFileLogger*(filename = defaultFilename(), 
-                           mode: TFileMode = fmReadWrite,
-                           levelThreshold = lvlAll,
-                           maxLines = 1000): ref TRollingFileLogger = 
-  new(result)
-  result.levelThreshold = levelThreshold
-  result.fmtStr = defaultFmtStr
-  result.maxLines = maxLines
-  result.f = open(filename, mode)
-  result.curLine = 0
-  
-  # TODO count all number files
-  # count lines in existing filename file
-  # if >= maxLines then rename to next numbered file and create new file
-  
-  #if mode in {fmReadWrite, fmReadWriteExisting}:
-  #  readLogLines(result)
-
-
-
-method log*(L: ref TRollingFileLogger, level: TLevel, 
-            frmt: string, args: varargs[string, `$`]) = 
-  # TODO 
-  # if more than maxlines, then set cursor to zero
-  
-  Writeln(L.f, LevelNames[level], " ", frmt % args)
-
-# --------
-
-var
-  level* = lvlAll  ## global log filter
-  handlers*: seq[ref TLogger] = @[] ## handlers with their own log levels
-
-proc logLoop(level: TLevel, frmt: string, args: varargs[string, `$`]) =
-  for logger in items(handlers): 
-    if level >= logger.levelThreshold:
-      log(logger, level, frmt, args)
-
-template log*(level: TLevel, frmt: string, args: varargs[string, `$`]) =
-  ## logs a message of the given level
-  bind logLoop
-  bind `%`
-  bind logging.Level
-  
-  if level >= logging.Level:
-    logLoop(level, frmt, args)
-
-template debug*(frmt: string, args: varargs[string, `$`]) =
-  ## logs a debug message
-  log(lvlDebug, frmt, args)
-
-template info*(frmt: string, args: varargs[string, `$`]) = 
-  ## logs an info message
-  log(lvlInfo, frmt, args)
-
-template warn*(frmt: string, args: varargs[string, `$`]) = 
-  ## logs a warning message
-  log(lvlWarn, frmt, args)
-
-template error*(frmt: string, args: varargs[string, `$`]) = 
-  ## logs an error message
-  log(lvlError, frmt, args)
-  
-template fatal*(frmt: string, args: varargs[string, `$`]) =  
-  ## logs a fatal error message
-  log(lvlFatal, frmt, args)
-
-
-# --------------
-
-when isMainModule:
-  var L = newConsoleLogger()
-  var fL = newFileLogger("test.log")
-  fL.fmtStr = verboseFmtStr
-  handlers.add(L)
-  handlers.add(fL)
-  info("hello", [])
-  
-
diff --git a/doc/gc.txt b/doc/gc.txt
index 13498afaa..18fb03b6d 100644
--- a/doc/gc.txt
+++ b/doc/gc.txt
@@ -107,3 +107,20 @@ that up to 100 objects are traversed and freed before it checks again. Thus
 ``workPackage`` affects the timing granularity and may need to be tweaked in
 highly specialized environments or for older hardware.
 
+
+Keeping track of memory
+-----------------------
+
+If you need to pass around memory allocated by Nimrod to C, you can use the
+procs ``GC_ref`` and ``GC_unref`` to mark objects as referenced to avoid them
+being freed by the GC. Other useful procs from `system <system.html>`_ you can
+use to keep track of memory are:
+
+* getTotalMem(): returns the amount of total memory managed by the GC.
+* getOccupiedMem(): bytes reserved by the GC and used by objects.
+* getFreeMem(): bytes reserved by the GC and not in use.
+
+In addition to ``GC_ref`` and ``GC_unref`` you can avoid the GC by manually
+allocating memory with procs like ``alloc``, ``allocShared``, or
+``allocCStringArray``. The GC won't try to free them, you need to call their
+respective *dealloc* pairs when you are done with them or they will leak.
diff --git a/doc/grammar.txt b/doc/grammar.txt
index 54c2217d8..63e898e11 100644
--- a/doc/grammar.txt
+++ b/doc/grammar.txt
@@ -59,8 +59,7 @@ primarySuffix = '(' (exprColonEqExpr comma?)* ')' doBlocks?
               | '.' optInd ('type' | 'addr' | symbol) generalizedLit?
               | '[' optInd indexExprList optPar ']'
               | '{' optInd indexExprList optPar '}'
-              | &( '`'|IDENT|literal|'cast') expr ^+ ',' # command syntax
-                     (doBlock | macroColon)?
+              | &( '`'|IDENT|literal|'cast') expr # command syntax
 condExpr = expr colcom expr optInd
         ('elif' expr colcom expr optInd)*
          'else' colcom expr
diff --git a/doc/lib.txt b/doc/lib.txt
index ba0cb0a90..3214cdae2 100644
--- a/doc/lib.txt
+++ b/doc/lib.txt
@@ -341,6 +341,9 @@ Miscellaneous
 * `endians <endians.html>`_
   This module contains helpers that deal with different byte orders.
 
+* `logging <logging.html>`_
+  This module implements a simple logger.
+
 
 Database support
 ----------------
diff --git a/doc/manual.txt b/doc/manual.txt
index faf62dcee..16e025ee0 100644
--- a/doc/manual.txt
+++ b/doc/manual.txt
@@ -12,6 +12,8 @@ Nimrod Manual
   user to one/some of the other players, but the total amount seems to remain
   pretty much constant for a given task. -- Ran
 
+
+
 About this document
 ===================
 
@@ -1313,12 +1315,9 @@ Examples:
 
 .. code-block:: nimrod
 
-  type
-    TCallback = proc (x: int) {.cdecl.}
-
-  proc printItem(x: Int) = ...
+  proc printItem(x: int) = ...
 
-  proc forEach(c: TCallback) =
+  proc forEach(c: proc (x: int) {.cdecl.}) =
     ...
 
   forEach(printItem)  # this will NOT work because calling conventions differ
@@ -1479,7 +1478,7 @@ But it seems all this boilerplate code needs to be repeated for the ``TEuro``
 currency. This can be solved with templates_.
 
 .. code-block:: nimrod
-  template Additive(typ: typedesc): stmt =
+  template additive(typ: typedesc): stmt =
     proc `+` *(x, y: typ): typ {.borrow.}
     proc `-` *(x, y: typ): typ {.borrow.}
     
@@ -1487,26 +1486,26 @@ currency. This can be solved with templates_.
     proc `+` *(x: typ): typ {.borrow.}
     proc `-` *(x: typ): typ {.borrow.}
 
-  template Multiplicative(typ, base: typedesc): stmt =
+  template multiplicative(typ, base: typedesc): stmt =
     proc `*` *(x: typ, y: base): typ {.borrow.}
     proc `*` *(x: base, y: typ): typ {.borrow.}
     proc `div` *(x: typ, y: base): typ {.borrow.}
     proc `mod` *(x: typ, y: base): typ {.borrow.}
 
-  template Comparable(typ: typedesc): stmt =
+  template comparable(typ: typedesc): stmt =
     proc `<` * (x, y: typ): bool {.borrow.}
     proc `<=` * (x, y: typ): bool {.borrow.}
     proc `==` * (x, y: typ): bool {.borrow.}
 
-  template DefineCurrency(typ, base: expr): stmt =
+  template defineCurrency(typ, base: expr): stmt =
     type
       typ* = distinct base
-    Additive(typ)
-    Multiplicative(typ, base)
-    Comparable(typ)
+    additive(typ)
+    multiplicative(typ, base)
+    comparable(typ)
     
-  DefineCurrency(TDollar, int)
-  DefineCurrency(TEuro, int)
+  defineCurrency(TDollar, int)
+  defineCurrency(TEuro, int)
 
 
 Void type
@@ -2232,6 +2231,8 @@ Instead of:
 Using statement
 ---------------
 
+**Warning**: The ``using`` statement is highly experimental!
+
 The `using statement`:idx: provides syntactic convenience for procs that
 heavily use a single contextual parameter. When applied to a variable or a
 constant, it will instruct Nimrod to automatically consider the used symbol as
@@ -2457,6 +2458,83 @@ notation. (Thus an operator can have more than two parameters):
 
   assert `*+`(3, 4, 6) == `*`(a, `+`(b, c))
 
+
+Method call syntax
+------------------
+
+For object oriented programming, the syntax ``obj.method(args)`` can be used 
+instead of ``method(obj, args)``. The parentheses can be omitted if there are no
+remaining arguments: ``obj.len`` (instead of ``len(obj)``).
+
+This `method call syntax`:idx: is not restricted to objects, it can be used
+to supply any type of first argument for procedures:
+
+.. code-block:: nimrod
+  
+  echo("abc".len) # is the same as echo(len("abc"))
+  echo("abc".toUpper())
+  echo({'a', 'b', 'c'}.card)
+  stdout.writeln("Hallo") # the same as writeln(stdout, "Hallo")
+
+Another way to look at the method call syntax is that it provides the missing
+postfix notation.
+
+
+Properties
+----------
+Nimrod has no need for *get-properties*: Ordinary get-procedures that are called
+with the *method call syntax* achieve the same. But setting a value is 
+different; for this a special setter syntax is needed:
+
+.. code-block:: nimrod
+  
+  type
+    TSocket* = object of TObject
+      FHost: int # cannot be accessed from the outside of the module
+                 # the `F` prefix is a convention to avoid clashes since
+                 # the accessors are named `host`
+
+  proc `host=`*(s: var TSocket, value: int) {.inline.} =
+    ## setter of hostAddr
+    s.FHost = value
+  
+  proc host*(s: TSocket): int {.inline.} =
+    ## getter of hostAddr
+    return s.FHost
+
+  var
+    s: TSocket
+  s.host = 34  # same as `host=`(s, 34)
+
+
+Command invocation syntax
+-------------------------
+
+Routines can be invoked without the ``()`` if the call is syntatically
+a statement. This `command invocation syntax`:idx: also works for
+expressions, but then only a single argument may follow. This restriction
+means ``echo f 1, f 2`` is parsed as ``echo(f(1), f(2))`` and not as
+``echo(f(1, f(2)))``. The method call syntax may be used to provide one
+more argument in this case:
+
+.. code-block:: nimrod
+  proc optarg(x:int, y:int = 0):int = x + y
+  proc singlearg(x:int):int = 20*x
+  
+  echo optarg 1, " ", singlearg 2  # prints "1 40"
+  
+  let fail = optarg 1, optarg 8   # Wrong. Too many arguments for a command call
+  let x = optarg(1, optarg 8)  # traditional procedure call with 2 arguments
+  let y = 1.optarg optarg 8    # same thing as above, w/o the parenthesis
+  assert x == y
+
+The command invocation syntax also can't have complex expressions as arguments. 
+For example: (`anonymous procs`_), ``if``, ``case`` or ``try``. The (`do 
+notation`_) is limited, but usable for a single proc (see the example in the 
+corresponding section). Function calls with no arguments still needs () to 
+distinguish between a call and the function itself as a first class value.
+
+
 Closures
 --------
 
@@ -2469,6 +2547,7 @@ the closure and its enclosing scope (i.e. any modifications made to them are
 visible in both places). The closure environment may be allocated on the heap
 or on the stack if the compiler determines that this would be safe.
 
+
 Anonymous Procs
 ---------------
 
@@ -2495,6 +2574,9 @@ calls can use the ``do`` keyword:
 .. code-block:: nimrod
   sort(cities) do (x,y: string) -> int:
     cmp(x.len, y.len)
+  # Less parenthesis using the method plus command syntax:
+  cities = cities.map do (x:string) -> string:  
+    "City of " & x
 
 ``do`` is written after the parentheses enclosing the regular proc params. 
 The proc expression represented by the do block is appended to them.
@@ -2849,7 +2931,7 @@ parameters of an outer factory proc:
         yield x
         inc x
 
-  let foo = mycount 1, 4
+  let foo = mycount(1, 4)
 
   for f in foo():
     echo f
@@ -3440,13 +3522,41 @@ A symbol can be forced to be open by a `mixin`:idx: declaration:
 
 .. code-block:: nimrod
   proc create*[T](): ref T =
-    # there is no overloaded 'mixin' here, so we need to state that it's an
+    # there is no overloaded 'init' here, so we need to state that it's an
     # open symbol explicitly:
     mixin init
     new result
     init result
 
 
+Bind statement
+--------------
+
+The `bind`:idx: statement is the counterpart to the ``mixin`` statement. It 
+can be used to explicitly declare identifiers that should be bound early (i.e.
+the identifiers should be looked up in the scope of the template/generic
+definition):
+
+.. code-block:: nimrod
+  # Module A
+  var 
+    lastId = 0
+  
+  template genId*: expr =
+    bind lastId
+    inc(lastId)
+    lastId
+
+.. code-block:: nimrod
+  # Module B
+  import A
+  
+  echo genId()
+
+But a ``bind`` is rarely useful because symbol binding from the definition
+scope is the default.
+
+
 Templates
 =========
 
@@ -3506,28 +3616,6 @@ receive undeclared identifiers:
   declareInt(x) # valid
 
 
-Scoping in templates
---------------------
-
-The template body does not open a new scope. To open a new scope a ``block``
-statement can be used:
-
-.. code-block:: nimrod
-  template declareInScope(x: expr, t: typedesc): stmt {.immediate.} = 
-    var x: t
-    
-  template declareInNewScope(x: expr, t: typedesc): stmt {.immediate.} = 
-    # open a new scope:
-    block: 
-      var x: t
-
-  declareInScope(a, int)
-  a = 42  # works, `a` is known here
-  
-  declareInNewScope(b, int)
-  b = 42  # does not work, `b` is unknown
-
-
 Passing a code block to a template
 ----------------------------------
 
@@ -3538,50 +3626,28 @@ special ``:`` syntax:
 .. code-block:: nimrod
 
   template withFile(f, fn, mode: expr, actions: stmt): stmt {.immediate.} =
-    block:
-      var f: TFile
-      if open(f, fn, mode):
-        try:
-          actions
-        finally:
-          close(f)
-      else:
-        quit("cannot open: " & fn)
+    var f: TFile
+    if open(f, fn, mode):
+      try:
+        actions
+      finally:
+        close(f)
+    else:
+      quit("cannot open: " & fn)
       
   withFile(txt, "ttempl3.txt", fmWrite):
     txt.writeln("line 1")
     txt.writeln("line 2")
   
 In the example the two ``writeln`` statements are bound to the ``actions``
-parameter. 
-
-**Note:** The symbol binding rules for templates might change!
+parameter.
 
-Symbol binding within templates happens after template instantiation: 
 
-.. code-block:: nimrod
-  # Module A
-  var 
-    lastId = 0
-  
-  template genId*: expr =
-    inc(lastId)
-    lastId
-
-.. code-block:: nimrod
-  # Module B
-  import A
-  
-  echo genId() # Error: undeclared identifier: 'lastId'
-
-
-Bind statement
---------------
+Symbol binding in templates
+---------------------------
 
-Exporting a template is a often a leaky abstraction as it can depend on 
-symbols that are not visible from a client module. However, to compensate for
-this case, a `bind`:idx: statement can be used: It declares all identifiers
-that should be bound early (i.e. when the template is parsed):
+A template is a `hygienic`:idx: macro and so opens a new scope. Most symbols are
+bound from the definition scope of the template:
 
 .. code-block:: nimrod
   # Module A
@@ -3589,7 +3655,6 @@ that should be bound early (i.e. when the template is parsed):
     lastId = 0
   
   template genId*: expr =
-    bind lastId
     inc(lastId)
     lastId
 
@@ -3597,9 +3662,11 @@ that should be bound early (i.e. when the template is parsed):
   # Module B
   import A
   
-  echo genId() # Works
+  echo genId() # Works as 'lastId' has been bound in 'genId's defining scope
+
+As in generics symbol binding can be influenced via ``mixin`` or ``bind`` 
+statements.
 
-A ``bind`` statement can also be used in generics for the same purpose.
 
 
 Identifier construction
@@ -3942,13 +4009,13 @@ Static params can also appear in the signatures of generic types:
 
   type
     Matrix[M,N: static[int]; T: Number] = array[0..(M*N - 1), T]
-      # Please, note how `Number` is just a type constraint here, while
+      # Note how `Number` is just a type constraint here, while
       # `static[int]` requires us to supply a compile-time int value
 
     AffineTransform2D[T] = Matrix[3, 3, T]
     AffineTransform3D[T] = Matrix[4, 4, T]
 
-  AffineTransform3D[float] # OK
+  AffineTransform3D[float]  # OK
   AffineTransform2D[string] # Error, `string` is not a `Number`
 
 
@@ -4685,6 +4752,10 @@ These rules ensure that the construction is tied to a variable and can easily
 be destructed at its scope exit. Later versions of the language will improve
 the support of destructors.
 
+Be aware that destructors are not called for objects allocated with ``new``.
+This may change in future versions of language, but for now use 
+the ``finalizer`` parameter to ``new``.
+
 
 delegator pragma
 ----------------
@@ -5173,9 +5244,9 @@ the same feature under the same name.
 Exportc pragma
 --------------
 The `exportc`:idx: pragma provides a means to export a type, a variable, or a
-procedure to C. The optional argument is a string containing the C identifier.
-If the argument is missing, the C name is the Nimrod
-identifier *exactly as spelled*:
+procedure to C. Enums and constants can't be exported. The optional argument
+is a string containing the C identifier.  If the argument is missing, the C
+name is the Nimrod identifier *exactly as spelled*:
 
 .. code-block:: Nimrod
   proc callme(formatstr: cstring) {.exportc: "callMe", varargs.}
diff --git a/doc/tut1.txt b/doc/tut1.txt
index 1ba3253c8..b70f40f4a 100644
--- a/doc/tut1.txt
+++ b/doc/tut1.txt
@@ -1321,6 +1321,30 @@ In this example ``$`` is applied to any argument that is passed to the
 parameter ``a``. Note that ``$`` applied to strings is a nop.
 
 
+Slices
+------
+
+Slices look similar to subranges types in syntax but are used in a different
+context. A slice is just an object of type TSlice which contains two bounds,
+`a` and `b`. By itself a slice is not very useful, but other collection types
+define operators which accept TSlice objects to define ranges.
+
+.. code-block:: nimrod
+
+  var
+    a = "Nimrod is a progamming language"
+    b = "Slices are useless."
+
+  echo a[10..15] # --> 'a prog'
+  b[11.. -2] = "useful"
+  echo b # --> 'Slices are useful.'
+
+In the previous example slices are used to modify a part of a string, and even
+a negative index is used. The slice's bounds can hold any value supported by
+their type, but it is the proc using the slice object which defines what values
+are accepted.
+
+
 Tuples
 ------
 
diff --git a/doc/tut2.txt b/doc/tut2.txt
index 581239cc7..6738c5551 100644
--- a/doc/tut2.txt
+++ b/doc/tut2.txt
@@ -528,7 +528,7 @@ containers:
   proc newNode*[T](data: T): PBinaryTree[T] =
     # constructor for a node
     new(result)
-    result.dat = data
+    result.data = data
 
   proc add*[T](root: var PBinaryTree[T], n: PBinaryTree[T]) =
     # insert a node into the tree
@@ -569,7 +569,7 @@ containers:
       
   var
     root: PBinaryTree[string] # instantiate a PBinaryTree with ``string``
-  add(root, newNode("hallo")) # instantiates ``newNode`` and ``add``
+  add(root, newNode("hello")) # instantiates ``newNode`` and ``add``
   add(root, "world")          # instantiates the second ``add`` proc
   for str in preorder(root):
     stdout.writeln(str)
diff --git a/koch.nim b/koch.nim
index 35a86a597..4d2b3bfb7 100644
--- a/koch.nim
+++ b/koch.nim
@@ -266,8 +266,9 @@ proc tests(args: string) =
   # we compile the tester with taintMode:on to have a basic
   # taint mode test :-)
   exec "nimrod cc --taintMode:on tests/testament/tester"
-  exec quoteShell(getCurrentDir() / "tests/testament/tester".exe) & " " &
-      (args|"all")
+  let tester = quoteShell(getCurrentDir() / "tests/testament/tester".exe)
+  exec tester & " " & (args|"all")
+  exec tester & " html"
 
 proc temp(args: string) =
   var output = "compiler" / "nimrod".exe
diff --git a/lib/core/macros.nim b/lib/core/macros.nim
index 3b36e31e0..585ccf869 100644
--- a/lib/core/macros.nim
+++ b/lib/core/macros.nim
@@ -294,19 +294,6 @@ proc quote*(bl: stmt, op = "``"): PNimrodNode {.magic: "QuoteAst".}
   ##       if not `ex`:
   ##         echo `info` & ": Check failed: " & `expString`
   
-when not defined(booting):
-  template emit*(e: static[string]): stmt =
-    ## accepts a single string argument and treats it as nimrod code
-    ## that should be inserted verbatim in the program
-    ## Example:
-    ##
-    ## .. code-block:: nimrod
-    ##   emit("echo " & '"' & "hello world".toUpper & '"')
-    ##
-    macro payload: stmt {.gensym.} =
-      result = e.parseStmt
-    payload()
-
 proc expectKind*(n: PNimrodNode, k: TNimrodNodeKind) {.compileTime.} =
   ## checks that `n` is of kind `k`. If this is not the case,
   ## compilation aborts with an error message. This is useful for writing
@@ -421,7 +408,8 @@ proc lispRepr*(n: PNimrodNode): string {.compileTime.} =
   of nnkFloatLit..nnkFloat64Lit: add(result, $n.floatVal)
   of nnkStrLit..nnkTripleStrLit: add(result, $n.strVal)
   of nnkIdent: add(result, "!\"" & $n.ident & '"')
-  of nnkSym, nnkNone: assert false
+  of nnkSym: add(result, $n.symbol)
+  of nnkNone: assert false
   else:
     add(result, lispRepr(n[0]))
     for j in 1..n.len-1:
@@ -745,3 +733,15 @@ proc addIdentIfAbsent*(dest: PNimrodNode, ident: string) {.compiletime.} =
     else: discard
   dest.add(ident(ident))
 
+when not defined(booting):
+  template emit*(e: static[string]): stmt =
+    ## accepts a single string argument and treats it as nimrod code
+    ## that should be inserted verbatim in the program
+    ## Example:
+    ##
+    ## .. code-block:: nimrod
+    ##   emit("echo " & '"' & "hello world".toUpper & '"')
+    ##
+    macro payload: stmt {.gensym.} =
+      result = parseStmt(e)
+    payload()
diff --git a/lib/impure/db_mongo.nim b/lib/impure/db_mongo.nim
index d012f677f..dc8a808f2 100644
--- a/lib/impure/db_mongo.nim
+++ b/lib/impure/db_mongo.nim
@@ -58,7 +58,7 @@ proc open*(host: string = defaultHost, port: int = defaultPort): TDbConn {.
   ## be established.
   init(result)
   
-  let x = connect(result, host, port.cint)
+  let x = client(result, host, port.cint)
   if x != 0'i32:
     dbError(result, "cannot open: " & host)
 
@@ -119,7 +119,7 @@ proc insertId*(db: var TDbConn, namespace: string, data: PJsonNode): TOid {.
   ## the generated OID for the ``_id`` field.
   result = genOid()
   var x = jsonToBSon(data, result)
-  insert(db, namespace, x)
+  insert(db, namespace, x, nil)
   destroy(x)
 
 proc insert*(db: var TDbConn, namespace: string, data: PJsonNode) {.
diff --git a/lib/impure/db_sqlite.nim b/lib/impure/db_sqlite.nim
index a3499a6df..809ee7039 100644
--- a/lib/impure/db_sqlite.nim
+++ b/lib/impure/db_sqlite.nim
@@ -148,7 +148,8 @@ proc getValue*(db: TDbConn, query: TSqlQuery,
   if finalize(stmt) != SQLITE_OK: dbError(db)
   
 proc tryInsertID*(db: TDbConn, query: TSqlQuery, 
-                  args: varargs[string, `$`]): int64 {.tags: [FWriteDb].} =
+                  args: varargs[string, `$`]): int64
+                  {.tags: [FWriteDb], raises: [].} =
   ## executes the query (typically "INSERT") and returns the 
   ## generated ID for the row or -1 in case of an error. 
   var q = dbFormat(query, args)
@@ -157,7 +158,8 @@ proc tryInsertID*(db: TDbConn, query: TSqlQuery,
   if prepare_v2(db, q, q.len.cint, stmt, nil) == SQLITE_OK:
     if step(stmt) == SQLITE_DONE:
       result = last_insert_rowid(db)
-  if finalize(stmt) != SQLITE_OK: dbError(db)
+    if finalize(stmt) != SQLITE_OK:
+      result = -1
 
 proc insertID*(db: TDbConn, query: TSqlQuery, 
                args: varargs[string, `$`]): int64 {.tags: [FWriteDb].} = 
diff --git a/lib/packages/docutils/highlite.nim b/lib/packages/docutils/highlite.nim
index db7a63928..4ca0c79e0 100644
--- a/lib/packages/docutils/highlite.nim
+++ b/lib/packages/docutils/highlite.nim
@@ -19,7 +19,7 @@ type
     gtEof, gtNone, gtWhitespace, gtDecNumber, gtBinNumber, gtHexNumber, 
     gtOctNumber, gtFloatNumber, gtIdentifier, gtKeyword, gtStringLit, 
     gtLongStringLit, gtCharLit, gtEscapeSequence, # escape sequence like \xff
-    gtOperator, gtPunctation, gtComment, gtLongComment, gtRegularExpression, 
+    gtOperator, gtPunctuation, gtComment, gtLongComment, gtRegularExpression, 
     gtTagStart, gtTagEnd, gtKey, gtValue, gtRawData, gtAssembler, 
     gtPreprocessor, gtDirective, gtCommand, gtRule, gtHyperlink, gtLabel, 
     gtReference, gtOther
@@ -39,7 +39,7 @@ const
   tokenClassToStr*: array[TTokenClass, string] = ["Eof", "None", "Whitespace", 
     "DecNumber", "BinNumber", "HexNumber", "OctNumber", "FloatNumber", 
     "Identifier", "Keyword", "StringLit", "LongStringLit", "CharLit", 
-    "EscapeSequence", "Operator", "Punctation", "Comment", "LongComment", 
+    "EscapeSequence", "Operator", "Punctuation", "Comment", "LongComment", 
     "RegularExpression", "TagStart", "TagEnd", "Key", "Value", "RawData", 
     "Assembler", "Preprocessor", "Directive", "Command", "Rule", "Hyperlink", 
     "Label", "Reference", "Other"]
@@ -258,7 +258,7 @@ proc nimNextToken(g: var TGeneralTokenizer) =
           else: inc(pos)
     of '(', ')', '[', ']', '{', '}', '`', ':', ',', ';': 
       inc(pos)
-      g.kind = gtPunctation
+      g.kind = gtPunctuation
     of '\0': 
       g.kind = gtEof
     else: 
@@ -473,7 +473,7 @@ proc clikeNextToken(g: var TGeneralTokenizer, keywords: openArray[string],
         else: inc(pos)
     of '(', ')', '[', ']', '{', '}', ':', ',', ';', '.': 
       inc(pos)
-      g.kind = gtPunctation
+      g.kind = gtPunctuation
     of '\0': 
       g.kind = gtEof
     else: 
diff --git a/lib/posix/posix.nim b/lib/posix/posix.nim
index c3d5b5939..41260b36f 100644
--- a/lib/posix/posix.nim
+++ b/lib/posix/posix.nim
@@ -2566,3 +2566,15 @@ proc poll*(a1: ptr TPollfd, a2: Tnfds, a3: int): cint {.
 
 proc realpath*(name, resolved: cstring): cstring {.
   importc: "realpath", header: "<stdlib.h>".}
+
+proc utimes*(path: cstring, times: ptr array [2, Ttimeval]): int {.
+  importc: "utimes", header: "<sys/time.h>".}
+  ## Sets file access and modification times.
+  ##
+  ## Pass the filename and an array of times to set the access and modification
+  ## times respectively. If you pass nil as the array both attributes will be
+  ## set to the current time.
+  ##
+  ## Returns zero on success.
+  ##
+  ## For more information read http://www.unix.com/man-page/posix/3/utimes/.
diff --git a/lib/pure/algorithm.nim b/lib/pure/algorithm.nim
index df7ae6d17..921c659de 100644
--- a/lib/pure/algorithm.nim
+++ b/lib/pure/algorithm.nim
@@ -131,3 +131,36 @@ proc sort*[T](a: var openArray[T],
       dec(m, s*2)
     s = s*2
 
+proc product*[T](x: openarray[seq[T]]): seq[seq[T]] =
+  ## produces the Cartesian product of the array. Warning: complexity
+  ## may explode.
+  result = @[]
+  if x.len == 0:
+    return
+  if x.len == 1:
+    result = @x
+    return
+  var
+    indexes = newSeq[int](x.len)
+    initial = newSeq[int](x.len)
+    index = 0
+  # replace with newSeq as soon as #853 is fixed
+  var next: seq[T] = @[]
+  next.setLen(x.len)
+  for i in 0..(x.len-1):
+    if len(x[i]) == 0: return
+    initial[i] = len(x[i])-1
+  indexes = initial
+  while true:
+    while indexes[index] == -1:
+      indexes[index] = initial[index]
+      index +=1
+      if index == x.len: return
+      indexes[index] -=1
+    for ni, i in indexes:
+      next[ni] = x[ni][i]
+    var res: seq[T]
+    shallowCopy(res, next)
+    result.add(res)
+    index = 0
+    indexes[index] -=1
diff --git a/lib/pure/asyncio.nim b/lib/pure/asyncio.nim
index f13cadaa2..96afc6f4f 100644
--- a/lib/pure/asyncio.nim
+++ b/lib/pure/asyncio.nim
@@ -689,5 +689,5 @@ when isMainModule:
   server.listen()
   d.register(server)
   
-  while d.poll(-1): nil
+  while d.poll(-1): discard
     
diff --git a/lib/pure/collections/sequtils.nim b/lib/pure/collections/sequtils.nim
index 3993f1ccc..b2f72ee14 100644
--- a/lib/pure/collections/sequtils.nim
+++ b/lib/pure/collections/sequtils.nim
@@ -276,6 +276,38 @@ template foldr*(sequence, operation: expr): expr =
     result = operation
   result
 
+template mapIt*(seq1, typ, pred: expr): expr =
+  ## Convenience template around the ``map`` proc to reduce typing.
+  ##
+  ## The template injects the ``it`` variable which you can use directly in an
+  ## expression. You also need to pass as `typ` the type of the expression,
+  ## since the new returned sequence can have a different type than the
+  ## original.  Example:
+  ##
+  ## .. code-block:: nimrod
+  ##   let
+  ##     nums = @[1, 2, 3, 4]
+  ##     strings = nums.mapIt(string, $(4 * it))
+  var result {.gensym.}: seq[typ] = @[]
+  for it {.inject.} in items(seq1):
+    result.add(pred)
+  result
+
+template mapIt*(varSeq, pred: expr) =
+  ## Convenience template around the mutable ``map`` proc to reduce typing.
+  ##
+  ## The template injects the ``it`` variable which you can use directly in an
+  ## expression. The expression has to return the same type as the sequence you
+  ## are mutating. Example:
+  ##
+  ## .. code-block:: nimrod
+  ##   var nums = @[1, 2, 3, 4]
+  ##   nums.mapIt(it * 3)
+  ##   assert nums[0] + nums[3] == 15
+  for i in 0 .. <len(varSeq):
+    let it {.inject.} = varSeq[i]
+    varSeq[i] = pred
+
 when isMainModule:
   import strutils
   block: # concat test
@@ -381,4 +413,11 @@ when isMainModule:
     Inserting [2,2,2,2,2,2] into [1,1,1,1,1,1,1,1]
     at 3 is [1,1,1,2,2,2,2,2,2,1,1,1,1,1]"""
 
+  block: # mapIt tests
+    var
+      nums = @[1, 2, 3, 4]
+      strings = nums.mapIt(string, $(4 * it))
+    nums.mapIt(it * 3)
+    assert nums[0] + nums[3] == 15
+
   echo "Finished doc tests"
diff --git a/lib/pure/collections/sets.nim b/lib/pure/collections/sets.nim
index 7259772aa..e6ab617e5 100644
--- a/lib/pure/collections/sets.nim
+++ b/lib/pure/collections/sets.nim
@@ -224,3 +224,20 @@ proc toOrderedSet*[A](keys: openArray[A]): TOrderedSet[A] =
 proc `$`*[A](s: TOrderedSet[A]): string =
   ## The `$` operator for ordered hash sets.
   dollarImpl()
+
+proc `<`*[A](s, t: TSet[A]): bool =
+  ## Is s a strict subset of t?
+  s.counter != t.counter and s <= t
+
+proc `<=`*[A](s, t: TSet[A]): bool =
+  ## Is s a subset of t?
+  result = false
+  if s.counter > t.counter: return
+  result = true
+  for item in s:
+    if not(t.contains(item)):
+      result = false
+      return
+      
+proc `==`*[A](s, t: TSet[A]): bool =
+  s.counter == t.counter and s <= t
diff --git a/lib/pure/collections/tables.nim b/lib/pure/collections/tables.nim
index 73da274b9..40ae57b5a 100644
--- a/lib/pure/collections/tables.nim
+++ b/lib/pure/collections/tables.nim
@@ -189,6 +189,16 @@ template dollarImpl(): stmt {.dirty.} =
 proc `$`*[A, B](t: TTable[A, B]): string =
   ## The `$` operator for hash tables.
   dollarImpl()
+  
+proc `==`*[A, B](s, t: TTable[A, B]): bool =
+  s.counter == t.counter and s.data == t.data
+  
+proc indexBy*[A, B, C](collection: A, index: proc(x: B): C): TTable[C, B] =
+  ## Index the collection with the proc provided.
+  # TODO: As soon as supported, change collection: A to collection: A[B]
+  result = initTable[C, B]()
+  for item in collection:
+    result[index(item)] = item
 
 # ------------------------------ ordered table ------------------------------
 
diff --git a/lib/pure/dynlib.nim b/lib/pure/dynlib.nim
index a64b7f138..3ed00fdb2 100644
--- a/lib/pure/dynlib.nim
+++ b/lib/pure/dynlib.nim
@@ -14,15 +14,15 @@
 type
   TLibHandle* = pointer ## a handle to a dynamically loaded library
 
-proc LoadLib*(path: string): TLibHandle
+proc loadLib*(path: string): TLibHandle
   ## loads a library from `path`. Returns nil if the library could not 
   ## be loaded.
 
-proc LoadLib*(): TLibHandle
+proc loadLib*(): TLibHandle
   ## gets the handle from the current executable. Returns nil if the 
   ## library could not be loaded.
 
-proc UnloadLib*(lib: TLibHandle)
+proc unloadLib*(lib: TLibHandle)
   ## unloads the library `lib`
 
 proc raiseInvalidLibrary*(name: cstring) {.noinline, noreturn.} =
@@ -60,9 +60,9 @@ when defined(posix):
   proc dlsym(lib: TLibHandle, name: cstring): pointer {.
       importc, header: "<dlfcn.h>".}
 
-  proc LoadLib(path: string): TLibHandle = return dlopen(path, RTLD_NOW)
-  proc LoadLib(): TLibHandle = return dlopen(nil, RTLD_NOW)
-  proc UnloadLib(lib: TLibHandle) = dlclose(lib)
+  proc loadLib(path: string): TLibHandle = return dlopen(path, RTLD_NOW)
+  proc loadLib(): TLibHandle = return dlopen(nil, RTLD_NOW)
+  proc unloadLib(lib: TLibHandle) = dlclose(lib)
   proc symAddr(lib: TLibHandle, name: cstring): pointer = 
     return dlsym(lib, name)
 
@@ -78,14 +78,14 @@ elif defined(windows) or defined(dos):
   proc FreeLibrary(lib: THINSTANCE) {.importc, header: "<windows.h>", stdcall.}
   proc winLoadLibrary(path: cstring): THINSTANCE {.
       importc: "LoadLibraryA", header: "<windows.h>", stdcall.}
-  proc GetProcAddress(lib: THINSTANCE, name: cstring): pointer {.
+  proc getProcAddress(lib: THINSTANCE, name: cstring): pointer {.
       importc: "GetProcAddress", header: "<windows.h>", stdcall.}
 
-  proc LoadLib(path: string): TLibHandle =
+  proc loadLib(path: string): TLibHandle =
     result = cast[TLibHandle](winLoadLibrary(path))
-  proc LoadLib(): TLibHandle =
+  proc loadLib(): TLibHandle =
     result = cast[TLibHandle](winLoadLibrary(nil))
-  proc UnloadLib(lib: TLibHandle) = FreeLibrary(cast[THINSTANCE](lib))
+  proc unloadLib(lib: TLibHandle) = FreeLibrary(cast[THINSTANCE](lib))
 
   proc symAddr(lib: TLibHandle, name: cstring): pointer =
     result = GetProcAddress(cast[THINSTANCE](lib), name)
diff --git a/lib/pure/htmlparser.nim b/lib/pure/htmlparser.nim
index 060f0e386..c38eb7063 100644
--- a/lib/pure/htmlparser.nim
+++ b/lib/pure/htmlparser.nim
@@ -480,7 +480,7 @@ proc untilElementEnd(x: var TXmlParser, result: PXmlNode,
         if htmlTag(x.elemName) in {tagOption, tagOptgroup}:
           errors.add(expected(x, result))
           break
-      else: nil
+      else: discard
       result.addNode(parse(x, errors))
     of xmlElementEnd: 
       if cmpIgnoreCase(x.elemName, result.tag) == 0: 
@@ -547,7 +547,7 @@ proc parse(x: var TXmlParser, errors: var seq[string]): PXmlNode =
     var u = entityToUtf8(x.rawData)
     if u.len != 0: result = newText(u)
     next(x)
-  of xmlEof: nil
+  of xmlEof: discard
 
 proc parseHtml*(s: PStream, filename: string, 
                 errors: var seq[string]): PXmlNode = 
diff --git a/lib/pure/irc.nim b/lib/pure/irc.nim
index 750c98516..c1b519b0b 100644
--- a/lib/pure/irc.nim
+++ b/lib/pure/irc.nim
@@ -476,12 +476,12 @@ when isMainModule:
   var client = irc("amber.tenthbit.net", nick="TestBot1234",
                    joinChans = @["#flood"])
   client.connect()
-  while True:
+  while true:
     var event: TIRCEvent
     if client.poll(event):
       case event.typ
       of EvConnected:
-        nil
+        discard
       of EvDisconnected:
         break
       of EvMsg:
diff --git a/lib/pure/logging.nim b/lib/pure/logging.nim
new file mode 100644
index 000000000..284384b37
--- /dev/null
+++ b/lib/pure/logging.nim
@@ -0,0 +1,267 @@
+#
+#
+#            Nimrod's Runtime Library
+#        (c) Copyright 2014 Andreas Rumpf, Dominik Picheta
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+## This module implements a simple logger. It has been designed to be as simple
+## as possible to avoid bloat, if this library does not fullfill your needs,
+## write your own.
+## 
+## Format strings support the following variables which must be prefixed with
+## the dollar operator (``$``):
+##
+## ============  =======================
+##   Operator     Output
+## ============  =======================
+## $date         Current date
+## $time         Current time
+## $app          ``os.getAppFilename()``
+## ============  =======================
+## 
+##
+## The following example demonstrates logging to three different handlers
+## simultaneously:
+##
+## .. code-block:: nimrod
+##     
+##    var L = newConsoleLogger()
+##    var fL = newFileLogger("test.log", fmtStr = verboseFmtStr)
+##    var rL = newRollingFileLogger("rolling.log", fmtStr = verboseFmtStr)
+##    handlers.add(L)
+##    handlers.add(fL)
+##    handlers.add(rL)
+##    info("920410:52 accepted")
+##    warn("4 8 15 16 23 4-- Error")
+##    error("922044:16 SYSTEM FAILURE")
+##    fatal("SYSTEM FAILURE SYSTEM FAILURE")
+
+import strutils, os, times
+
+type
+  TLevel* = enum  ## logging level
+    lvlAll,       ## all levels active
+    lvlDebug,     ## debug level (and any above) active
+    lvlInfo,      ## info level (and any above) active
+    lvlWarn,      ## warn level (and any above) active
+    lvlError,     ## error level (and any above) active
+    lvlFatal,     ## fatal level (and any above) active
+    lvlNone       ## no levels active
+
+const
+  LevelNames*: array [TLevel, string] = [
+    "DEBUG", "DEBUG", "INFO", "WARN", "ERROR", "FATAL", "NONE"
+  ]
+
+  defaultFmtStr* = "" ## default string between log level and message per logger
+  verboseFmtStr* = "$date $time "
+
+type
+  PLogger* = ref object of PObject ## abstract logger; the base type of all loggers
+    levelThreshold*: TLevel    ## only messages of level >= levelThreshold 
+                               ## should be processed
+    fmtStr: string ## = defaultFmtStr by default, see substituteLog for $date etc.
+    
+  PConsoleLogger* = ref object of PLogger ## logger that writes the messages to the
+                                      ## console
+  
+  PFileLogger* = ref object of PLogger ## logger that writes the messages to a file
+    f: TFile
+  
+  PRollingFileLogger* = ref object of PFileLogger ## logger that writes the 
+                                                  ## messages to a file and
+                                                  ## performs log rotation
+    maxLines: int # maximum number of lines    
+    curLine : int
+    baseName: string # initial filename
+    baseMode: TFileMode # initial file mode
+    logFiles: int # how many log files already created, e.g. basename.1, basename.2...
+
+proc substituteLog(frmt: string): string = 
+  ## converts $date to the current date
+  ## converts $time to the current time
+  ## converts $app to getAppFilename()
+  ## converts 
+  result = newStringOfCap(frmt.len + 20)
+  var i = 0
+  while i < frmt.len: 
+    if frmt[i] != '$': 
+      result.add(frmt[i])
+      inc(i)
+    else:
+      inc(i)
+      var v = ""
+      var app = getAppFilename()
+      while frmt[i] in IdentChars: 
+        v.add(toLower(frmt[i]))
+        inc(i)
+      case v
+      of "date": result.add(getDateStr())
+      of "time": result.add(getClockStr())
+      of "app":  result.add(app)
+      of "appdir": result.add(app.splitFile.dir)
+      of "appname": result.add(app.splitFile.name)
+
+method log*(logger: PLogger, level: TLevel,
+            frmt: string, args: varargs[string, `$`]) {.raises: [EBase], tags: [FTime, FWriteIO, FReadIO].} =
+  ## Override this method in custom loggers. Default implementation does
+  ## nothing.
+  discard
+  
+method log*(logger: PConsoleLogger, level: TLevel,
+            frmt: string, args: varargs[string, `$`]) =
+  ## Logs to the console using ``logger`` only.
+  if level >= logger.levelThreshold:
+    writeln(stdout, LevelNames[level], " ", substituteLog(logger.fmtStr),
+            frmt % args)
+
+method log*(logger: PFileLogger, level: TLevel, 
+            frmt: string, args: varargs[string, `$`]) =
+  ## Logs to a file using ``logger`` only.
+  if level >= logger.levelThreshold:
+    writeln(logger.f, LevelNames[level], " ",
+            substituteLog(logger.fmtStr), frmt % args)
+
+proc defaultFilename*(): string = 
+  ## Returns the default filename for a logger.
+  var (path, name, ext) = splitFile(getAppFilename())
+  result = changeFileExt(path / name, "log")
+
+proc newConsoleLogger*(levelThreshold = lvlAll, fmtStr = defaultFmtStr): PConsoleLogger =
+  ## Creates a new console logger. This logger logs to the console.
+  new result
+  result.fmtStr = fmtStr
+  result.levelThreshold = levelThreshold
+
+proc newFileLogger*(filename = defaultFilename(), 
+                    mode: TFileMode = fmAppend,
+                    levelThreshold = lvlAll,
+                    fmtStr = defaultFmtStr): PFileLogger = 
+  ## Creates a new file logger. This logger logs to a file.
+  new(result)
+  result.levelThreshold = levelThreshold
+  result.f = open(filename, mode)
+  result.fmtStr = fmtStr
+
+# ------
+
+proc countLogLines(logger: PRollingFileLogger): int =
+  result = 0
+  for line in logger.f.lines():
+    result.inc()
+
+proc countFiles(filename: string): int =
+  # Example: file.log.1
+  result = 0
+  let (dir, name, ext) = splitFile(filename)
+  for kind, path in walkDir(dir):
+    if kind == pcFile:
+      let llfn = name & ext & ExtSep
+      if path.extractFilename.startsWith(llfn):
+        let numS = path.extractFilename[llfn.len .. -1]
+        try:
+          let num = parseInt(numS)
+          if num > result:
+            result = num
+        except EInvalidValue: discard
+
+proc newRollingFileLogger*(filename = defaultFilename(), 
+                           mode: TFileMode = fmReadWrite,
+                           levelThreshold = lvlAll,
+                           fmtStr = defaultFmtStr,
+                           maxLines = 1000): PRollingFileLogger =
+  ## Creates a new rolling file logger. Once a file reaches ``maxLines`` lines
+  ## a new log file will be started and the old will be renamed.
+  new(result)
+  result.levelThreshold = levelThreshold
+  result.fmtStr = defaultFmtStr
+  result.maxLines = maxLines
+  result.f = open(filename, mode)
+  result.curLine = 0
+  result.baseName = filename
+  result.baseMode = mode
+  
+  result.logFiles = countFiles(filename)
+  
+  if mode == fmAppend:
+    # We need to get a line count because we will be appending to the file.
+    result.curLine = countLogLines(result)
+
+proc rotate(logger: PRollingFileLogger) =
+  let (dir, name, ext) = splitFile(logger.baseName)
+  for i in countdown(logger.logFiles, 0):
+    let srcSuff = if i != 0: ExtSep & $i else: ""
+    moveFile(dir / (name & ext & srcSuff),
+             dir / (name & ext & ExtSep & $(i+1)))
+
+method log*(logger: PRollingFileLogger, level: TLevel, 
+            frmt: string, args: varargs[string, `$`]) =
+  ## Logs to a file using rolling ``logger`` only.
+  if level >= logger.levelThreshold:
+    if logger.curLine >= logger.maxLines:
+      logger.f.close()
+      rotate(logger)
+      logger.logFiles.inc
+      logger.curLine = 0
+      logger.f = open(logger.baseName, logger.baseMode)
+    
+    writeln(logger.f, LevelNames[level], " ", frmt % args)
+    logger.curLine.inc
+
+# --------
+
+var
+  level* = lvlAll  ## global log filter
+  handlers*: seq[PLogger] = @[] ## handlers with their own log levels
+
+proc logLoop(level: TLevel, frmt: string, args: varargs[string, `$`]) =
+  for logger in items(handlers): 
+    if level >= logger.levelThreshold:
+      log(logger, level, frmt, args)
+
+template log*(level: TLevel, frmt: string, args: varargs[string, `$`]) =
+  ## Logs a message to all registered handlers at the given level.
+  bind logLoop
+  bind `%`
+  bind logging.Level
+  
+  if level >= logging.Level:
+    logLoop(level, frmt, args)
+
+template debug*(frmt: string, args: varargs[string, `$`]) =
+  ## Logs a debug message to all registered handlers.
+  log(lvlDebug, frmt, args)
+
+template info*(frmt: string, args: varargs[string, `$`]) = 
+  ## Logs an info message to all registered handlers.
+  log(lvlInfo, frmt, args)
+
+template warn*(frmt: string, args: varargs[string, `$`]) = 
+  ## Logs a warning message to all registered handlers.
+  log(lvlWarn, frmt, args)
+
+template error*(frmt: string, args: varargs[string, `$`]) = 
+  ## Logs an error message to all registered handlers.
+  log(lvlError, frmt, args)
+  
+template fatal*(frmt: string, args: varargs[string, `$`]) =  
+  ## Logs a fatal error message to all registered handlers.
+  log(lvlFatal, frmt, args)
+
+
+# --------------
+
+when isMainModule:
+  var L = newConsoleLogger()
+  var fL = newFileLogger("test.log", fmtStr = verboseFmtStr)
+  var rL = newRollingFileLogger("rolling.log", fmtStr = verboseFmtStr)
+  handlers.add(L)
+  handlers.add(fL)
+  handlers.add(rL)
+  for i in 0 .. 25:
+    info("hello" & $i, [])
+  
+
diff --git a/lib/pure/matchers.nim b/lib/pure/matchers.nim
index b57e0c45a..2db7fa660 100644
--- a/lib/pure/matchers.nim
+++ b/lib/pure/matchers.nim
@@ -54,7 +54,7 @@ proc parseInt*(s: string, value: var int, validRange: TSlice[int]) {.
   try:
     discard parseutils.parseInt(s, x, 0)
   except EOverflow:
-    nil
+    discard
   if x in validRange: value = x
 
 when isMainModule:
diff --git a/lib/pure/oids.nim b/lib/pure/oids.nim
index fbe0dda95..b3e74d2a1 100644
--- a/lib/pure/oids.nim
+++ b/lib/pure/oids.nim
@@ -28,7 +28,7 @@ proc hexbyte*(hex: char): int =
   of '0'..'9': result = (ord(hex) - ord('0'))
   of 'a'..'f': result = (ord(hex) - ord('a') + 10)
   of 'A'..'F': result = (ord(hex) - ord('A') + 10)
-  else: nil
+  else: discard
 
 proc parseOid*(str: cstring): TOid =
   ## parses an OID.
diff --git a/lib/pure/os.nim b/lib/pure/os.nim
index 1f42d0d58..bb70f28b6 100644
--- a/lib/pure/os.nim
+++ b/lib/pure/os.nim
@@ -287,12 +287,18 @@ proc osLastError*(): TOSErrorCode =
     result = TOSErrorCode(errno)
 {.pop.}
 
-proc unixToNativePath*(path: string): string {.
+proc unixToNativePath*(path: string, drive=""): string {.
   noSideEffect, rtl, extern: "nos$1".} =
   ## Converts an UNIX-like path to a native one.
   ##
   ## On an UNIX system this does nothing. Else it converts
   ## '/', '.', '..' to the appropriate things.
+  ##
+  ## On systems with a concept of "drives", `drive` is used to determine
+  ## which drive label to use during absolute path conversion.
+  ## `drive` defaults to the drive of the current working directory, and is
+  ## ignored on systems that do not have a concept of "drives".
+
   when defined(unix):
     result = path
   else:
@@ -300,7 +306,10 @@ proc unixToNativePath*(path: string): string {.
     if path[0] == '/':
       # an absolute path
       when doslike:
-        result = r"C:\"
+        if drive != "":
+          result = drive & ":" & DirSep
+        else:
+          result = $DirSep
       elif defined(macos):
         result = "" # must not start with ':'
       else:
@@ -387,6 +396,21 @@ proc existsDir*(dir: string): bool {.rtl, extern: "nos$1", tags: [FReadDir].} =
     var res: TStat
     return stat(dir, res) >= 0'i32 and S_ISDIR(res.st_mode)
 
+proc symlinkExists*(link: string): bool {.rtl, extern: "nos$1",
+                                          tags: [FReadDir].} =
+  ## Returns true iff the symlink `link` exists. Will return true
+  ## regardless of whether the link points to a directory or file.
+  when defined(windows):
+    when useWinUnicode:
+      wrapUnary(a, getFileAttributesW, link)
+    else:
+      var a = getFileAttributesA(link)
+    if a != -1'i32:
+      result = (a and FILE_ATTRIBUTE_REPARSE_POINT) != 0'i32
+  else:
+    var res: TStat
+    return lstat(link, res) >= 0'i32 and S_ISLNK(res.st_mode)
+
 proc fileExists*(filename: string): bool {.inline.} =
   ## Synonym for existsFile
   existsFile(filename)
@@ -1013,7 +1037,7 @@ proc execShellCmd*(command: string): int {.rtl, extern: "nos$1",
   ## the process has finished. To execute a program without having a
   ## shell involved, use the `execProcess` proc of the `osproc`
   ## module.
-  result = c_system(command)
+  result = c_system(command) shr 8
 
 # Environment handling cannot be put into RTL, because the ``envPairs``
 # iterator depends on ``environment``.
@@ -1054,9 +1078,9 @@ when defined(windows):
         while true:
           var eend = strEnd(e)
           add(environment, $e)
-          e = cast[CString](cast[TAddress](eend)+1)
+          e = cast[cstring](cast[TAddress](eend)+1)
           if eend[1] == '\0': break
-        discard FreeEnvironmentStringsA(env)
+        discard freeEnvironmentStringsA(env)
       envComputed = true
 
 else:
@@ -1221,6 +1245,8 @@ iterator walkDir*(dir: string): tuple[kind: TPathComponent, path: string] {.
         if not skipFindData(f):
           if (f.dwFileAttributes and FILE_ATTRIBUTE_DIRECTORY) != 0'i32:
             k = pcDir
+          if (f.dwFileAttributes and FILE_ATTRIBUTE_REPARSE_POINT) != 0'i32:
+            k = succ(k)
           yield (k, dir / extractFilename(getFilename(f)))
         if findNextFile(h, f) == 0'i32: break
       findClose(h)
@@ -1245,6 +1271,10 @@ iterator walkDirRec*(dir: string, filter={pcFile, pcDir}): string {.
   tags: [FReadDir].} =
   ## walks over the directory `dir` and yields for each file in `dir`. The
   ## full path for each file is returned.
+  ## **Warning**:
+  ## Modifying the directory structure while the iterator 
+  ## is traversing may result in undefined behavior! 
+  ## 
   ## Walking is recursive. `filter` controls the behaviour of the iterator:
   ##
   ## ---------------------   ---------------------------------------------
@@ -1336,6 +1366,46 @@ proc copyDir*(source, dest: string) {.rtl, extern: "nos$1",
       copyDir(path, dest / noSource)
     else: discard
 
+proc createSymlink*(src, dest: string) =
+  ## Create a symbolic link at `dest` which points to the item specified
+  ## by `src`. On most operating systems, will fail if a lonk
+  ##
+  ## **Warning**:
+  ## Some OS's (such as Microsoft Windows) restrict the creation 
+  ## of symlinks to root users (administrators).
+  when defined(Windows):
+    let flag = dirExists(src).int32
+    when useWinUnicode:
+      var wSrc = newWideCString(src)
+      var wDst = newWideCString(dest)
+      if createSymbolicLinkW(wDst, wSrc, flag) == 0 or getLastError() != 0:
+        osError(osLastError())
+    else:
+      if createSymbolicLinkA(dest, src, flag) == 0 or getLastError() != 0:
+        osError(osLastError())
+  else:
+    if symlink(src, dest) != 0:
+      osError(osLastError())
+
+proc createHardlink*(src, dest: string) =
+  ## Create a hard link at `dest` which points to the item specified
+  ## by `src`.
+  ##
+  ## **Warning**: Most OS's restrict the creation of hard links to 
+  ## root users (administrators) .
+  when defined(Windows):
+    when useWinUnicode:
+      var wSrc = newWideCString(src)
+      var wDst = newWideCString(dest)
+      if createHardLinkW(wDst, wSrc, nil) == 0:
+        osError(osLastError())
+    else:
+      if createHardLinkA(dest, src, nil) == 0:
+        osError(osLastError())
+  else:
+    if link(src, dest) != 0:
+      osError(osLastError())
+
 proc parseCmdLine*(c: string): seq[string] {.
   noSideEffect, rtl, extern: "nos$1".} =
   ## Splits a command line into several components;
diff --git a/lib/pure/osproc.nim b/lib/pure/osproc.nim
index f764971c4..c0c7f46d7 100644
--- a/lib/pure/osproc.nim
+++ b/lib/pure/osproc.nim
@@ -455,7 +455,7 @@ when defined(Windows) and not defined(useNimRtl):
         ee, wwd, si, procInfo)
     else:
       success = winlean.createProcessA(nil,
-        cmdl, nil, nil, 1, NORMAL_PRIORITY_CLASS, e, wd, SI, ProcInfo)
+        cmdl, nil, nil, 1, NORMAL_PRIORITY_CLASS, e, wd, si, procInfo)
     let lastError = osLastError()
 
     if poParentStreams notin options:
@@ -534,7 +534,7 @@ when defined(Windows) and not defined(useNimRtl):
         NORMAL_PRIORITY_CLASS, nil, nil, si, procInfo)
     else:
       var res = winlean.createProcessA(nil, command, nil, nil, 0,
-        NORMAL_PRIORITY_CLASS, nil, nil, SI, ProcInfo)
+        NORMAL_PRIORITY_CLASS, nil, nil, si, procInfo)
     if res == 0:
       osError(osLastError())
     else:
@@ -791,7 +791,7 @@ elif not defined(useNimRtl):
   proc csystem(cmd: cstring): cint {.nodecl, importc: "system".}
 
   proc execCmd(command: string): int =
-    result = csystem(command)
+    result = csystem(command) shr 8
 
   proc createFdSet(fd: var TFdSet, s: seq[PProcess], m: var int) =
     FD_ZERO(fd)
diff --git a/lib/pure/parsecsv.nim b/lib/pure/parsecsv.nim
index 5970f2090..4b25babec 100644
--- a/lib/pure/parsecsv.nim
+++ b/lib/pure/parsecsv.nim
@@ -149,7 +149,7 @@ proc readRow*(my: var TCsvParser, columns = 0): bool =
           of '\c': my.bufpos = handleCR(my, my.bufpos)
           of '\l': my.bufpos = handleLF(my, my.bufpos)
           else: break
-      of '\0': nil
+      of '\0': discard
       else: error(my, my.bufpos, my.sep & " expected")
       break
   
diff --git a/lib/pure/parsesql.nim b/lib/pure/parsesql.nim
index 31951e966..3f9686e1e 100644
--- a/lib/pure/parsesql.nim
+++ b/lib/pure/parsesql.nim
@@ -79,7 +79,7 @@ proc handleHexChar(c: var TSqlLexer, xi: var int) =
     xi = (xi shl 4) or (ord(c.buf[c.bufpos]) - ord('A') + 10)
     inc(c.bufpos)
   else: 
-    nil
+    discard
 
 proc handleOctChar(c: var TSqlLexer, xi: var int) = 
   if c.buf[c.bufpos] in {'0'..'7'}:
@@ -373,7 +373,7 @@ proc getOperator(c: var TSqlLexer, tok: var TToken) =
     of '+':
       if not trailingPlusMinus and buf[pos+1] notin operators and
            tok.literal.len > 0: break
-    of '*', '<', '>', '=': nil
+    of '*', '<', '>', '=': discard
     else: break
     add(tok.literal, buf[pos])
     inc(pos)
@@ -1120,7 +1120,7 @@ proc rs(n: PSqlNode, s: var string, indent: int,
 proc ra(n: PSqlNode, s: var string, indent: int) =
   if n == nil: return
   case n.kind
-  of nkNone: nil
+  of nkNone: discard
   of nkIdent:
     if allCharsInSet(n.strVal, {'\33'..'\127'}):
       s.add(n.strVal)
diff --git a/lib/pure/smtp.nim b/lib/pure/smtp.nim
index 6a3f65279..88afeb589 100644
--- a/lib/pure/smtp.nim
+++ b/lib/pure/smtp.nim
@@ -66,13 +66,15 @@ proc checkReply(smtp: var TSMTP, reply: string) =
   if not line.string.startswith(reply):
     quitExcpt(smtp, "Expected " & reply & " reply, got: " & line.string)
 
+const compiledWithSsl = defined(ssl)
+
 proc connect*(address: string, port = 25, 
               ssl = false, debug = false): TSMTP =
   ## Establishes a connection with a SMTP server.
   ## May fail with EInvalidReply or with a socket error.
   result.sock = socket()
   if ssl:
-    when defined(ssl):
+    when compiledWithSsl:
       let ctx = newContext(verifyMode = CVerifyNone)
       ctx.wrapSocket(result.sock)
     else:
diff --git a/lib/pure/sockets.nim b/lib/pure/sockets.nim
index fd6403118..76d37879b 100644
--- a/lib/pure/sockets.nim
+++ b/lib/pure/sockets.nim
@@ -311,7 +311,8 @@ when defined(ssl):
       newCTX.SSLCTXSetVerify(SSLVerifyNone, nil)
     if newCTX == nil:
       SSLError()
-    
+
+    discard newCTX.SSLCTXSetMode(SSL_MODE_AUTO_RETRY)
     newCTX.loadCertificates(certFile, keyFile)
     return PSSLContext(newCTX)
 
@@ -1291,14 +1292,14 @@ proc readLine*(socket: TSocket, line: var TaintedString, timeout = -1) {.
     var c: char
     discard waitFor(socket, waited, timeout, 1, "readLine")
     var n = recv(socket, addr(c), 1)
-    if n < 0: osError(osLastError())
+    if n < 0: socket.socketError()
     elif n == 0: return
     if c == '\r':
       discard waitFor(socket, waited, timeout, 1, "readLine")
       n = peekChar(socket, c)
       if n > 0 and c == '\L':
         discard recv(socket, addr(c), 1)
-      elif n <= 0: osError(osLastError())
+      elif n <= 0: socket.socketError()
       addNLIfEmpty()
       return
     elif c == '\L': 
diff --git a/lib/pure/strutils.nim b/lib/pure/strutils.nim
index de8dc5e51..b63224cec 100644
--- a/lib/pure/strutils.nim
+++ b/lib/pure/strutils.nim
@@ -45,6 +45,16 @@ const
   NewLines* = {'\13', '\10'}
     ## the set of characters a newline terminator can start with
 
+  AllChars* = {'\x00'..'\xFF'}
+    ## A set with all the possible characters. Not very useful by its own, you
+    ## can use it to create *inverted* sets to make the ``find()`` proc find
+    ## **invalid** characters in strings. Example:
+    ##
+    ## .. code-block:: nimrod
+    ##   let invalid = AllChars - Digits
+    ##   doAssert "01234".find(invalid) == -1
+    ##   doAssert "01A34".find(invalid) == 2
+
 proc toLower*(c: char): char {.noSideEffect, procvar,
   rtl, extern: "nsuToLowerChar".} =
   ## Converts `c` into lower case. This works only for the letters A-Z.
diff --git a/lib/pure/times.nim b/lib/pure/times.nim
index 6186fcad8..de6c4e4fa 100644
--- a/lib/pure/times.nim
+++ b/lib/pure/times.nim
@@ -211,7 +211,9 @@ proc initInterval*(miliseconds, seconds, minutes, hours, days, months,
   result.months = months
   result.years = years
 
-proc isLeapYear(year: int): bool =
+proc isLeapYear*(year: int): bool =
+  ## returns true if ``year`` is a leap year
+
   if year mod 400 == 0:
     return true
   elif year mod 100 == 0: 
@@ -221,7 +223,9 @@ proc isLeapYear(year: int): bool =
   else:
     return false
 
-proc getDaysInMonth(month: TMonth, year: int): int =
+proc getDaysInMonth*(month: TMonth, year: int): int =
+  ## gets the amount of days in a ``month`` of a ``year``
+
   # http://www.dispersiondesign.com/articles/time/number_of_days_in_a_month
   case month 
   of mFeb: result = if isLeapYear(year): 29 else: 28
diff --git a/lib/pure/xmlparser.nim b/lib/pure/xmlparser.nim
index 16bbe1455..8b8bb3b03 100644
--- a/lib/pure/xmlparser.nim
+++ b/lib/pure/xmlparser.nim
@@ -96,7 +96,7 @@ proc parse(x: var TXmlParser, errors: var seq[string]): PXmlNode =
     ## &entity;
     errors.add(errorMsg(x, "unknown entity: " & x.entityName))
     next(x)
-  of xmlEof: nil
+  of xmlEof: discard
 
 proc parseXml*(s: PStream, filename: string, 
                errors: var seq[string]): PXmlNode = 
@@ -110,7 +110,7 @@ proc parseXml*(s: PStream, filename: string,
     of xmlElementOpen, xmlElementStart: 
       result = parse(x, errors)
       break
-    of xmlComment, xmlWhitespace, xmlSpecial, xmlPI: nil # just skip it
+    of xmlComment, xmlWhitespace, xmlSpecial, xmlPI: discard # just skip it
     of xmlError:
       errors.add(errorMsg(x))
     else:
diff --git a/lib/system.nim b/lib/system.nim
index 09e44a45a..2acb989c5 100644
--- a/lib/system.nim
+++ b/lib/system.nim
@@ -2333,29 +2333,29 @@ when not defined(JS): #and not defined(NimrodVM):
 
 elif defined(JS):
   # Stubs:
-  proc nimGCvisit(d: pointer, op: int) {.compilerRtl.} = nil
-
-  proc GC_disable() = nil
-  proc GC_enable() = nil
-  proc GC_fullCollect() = nil
-  proc GC_setStrategy(strategy: TGC_Strategy) = nil
-  proc GC_enableMarkAndSweep() = nil
-  proc GC_disableMarkAndSweep() = nil
+  proc nimGCvisit(d: pointer, op: int) {.compilerRtl.} = discard
+
+  proc GC_disable() = discard
+  proc GC_enable() = discard
+  proc GC_fullCollect() = discard
+  proc GC_setStrategy(strategy: TGC_Strategy) = discard
+  proc GC_enableMarkAndSweep() = discard
+  proc GC_disableMarkAndSweep() = discard
   proc GC_getStatistics(): string = return ""
   
   proc getOccupiedMem(): int = return -1
   proc getFreeMem(): int = return -1
   proc getTotalMem(): int = return -1
 
-  proc dealloc(p: pointer) = nil
-  proc alloc(size: int): pointer = nil
-  proc alloc0(size: int): pointer = nil
-  proc realloc(p: Pointer, newsize: int): pointer = nil
+  proc dealloc(p: pointer) = discard
+  proc alloc(size: int): pointer = discard
+  proc alloc0(size: int): pointer = discard
+  proc realloc(p: Pointer, newsize: int): pointer = discard
 
-  proc allocShared(size: int): pointer = nil
-  proc allocShared0(size: int): pointer = nil
-  proc deallocShared(p: pointer) = nil
-  proc reallocShared(p: pointer, newsize: int): pointer = nil
+  proc allocShared(size: int): pointer = discard
+  proc allocShared0(size: int): pointer = discard
+  proc deallocShared(p: pointer) = discard
+  proc reallocShared(p: pointer, newsize: int): pointer = discard
 
   when defined(JS):
     include "system/jssys"
@@ -2490,11 +2490,11 @@ proc staticRead*(filename: string): string {.magic: "Slurp".}
   ## ``slurp`` is an alias for ``staticRead``.
 
 proc gorge*(command: string, input = ""): string {.
-  magic: "StaticExec".} = nil
+  magic: "StaticExec".} = discard
   ## This is an alias for ``staticExec``.
 
 proc staticExec*(command: string, input = ""): string {.
-  magic: "StaticExec".} = nil
+  magic: "StaticExec".} = discard
   ## Executes an external process at compile-time.
   ## if `input` is not an empty string, it will be passed as a standard input
   ## to the executed program.
@@ -2561,7 +2561,7 @@ proc instantiationInfo*(index = -1, fullPaths = false): tuple[
   ##         $pos.line, astToStr(code)]
   ##       assert false, "A test expecting failure succeeded?"
   ##     except exception:
-  ##       nil
+  ##       discard
   ##
   ##   proc tester(pos: int): int =
   ##     let
diff --git a/lib/system/excpt.nim b/lib/system/excpt.nim
index a3f6669d4..e50ba7b9f 100644
--- a/lib/system/excpt.nim
+++ b/lib/system/excpt.nim
@@ -23,7 +23,7 @@ else:
   proc MessageBoxA(hWnd: cint, lpText, lpCaption: cstring, uType: int): int32 {.
     header: "<windows.h>", nodecl.}
 
-  proc writeToStdErr(msg: CString) =
+  proc writeToStdErr(msg: cstring) =
     discard MessageBoxA(0, msg, nil, 0)
 
 proc showErrorMessage(data: cstring) =
diff --git a/lib/system/gc.nim b/lib/system/gc.nim
index 820093b3e..b08a6d214 100644
--- a/lib/system/gc.nim
+++ b/lib/system/gc.nim
@@ -802,7 +802,7 @@ when defined(sparc): # For SPARC architecture.
     # Addresses decrease as the stack grows.
     while sp <= max:
       gcMark(gch, sp[])
-      sp = cast[ppointer](cast[TAddress](sp) +% sizeof(pointer))
+      sp = cast[PPointer](cast[TAddress](sp) +% sizeof(pointer))
 
 elif defined(ELATE):
   {.error: "stack marking code is to be written for this architecture".}
diff --git a/lib/system/gc_ms.nim b/lib/system/gc_ms.nim
index 2e3596985..e78a4e5cd 100644
--- a/lib/system/gc_ms.nim
+++ b/lib/system/gc_ms.nim
@@ -1,7 +1,7 @@
 #
 #
 #            Nimrod's Runtime Library
-#        (c) Copyright 2013 Andreas Rumpf
+#        (c) Copyright 2014 Andreas Rumpf
 #
 #    See the file "copying.txt", included in this
 #    distribution, for details about the copyright.
@@ -59,11 +59,11 @@ var
   gch {.rtlThreadVar.}: TGcHeap
 
 when not defined(useNimRtl):
-  InstantiateForRegion(gch.region)
+  instantiateForRegion(gch.region)
 
 template acquire(gch: TGcHeap) = 
   when hasThreadSupport and hasSharedHeap:
-    AcquireSys(HeapLock)
+    acquireSys(HeapLock)
 
 template release(gch: TGcHeap) = 
   when hasThreadSupport and hasSharedHeap:
@@ -90,7 +90,7 @@ proc extGetCellType(c: pointer): PNimType {.compilerproc.} =
   # used for code generation concerning debugging
   result = usrToCell(c).typ
 
-proc unsureAsgnRef(dest: ppointer, src: pointer) {.inline.} =
+proc unsureAsgnRef(dest: PPointer, src: pointer) {.inline.} =
   dest[] = src
 
 proc internRefcount(p: pointer): int {.exportc: "getRefcount".} =
@@ -114,10 +114,10 @@ when BitsPerPage mod (sizeof(int)*8) != 0:
 
 # forward declarations:
 proc collectCT(gch: var TGcHeap)
-proc IsOnStack*(p: pointer): bool {.noinline.}
+proc isOnStack*(p: pointer): bool {.noinline.}
 proc forAllChildren(cell: PCell, op: TWalkOp)
 proc doOperation(p: pointer, op: TWalkOp)
-proc forAllChildrenAux(dest: Pointer, mt: PNimType, op: TWalkOp)
+proc forAllChildrenAux(dest: pointer, mt: PNimType, op: TWalkOp)
 # we need the prototype here for debugging purposes
 
 proc prepareDealloc(cell: PCell) =
@@ -162,19 +162,19 @@ proc forAllSlotsAux(dest: pointer, n: ptr TNimNode, op: TWalkOp) =
     if m != nil: forAllSlotsAux(dest, m, op)
   of nkNone: sysAssert(false, "forAllSlotsAux")
 
-proc forAllChildrenAux(dest: Pointer, mt: PNimType, op: TWalkOp) =
+proc forAllChildrenAux(dest: pointer, mt: PNimType, op: TWalkOp) =
   var d = cast[TAddress](dest)
   if dest == nil: return # nothing to do
   if ntfNoRefs notin mt.flags:
-    case mt.Kind
+    case mt.kind
     of tyRef, tyString, tySequence: # leaf:
-      doOperation(cast[ppointer](d)[], op)
+      doOperation(cast[PPointer](d)[], op)
     of tyObject, tyTuple:
       forAllSlotsAux(dest, mt.node, op)
     of tyArray, tyArrayConstr, tyOpenArray:
       for i in 0..(mt.size div mt.base.size)-1:
         forAllChildrenAux(cast[pointer](d +% i *% mt.base.size), mt.base, op)
-    else: nil
+    else: discard
 
 proc forAllChildren(cell: PCell, op: TWalkOp) =
   gcAssert(cell != nil, "forAllChildren: 1")
@@ -184,7 +184,7 @@ proc forAllChildren(cell: PCell, op: TWalkOp) =
   if marker != nil:
     marker(cellToUsr(cell), op.int)
   else:
-    case cell.typ.Kind
+    case cell.typ.kind
     of tyRef: # common case
       forAllChildrenAux(cellToUsr(cell), cell.typ.base, op)
     of tySequence:
@@ -194,7 +194,7 @@ proc forAllChildren(cell: PCell, op: TWalkOp) =
         for i in 0..s.len-1:
           forAllChildrenAux(cast[pointer](d +% i *% cell.typ.base.size +%
             GenericSeqSize), cell.typ.base, op)
-    else: nil
+    else: discard
 
 proc rawNewObj(typ: PNimType, size: int, gch: var TGcHeap): pointer =
   # generates a new object and sets its reference counter to 0
@@ -466,7 +466,7 @@ else:
         sp = sp +% sizeof(pointer)*8
       # last few entries:
       while sp <=% max:
-        gcMark(gch, cast[ppointer](sp)[])
+        gcMark(gch, cast[PPointer](sp)[])
         sp = sp +% sizeof(pointer)
 
 # ----------------------------------------------------------------------------
@@ -505,7 +505,7 @@ when not defined(useNimRtl):
       else:
         dec(gch.recGcLock)
 
-  proc GC_setStrategy(strategy: TGC_Strategy) = nil
+  proc GC_setStrategy(strategy: TGC_Strategy) = discard
 
   proc GC_enableMarkAndSweep() =
     gch.cycleThreshold = InitialThreshold
diff --git a/lib/windows/winlean.nim b/lib/windows/winlean.nim
index 91c6495ce..5b641185e 100644
--- a/lib/windows/winlean.nim
+++ b/lib/windows/winlean.nim
@@ -195,16 +195,31 @@ else:
     importc: "GetCurrentDirectoryA", dynlib: "kernel32", stdcall.}
   proc setCurrentDirectoryA*(lpPathName: cstring): int32 {.
     importc: "SetCurrentDirectoryA", dynlib: "kernel32", stdcall.}
-  proc createDirectoryA*(pathName: cstring, security: Pointer=nil): int32 {.
+  proc createDirectoryA*(pathName: cstring, security: pointer=nil): int32 {.
     importc: "CreateDirectoryA", dynlib: "kernel32", stdcall.}
   proc removeDirectoryA*(lpPathName: cstring): int32 {.
     importc: "RemoveDirectoryA", dynlib: "kernel32", stdcall.}
   proc setEnvironmentVariableA*(lpName, lpValue: cstring): int32 {.
     stdcall, dynlib: "kernel32", importc: "SetEnvironmentVariableA".}
 
-  proc getModuleFileNameA*(handle: THandle, buf: CString, size: int32): int32 {.
+  proc getModuleFileNameA*(handle: THandle, buf: cstring, size: int32): int32 {.
     importc: "GetModuleFileNameA", dynlib: "kernel32", stdcall.}
-  
+
+when useWinUnicode:
+  proc createSymbolicLinkW*(lpSymlinkFileName, lpTargetFileName: WideCString,
+                         flags: DWORD): int32 {.
+    importc:"CreateSymbolicLinkW", dynlib: "kernel32", stdcall.}
+  proc createHardLinkW*(lpFileName, lpExistingFileName: WideCString,
+                         security: pointer=nil): int32 {.
+    importc:"CreateHardLinkW", dynlib: "kernel32", stdcall.}
+else:
+  proc createSymbolicLinkA*(lpSymlinkFileName, lpTargetFileName: cstring,
+                           flags: DWORD): int32 {.
+    importc:"CreateSymbolicLinkA", dynlib: "kernel32", stdcall.}
+  proc createHardLinkA*(lpFileName, lpExistingFileName: cstring,
+                           security: pointer=nil): int32 {.
+    importc:"CreateHardLinkA", dynlib: "kernel32", stdcall.}
+
 const
   FILE_ATTRIBUTE_ARCHIVE* = 32'i32
   FILE_ATTRIBUTE_COMPRESSED* = 2048'i32
@@ -212,6 +227,7 @@ const
   FILE_ATTRIBUTE_DIRECTORY* = 16'i32
   FILE_ATTRIBUTE_HIDDEN* = 2'i32
   FILE_ATTRIBUTE_READONLY* = 1'i32
+  FILE_ATTRIBUTE_REPARSE_POINT* = 1024'i32
   FILE_ATTRIBUTE_SYSTEM* = 4'i32
   FILE_ATTRIBUTE_TEMPORARY* = 256'i32
 
@@ -284,7 +300,7 @@ else:
                            dwFileAttributes: int32): WINBOOL {.
       stdcall, dynlib: "kernel32", importc: "SetFileAttributesA".}
 
-  proc copyFileA*(lpExistingFileName, lpNewFileName: CString,
+  proc copyFileA*(lpExistingFileName, lpNewFileName: cstring,
                  bFailIfExists: cint): cint {.
     importc: "CopyFileA", stdcall, dynlib: "kernel32".}
 
diff --git a/lib/wrappers/mongo.nim b/lib/wrappers/mongo.nim
index 6673e8ddf..098b4f4d3 100644
--- a/lib/wrappers/mongo.nim
+++ b/lib/wrappers/mongo.nim
@@ -109,11 +109,12 @@ type
     cur*: cstring
     dataSize*: cint
     finished*: TBsonBool
-    stack*: array[0..32 - 1, cint]
+    ownsData*: TBsonBool
+    err*: cint
+    stackSize*: cint
     stackPos*: cint
-    err*: cint       ## Bitfield representing errors or warnings on this buffer 
-    errstr*: cstring ## A string representation of the most recent error
-                     ## or warning. 
+    stackPtr*: ptr csize
+    stack*: array[0..32 - 1, csize]
   
   TDate* = int64
 
@@ -141,6 +142,7 @@ proc print*(TBson: cstring, depth: cint) {.stdcall,
     importc: "bson_print_raw", dynlib: bsondll.}
   ## Print a string representation of a BSON object up to `depth`.
 
+
 proc data*(b: var TBson): cstring{.stdcall, importc: "bson_data", 
                                    dynlib: bsondll.}
   ## Return a pointer to the raw buffer stored by this bson object.
@@ -590,19 +592,30 @@ type
     hosts*: ptr THostPort    ## List of host/ports given by the replica set 
     name*: cstring           ## Name of the replica set. 
     primary_connected*: TBsonBool ## Primary node connection status. 
+
+  TWriteConcern*{.pure, final.} = object ## mongo_write_concern
+    w*: cint
+    wtimeout*: cint
+    j*: cint
+    fsync*: cint
+    mode*: cstring
+    cmd*: TBSon
   
   TMongo*{.pure, final.} = object ## mongo
-    primary*: ptr THostPort   ## Primary connection info. 
-    replset*: ptr TReplSet    ## replset object if connected to a replica set. 
-    sock*: cint               ## Socket file descriptor. 
-    flags*: cint              ## Flags on this connection object. 
-    conn_timeout_ms*: cint    ## Connection timeout in milliseconds. 
-    op_timeout_ms*: cint      ## Read and write timeout in milliseconds. 
-    connected*: TBsonBool     ## Connection status. 
-    err*: TError              ## Most recent driver error code. 
-    errstr*: array[0..128 - 1, char] ## String version of most recent driver error code. 
-    lasterrcode*: cint        ## getlasterror code given by the server on error. 
-    lasterrstr*: cstring      ## getlasterror string generated by server. 
+    primary*: ptr THostPort              ## Primary connection info. 
+    replset*: ptr TReplSet               ## replset object if connected to a replica set. 
+    sock*: cint                          ## Socket file descriptor. 
+    flags*: cint                         ## Flags on this connection object. 
+    conn_timeout_ms*: cint               ## Connection timeout in milliseconds. 
+    op_timeout_ms*: cint                 ## Read and write timeout in milliseconds. 
+    max_bson_size*: cint                 ## Largest BSON object allowed on this connection. 
+    connected*: TBsonBool                ## Connection status. 
+    write_concern*: TWriteConcern        ## The default write concern.
+    err*: TError                         ## Most recent driver error code. 
+    errcode*: cint                       ## Most recent errno or WSAGetLastError().
+    errstr*: array[0..128 - 1, char]     ## String version of most recent driver error code. 
+    lasterrcode*: cint                   ## getlasterror code given by the server on error. 
+    lasterrstr*: array[0..128 - 1, char] ## getlasterror string generated by server. 
   
   TCursor*{.pure, final.} = object ## cursor
     reply*: ptr TReply        ## reply is owned by cursor 
@@ -654,7 +667,11 @@ proc init*(conn: var TMongo){.stdcall, importc: "mongo_init", dynlib: mongodll.}
 
 proc connect*(conn: var TMongo, host: cstring = defaultHost, 
               port: cint = defaultPort): cint {.stdcall, 
-    importc: "mongo_connect", dynlib: mongodll.}
+    importc: "mongo_connect", dynlib: mongodll, deprecated.}
+  ## Connect to a single MongoDB server.
+proc client*(conn: var TMongo, host: cstring = defaultHost, 
+              port: cint = defaultPort): cint {.stdcall, 
+    importc: "mongo_client", dynlib: mongodll.}
   ## Connect to a single MongoDB server.
 
 proc replsetInit*(conn: var TMongo, name: cstring){.stdcall, 
@@ -714,7 +731,8 @@ proc destroy*(conn: var TMongo){.stdcall, importc: "mongo_destroy",
   ## You must always call this function when finished with the connection
   ## object.
 
-proc insert*(conn: var TMongo, ns: cstring, data: var TBson): cint{.stdcall, 
+proc insert*(conn: var TMongo, ns: cstring, data: var TBson,
+             custom_write_concern: ptr TWriteConcern): cint{.stdcall, 
     importc: "mongo_insert", dynlib: mongodll, discardable.}
   ## Insert a BSON document into a MongoDB server. This function
   ## will fail if the supplied BSON struct is not UTF-8 or if
diff --git a/lib/wrappers/openssl.nim b/lib/wrappers/openssl.nim
index af72d04eb..90c398dce 100644
--- a/lib/wrappers/openssl.nim
+++ b/lib/wrappers/openssl.nim
@@ -268,14 +268,22 @@ proc OpenSSL_add_all_algorithms*(){.cdecl, dynlib: DLLUtilName, importc: "OPENSS
 
 proc OPENSSL_config*(configName: cstring){.cdecl, dynlib: DLLSSLName, importc.}
 
-proc CRYPTO_set_mem_functions(a,b,c: pointer){.cdecl, dynlib: DLLSSLName, importc.}
+when not defined(windows):
+  proc CRYPTO_set_mem_functions(a,b,c: pointer){.cdecl, 
+    dynlib: DLLSSLName, importc.}
 
 proc CRYPTO_malloc_init*() =
   when not defined(windows):
     CRYPTO_set_mem_functions(alloc, realloc, dealloc)
 
-when True:
-  nil
+proc SSL_CTX_ctrl*(ctx: PSSL_CTX, cmd: cInt, larg: int, parg: pointer): int{.
+  cdecl, dynlib: DLLSSLName, importc.}
+
+proc SSLCTXSetMode*(ctx: PSSL_CTX, mode: int): int =
+  result = SSL_CTX_ctrl(ctx, SSL_CTRL_MODE, mode, nil)
+
+when true:
+  discard
 else:
   proc SslCtxSetCipherList*(arg0: PSSL_CTX, str: cstring): cInt{.cdecl, 
       dynlib: DLLSSLName, importc.}
@@ -288,7 +296,6 @@ else:
   proc SslCTXCtrl*(ctx: PSSL_CTX, cmd: cInt, larg: int, parg: Pointer): int{.
       cdecl, dynlib: DLLSSLName, importc.}
 
-  proc SSLCTXSetMode*(ctx: PSSL_CTX, mode: int): int
   proc SSLSetMode*(s: PSSL, mode: int): int
   proc SSLCTXGetMode*(ctx: PSSL_CTX): int
   proc SSLGetMode*(s: PSSL): int
@@ -417,15 +424,12 @@ else:
                       enc: cInt){.cdecl, dynlib: DLLUtilName, importc.}
   # implementation
 
-  proc SSLCTXSetMode(ctx: PSSL_CTX, mode: int): int = 
-    Result = SslCTXCtrl(ctx, SSL_CTRL_MODE, mode, nil)
-
   proc SSLSetMode(s: PSSL, mode: int): int = 
-    Result = SSLctrl(s, SSL_CTRL_MODE, mode, nil)
+    result = SSLctrl(s, SSL_CTRL_MODE, mode, nil)
 
   proc SSLCTXGetMode(ctx: PSSL_CTX): int = 
-    Result = SSLCTXctrl(ctx, SSL_CTRL_MODE, 0, nil)
+    result = SSLCTXctrl(ctx, SSL_CTRL_MODE, 0, nil)
 
   proc SSLGetMode(s: PSSL): int = 
-    Result = SSLctrl(s, SSL_CTRL_MODE, 0, nil)
+    result = SSLctrl(s, SSL_CTRL_MODE, 0, nil)
 
diff --git a/readme.md b/readme.md
index 8d42c66db..3eaef0b35 100644
--- a/readme.md
+++ b/readme.md
@@ -61,5 +61,5 @@ allowing you to create commercial applications.
 
 Read copying.txt for more details.
 
-Copyright (c) 2004-2013 Andreas Rumpf.
+Copyright (c) 2004-2014 Andreas Rumpf.
 All rights reserved.
diff --git a/readme.txt b/readme.txt
index 8d42c66db..3eaef0b35 100644
--- a/readme.txt
+++ b/readme.txt
@@ -61,5 +61,5 @@ allowing you to create commercial applications.
 
 Read copying.txt for more details.
 
-Copyright (c) 2004-2013 Andreas Rumpf.
+Copyright (c) 2004-2014 Andreas Rumpf.
 All rights reserved.
diff --git a/tests/collections/ttables.nim b/tests/collections/ttables.nim
new file mode 100644
index 000000000..f374d5504
--- /dev/null
+++ b/tests/collections/ttables.nim
@@ -0,0 +1,22 @@
+import tables
+
+doAssert indexBy(newSeq[int](), proc(x: int):int = x) == initTable[int, int](), "empty int table"
+
+var tbl1 = initTable[int, int]()
+tbl1.add(1,1)
+tbl1.add(2,2)
+doAssert indexBy(@[1,2], proc(x: int):int = x) == tbl1, "int table"
+
+type
+  TElem = object
+    foo: int
+    bar: string
+    
+let
+  elem1 = TElem(foo: 1, bar: "bar")
+  elem2 = TElem(foo: 2, bar: "baz")
+  
+var tbl2 = initTable[string, TElem]()
+tbl2.add("bar", elem1)
+tbl2.add("baz", elem2)
+doAssert indexBy(@[elem1,elem2], proc(x: TElem): string = x.bar) == tbl2, "element table"
diff --git a/tests/exprs/tstmtexprs.nim b/tests/exprs/tstmtexprs.nim
index 497a2f6d0..816e58cb1 100644
--- a/tests/exprs/tstmtexprs.nim
+++ b/tests/exprs/tstmtexprs.nim
@@ -1,5 +1,6 @@
 discard """
-  output: '''(bar: bar)
+  output: '''24
+(bar: bar)
 1244
 6
 abcdefghijklmnopqrstuvwxyz
@@ -8,6 +9,10 @@ abcdefghijklmnopqrstuvwxyz
 
 import strutils
 
+const fac4 = (var x = 1; for i in 1..4: x *= i; x)
+
+echo fac4
+
 when true:
   proc test(foo: proc (x, y: int): bool) =
     echo foo(5, 5)
@@ -69,3 +74,15 @@ proc semiProblem() =
   if false: echo "aye"; echo "indeed"
 
 semiProblem()
+
+
+# bug #844
+
+import json 
+proc parseResponse(): PJsonNode =
+  result = % { "key1": % { "key2": % "value" } }
+  for key, val in result["key1"]:
+    var excMsg = key & "("
+    if (var n=result["key2"]; n != nil):
+      excMsg &= n.str
+    raise newException(ESynch, excMsg)
diff --git a/tests/gc/gcleak4.nim b/tests/gc/gcleak4.nim
index bd7bded28..6f2b8a1fe 100644
--- a/tests/gc/gcleak4.nim
+++ b/tests/gc/gcleak4.nim
@@ -6,7 +6,7 @@ when defined(GC_setMaxPause):
   GC_setMaxPause 2_000
 
 type
-  TExpr = object ## abstract base class for an expression
+  TExpr = object {.inheritable.} ## abstract base class for an expression
   PLiteral = ref TLiteral
   TLiteral = object of TExpr
     x: int
diff --git a/tests/gc/gcleak5.nim b/tests/gc/gcleak5.nim
new file mode 100644
index 000000000..9e2948729
--- /dev/null
+++ b/tests/gc/gcleak5.nim
@@ -0,0 +1,25 @@
+discard """
+  output: "success"
+"""
+
+import os, times
+
+proc main =
+  var i = 0
+  for ii in 0..50_000:
+    #while true:
+    var t = getTime()
+    var g = t.getGMTime()
+    #echo isOnStack(addr g)
+    
+    if i mod 100 == 0:
+      let om = getOccupiedMem()
+      #echo "memory: ", om
+      if om > 100_000: quit "leak"
+     
+    inc(i)
+    sleep(1)
+
+  echo "success"
+
+main()
diff --git a/tests/generics/tgenericrefs.nim b/tests/generics/tgenericrefs.nim
index ef931dfa7..a44b96af9 100644
--- a/tests/generics/tgenericrefs.nim
+++ b/tests/generics/tgenericrefs.nim
@@ -6,6 +6,18 @@ var a: PA[string]
 new(a)
 a.field = "some string"
 
+
+proc someOther[T](len: string): seq[T] = discard
+proc someOther[T](len: int): seq[T] = echo "we"
+
+proc foo[T](x: T) =
+  var s = someOther[T](34)
+  #newSeq[T](34)
+
+foo 23
+
+
+
 when false:
   # Compiles unless you use var a: PA[string]
   type 
diff --git a/tests/iter/tanoniter1.nim b/tests/iter/tanoniter1.nim
index 9db5ab8ec..578749caf 100644
--- a/tests/iter/tanoniter1.nim
+++ b/tests/iter/tanoniter1.nim
@@ -22,11 +22,11 @@ proc factory2(a, b: int): iterator (): int =
       yield x
       inc x
 
-let foo = factory 1, 4
+let foo = factory(1, 4)
 
 for f in foo():
   echo f
 
-let foo2 = factory2 1,2
+let foo2 = factory2(1,2)
 
 for f in foo2(): echo f
diff --git a/tests/macros/tdebugstmt.nim b/tests/macros/tdebugstmt.nim
new file mode 100644
index 000000000..865dc436a
--- /dev/null
+++ b/tests/macros/tdebugstmt.nim
@@ -0,0 +1,29 @@
+discard """
+  output: '''a[0]: 42
+a[1]: 45
+x: some string'''
+"""
+
+import macros
+
+macro debug(n: varargs[expr]): stmt =
+  # `n` is a Nimrod AST that contains the whole macro invocation
+  # this macro returns a list of statements:
+  result = newNimNode(nnkStmtList, n)
+  # iterate over any argument that is passed to this macro:
+  for i in 0..n.len-1:
+    # add a call to the statement list that writes the expression;
+    # `toStrLit` converts an AST to its string representation:
+    add(result, newCall("write", newIdentNode("stdout"), toStrLit(n[i])))
+    # add a call to the statement list that writes ": "
+    add(result, newCall("write", newIdentNode("stdout"), newStrLitNode(": ")))
+    # add a call to the statement list that writes the expressions value:
+    add(result, newCall("writeln", newIdentNode("stdout"), n[i]))
+
+var
+  a: array [0..10, int]
+  x = "some string"
+a[0] = 42
+a[1] = 45
+
+debug(a[0], a[1], x)
diff --git a/tests/macros/tdumpast.nim b/tests/macros/tdumpast.nim
index 55a964327..160e4e194 100644
--- a/tests/macros/tdumpast.nim
+++ b/tests/macros/tdumpast.nim
@@ -2,7 +2,7 @@
 
 import macros
 
-template plus(a, b: expr): expr =
+template plus(a, b: expr): expr {.dirty} =
   a + b
 
 macro call(e: expr): expr =
diff --git a/tests/macros/tdumpast2.nim b/tests/macros/tdumpast2.nim
index c6eab39a9..2a7024a01 100644
--- a/tests/macros/tdumpast2.nim
+++ b/tests/macros/tdumpast2.nim
@@ -7,7 +7,7 @@ proc dumpit(n: PNimrodNode): string {.compileTime.} =
   result = $n.kind
   add(result, "(")
   case n.kind
-  of nnkEmpty: nil # same as nil node in this representation 
+  of nnkEmpty: discard # same as nil node in this representation 
   of nnkNilLit:                  add(result, "nil")
   of nnkCharLit..nnkInt64Lit:    add(result, $n.intVal)
   of nnkFloatLit..nnkFloat64Lit: add(result, $n.floatVal)
diff --git a/tests/macros/tmacrogenerics.nim b/tests/macros/tmacrogenerics.nim
index 5ae59e0da..b886f4fa5 100644
--- a/tests/macros/tmacrogenerics.nim
+++ b/tests/macros/tmacrogenerics.nim
@@ -1,10 +1,8 @@
 discard """
   file: "tmacrogenerics.nim"
   msg: '''
-instantiation 1 with int and float
-instantiation 2 with float and string
-instantiation 3 with string and string
-counter: 3
+instantiation 1 with typedesc and typedesc
+counter: 1
 '''
   output: "int\nfloat\nint\nstring"
 """
diff --git a/tests/macros/tmacrotypes.nim b/tests/macros/tmacrotypes.nim
index 7697dba27..f19aa2ddb 100644
--- a/tests/macros/tmacrotypes.nim
+++ b/tests/macros/tmacrotypes.nim
@@ -1,3 +1,7 @@
+discard """
+  disabled: true
+"""
+
 import macros, typetraits
 
 macro checkType(ex, expected: expr): stmt {.immediate.} =
diff --git a/tests/macros/tmemit.nim b/tests/macros/tmemit.nim
index e4bb2daed..6fb2f3b65 100644
--- a/tests/macros/tmemit.nim
+++ b/tests/macros/tmemit.nim
@@ -1,5 +1,5 @@
 discard """
-  out: '''HELLO WORLD'''
+  output: '''HELLO WORLD'''
 """
 
 import macros, strutils
diff --git a/tests/macros/tstringinterp.nim b/tests/macros/tstringinterp.nim
index f030213e0..a500ed56e 100644
--- a/tests/macros/tstringinterp.nim
+++ b/tests/macros/tstringinterp.nim
@@ -9,7 +9,7 @@ proc concat(strings: varargs[string]): string =
   result = newString(0)
   for s in items(strings): result.add(s)
 
-template ProcessInterpolations(e: expr) =
+template processInterpolations(e: expr) =
   var s = e[1].strVal
   for f in interpolatedFragments(s):
     case f.kind
@@ -35,7 +35,7 @@ macro formatStyleInterpolation(e: expr): expr =
   proc addDollar() =
     formatString.add("$$")
     
-  ProcessInterpolations(e)
+  processInterpolations(e)
 
   result = parseExpr("\"x\" % [y]")
   result[1].strVal = formatString
@@ -50,7 +50,7 @@ macro concatStyleInterpolation(e: expr): expr =
   proc addExpr(e: PNimrodNode) = args.add(e)
   proc addDollar()             = args.add(newStrLitNode"$")
 
-  ProcessInterpolations(e)
+  processInterpolations(e)
 
   result = newCall("concat", args)
 
diff --git a/tests/parser/tcommand_as_expr.nim b/tests/parser/tcommand_as_expr.nim
index f6868a2fc..22c49ab3f 100644
--- a/tests/parser/tcommand_as_expr.nim
+++ b/tests/parser/tcommand_as_expr.nim
@@ -1,12 +1,23 @@
 discard """
-  output: "12"
+  output: '''140
+5-120-120
+359'''
 """
+#import math
+
+proc optarg(x:int, y:int = 0):int = x + 3 * y
+proc singlearg(x:int):int = 20*x
+echo optarg 1, singlearg 2
+
 
 proc foo(x: int): int = x-1
 proc foo(x, y: int): int = x-y
 
-let x = foo 7.foo,  # comment here
-            foo(1, foo 8)
-#  12 =       6     -     -6
-echo x
+let x = optarg foo 7.foo
+let y = singlearg foo(1, foo 8)
+let z = singlearg 1.foo foo 8
+    
+echo x, y, z
 
+let a = [2,4,8].map do (d:int) -> int: d + 1
+echo a[0], a[1], a[2]
\ No newline at end of file
diff --git a/tests/sets/testequivalence.nim b/tests/sets/testequivalence.nim
new file mode 100644
index 000000000..7c5d9e3e9
--- /dev/null
+++ b/tests/sets/testequivalence.nim
@@ -0,0 +1,15 @@
+discard """
+  output: ''''''
+"""
+import unittest
+import sets
+
+doAssert(toSet(@[1,2,3]) <= toSet(@[1,2,3,4]), "equivalent or subset")
+doAssert(toSet(@[1,2,3]) <= toSet(@[1,2,3]), "equivalent or subset")
+doAssert((not(toSet(@[1,2,3]) <= toSet(@[1,2]))), "equivalent or subset")
+doAssert(toSet(@[1,2,3]) <= toSet(@[1,2,3,4]), "strict subset")
+doAssert((not(toSet(@[1,2,3]) < toSet(@[1,2,3]))), "strict subset")
+doAssert((not(toSet(@[1,2,3]) < toSet(@[1,2]))), "strict subset")
+doAssert((not(toSet(@[1,2,3]) == toSet(@[1,2,3,4]))), "==")
+doAssert(toSet(@[1,2,3]) == toSet(@[1,2,3]), "==")
+doAssert((not(toSet(@[1,2,3]) == toSet(@[1,2]))), "==")
diff --git a/tests/specials.nim b/tests/specials.nim
deleted file mode 100644
index 9ced66bbb..000000000
--- a/tests/specials.nim
+++ /dev/null
@@ -1,238 +0,0 @@
-#
-#
-#            Nimrod Tester
-#        (c) Copyright 2013 Andreas Rumpf
-#
-#    See the file "copying.txt", included in this
-#    distribution, for details about the copyright.
-#
-
-## Include for the tester that contains test suites that test special features
-## of the compiler.
-
-# included from tester.nim
-# ---------------- ROD file tests ---------------------------------------------
-
-const
-  rodfilesDir = "tests/rodfiles"
-  nimcacheDir = rodfilesDir / "nimcache"
-
-proc delNimCache() =
-  try:
-    removeDir(nimcacheDir)
-  except EOS:
-    echo "[Warning] could not delete: ", nimcacheDir
-    
-proc runRodFiles(r: var TResults, options: string) =
-  template test(filename: expr): stmt =
-    runSingleTest(r, rodfilesDir / filename, options)
-  
-  delNimCache()
-  
-  # test basic recompilation scheme:
-  test "hallo"
-  test "hallo"
-  # test incremental type information:
-  test "hallo2"
-  delNimCache()
-  
-  # test type converters:
-  test "aconv"
-  test "bconv"
-  delNimCache()
-  
-  # test G, A, B example from the documentation; test init sections:
-  test "deada"
-  test "deada2"
-  delNimCache()
-  
-  # test method generation:
-  test "bmethods"
-  test "bmethods2"
-  delNimCache()
-  
-  # test generics:
-  test "tgeneric1"
-  test "tgeneric2"
-  delNimCache()
-
-proc compileRodFiles(r: var TResults, options: string) =
-  template test(filename: expr): stmt =
-    compileSingleTest(r, rodfilesDir / filename, options)
-    
-  delNimCache()
-  # test DLL interfacing:
-  test "gtkex1"
-  test "gtkex2"
-  delNimCache()
-
-# --------------------- DLL generation tests ----------------------------------
-
-proc safeCopyFile(src, dest: string) =
-  try:
-    copyFile(src, dest)
-  except EOS:
-    echo "[Warning] could not copy: ", src, " to ", dest
-
-proc runBasicDLLTest(c, r: var TResults, options: string) =
-  compileSingleTest c, "lib/nimrtl.nim", options & " --app:lib -d:createNimRtl"
-  compileSingleTest c, "tests/dll/server.nim", 
-    options & " --app:lib -d:useNimRtl"
-  
-  when defined(Windows): 
-    # windows looks in the dir of the exe (yay!):
-    var nimrtlDll = DynlibFormat % "nimrtl"
-    safeCopyFile("lib" / nimrtlDll, "tests/dll" / nimrtlDll)
-  else:
-    # posix relies on crappy LD_LIBRARY_PATH (ugh!):
-    var libpath = getenv"LD_LIBRARY_PATH".string
-    if peg"\i '/nimrod' (!'/')* '/lib'" notin libpath:
-      echo "[Warning] insufficient LD_LIBRARY_PATH"
-    var serverDll = DynlibFormat % "server"
-    safeCopyFile("tests/dll" / serverDll, "lib" / serverDll)
-  
-  runSingleTest r, "tests/dll/client.nim", options & " -d:useNimRtl"
-
-proc runDLLTests(r: var TResults, options: string) =
-  # dummy compile result:
-  var c = initResults()
-  
-  runBasicDLLTest c, r, options
-  runBasicDLLTest c, r, options & " -d:release"
-  runBasicDLLTest c, r, options & " --gc:boehm"
-  runBasicDLLTest c, r, options & " -d:release --gc:boehm"
-
-proc compileDLLTests(r: var TResults, options: string) =
-  # dummy run result:
-  var c = initResults()
-  
-  runBasicDLLTest r, c, options
-  runBasicDLLTest r, c, options & " -d:release"
-  runBasicDLLTest r, c, options & " --gc:boehm"
-  runBasicDLLTest r, c, options & " -d:release --gc:boehm"
-
-# ------------------------------ GC tests -------------------------------------
-
-proc runGcTests(r: var TResults, options: string) =
-  template test(filename: expr): stmt =
-    runSingleTest(r, "tests/gc" / filename, options)
-    runSingleTest(r, "tests/gc" / filename, options & " -d:release")
-    runSingleTest(r, "tests/gc" / filename, options &
-                  " -d:release -d:useRealtimeGC")
-    runSingleTest(r, "tests/gc" / filename, options &
-                  " --gc:markAndSweep")
-    runSingleTest(r, "tests/gc" / filename, options &
-                  " -d:release --gc:markAndSweep")
-  
-  test "gcbench"
-  test "gcleak"
-  test "gcleak2"
-  test "gctest"
-  test "gcleak3"
-  test "weakrefs"
-  test "cycleleak"
-  test "closureleak"
-
-# ------------------------- threading tests -----------------------------------
-
-proc runThreadTests(r: var TResults, options: string) =
-  template test(filename: expr): stmt =
-    runSingleTest(r, "tests/threads" / filename, options)
-    runSingleTest(r, "tests/threads" / filename, options & " -d:release")
-    runSingleTest(r, "tests/threads" / filename, options & " --tlsEmulation:on")
-  
-  test "tactors"
-  test "tactors2"
-  test "threadex"
-  # deactivated because output capturing still causes problems sometimes:
-  #test "trecursive_actor"
-  #test "threadring"
-  #test "tthreadanalysis"
-  #test "tthreadsort"
-
-proc rejectThreadTests(r: var TResults, options: string) =
-  rejectSingleTest(r, "tests/threads/tthreadanalysis2", options)
-  rejectSingleTest(r, "tests/threads/tthreadanalysis3", options)
-  rejectSingleTest(r, "tests/threads/tthreadheapviolation1", options)
-
-# ------------------------- IO tests ------------------------------------------
-
-proc runIOTests(r: var TResults, options: string) =
-  # We need readall_echo to be compiled for this test to run.
-  # dummy compile result:
-  var c = initResults()
-  compileSingleTest(c, "tests/system/helpers/readall_echo", options)
-  runSingleTest(r, "tests/system/io", options)
-  
-# ------------------------- debugger tests ------------------------------------
-
-proc compileDebuggerTests(r: var TResults, options: string) =
-  compileSingleTest(r, "tools/nimgrep", options & 
-                    " --debugger:on")
-
-# ------------------------- JS tests ------------------------------------------
-
-proc runJsTests(r: var TResults, options: string) =
-  template test(filename: expr): stmt =
-    runSingleTest(r, filename, options & " -d:nodejs", targetJS)
-    runSingleTest(r, filename, options & " -d:nodejs -d:release", targetJS)
-    
-  for t in os.walkFiles("tests/js/t*.nim"):
-    test(t)
-  for testfile in ["texceptions", "texcpt1", "texcsub", "tfinally",
-                   "tfinally2", "tfinally3", "tactiontable", "tmultim1",
-                   "tmultim3", "tmultim4"]:
-    test "tests/run/" & testfile & ".nim"
-
-# ------------------------- register special tests here -----------------------
-proc runSpecialTests(r: var TResults, options: string) =
-  runRodFiles(r, options)
-  #runDLLTests(r, options)
-  runGCTests(r, options)
-  runThreadTests(r, options & " --threads:on")
-  runIOTests(r, options)
-
-  for t in os.walkFiles("tests/patterns/t*.nim"):
-    runSingleTest(r, t, options)
-  for t in ["lib/packages/docutils/highlite"]:
-    runSingleTest(r, t, options)
-
-proc rejectSpecialTests(r: var TResults, options: string) =
-  rejectThreadTests(r, options)
-
-proc findMainFile(dir: string): string =
-  # finds the file belonging to ".nimrod.cfg"; if there is no such file
-  # it returns the some ".nim" file if there is only one: 
-  const cfgExt = ".nimrod.cfg"
-  result = ""
-  var nimFiles = 0
-  for kind, file in os.walkDir(dir):
-    if kind == pcFile:
-      if file.endsWith(cfgExt): return file[.. -(cfgExt.len+1)] & ".nim"
-      elif file.endsWith(".nim"):
-        if result.len == 0: result = file
-        inc nimFiles
-  if nimFiles != 1: result.setlen(0)
-
-proc compileManyLoc(r: var TResults, options: string) =
-  for kind, dir in os.walkDir("tests/manyloc"):
-    if kind == pcDir:
-      let mainfile = findMainFile(dir)
-      if mainfile != ".nim":
-        compileSingleTest(r, mainfile, options)
-
-proc compileSpecialTests(r: var TResults, options: string) =
-  compileRodFiles(r, options)
-
-  compileSingleTest(r, "compiler/c2nim/c2nim.nim", options)
-  compileSingleTest(r, "compiler/pas2nim/pas2nim.nim", options)
-
-  compileDLLTests(r, options)
-  compileDebuggerTests(r, options)
-  
-  compileManyLoc(r, options)
-
-  #var given = callCompiler("nimrod i", "nimrod i", options)
-  #r.addResult("nimrod i", given.msg, if given.err: reFailure else: reSuccess)
-  #if not given.err: inc(r.passed)
-
diff --git a/tests/stdlib/talgorithm.nim b/tests/stdlib/talgorithm.nim
new file mode 100644
index 000000000..7ab652c82
--- /dev/null
+++ b/tests/stdlib/talgorithm.nim
@@ -0,0 +1,8 @@
+import algorithm
+
+doAssert product[int](newSeq[seq[int]]()) == newSeq[seq[int]](), "empty input"
+doAssert product[int](@[newSeq[int](), @[], @[]]) == newSeq[seq[int]](), "bit more empty input"
+doAssert product(@[@[1,2]]) == @[@[1,2]], "a simple case of one element"
+doAssert product(@[@[1,2], @[3,4]]) == @[@[2,4],@[1,4],@[2,3],@[1,3]], "two elements"
+doAssert product(@[@[1,2], @[3,4], @[5,6]]) == @[@[2,4,6],@[1,4,6],@[2,3,6],@[1,3,6], @[2,4,5],@[1,4,5],@[2,3,5],@[1,3,5]], "three elements"
+doAssert product(@[@[1,2], @[]]) == newSeq[seq[int]](), "two elements, but one empty"
diff --git a/tests/template/tprefer_immediate.nim b/tests/template/tprefer_immediate.nim
new file mode 100644
index 000000000..578f447b0
--- /dev/null
+++ b/tests/template/tprefer_immediate.nim
@@ -0,0 +1,17 @@
+discard """
+  output: '''immediate'''
+"""
+
+# Test that immediate templates are preferred over non-immediate templates
+
+template foo(a, b: expr) = echo "foo expr"
+
+template foo(a, b: int) = echo "foo int"
+template foo(a, b: float) = echo "foo float"
+template foo(a, b: string) = echo "foo string"
+template foo(a, b: expr) {.immediate.} = echo "immediate"
+template foo(a, b: bool) = echo "foo bool"
+template foo(a, b: char) = echo "foo char"
+
+foo(undeclaredIdentifier, undeclaredIdentifier2)
+
diff --git a/tests/testament/backend.nim b/tests/testament/backend.nim
index bc1f92eba..5199bb9d6 100644
--- a/tests/testament/backend.nim
+++ b/tests/testament/backend.nim
@@ -49,10 +49,10 @@ proc createDb() =
   #  """, [])
 
 type
-  MachineId = distinct int64
+  MachineId* = distinct int64
   CommitId = distinct int64
 
-proc `$`(id: MachineId): string {.borrow.}
+proc `$`*(id: MachineId): string {.borrow.}
 proc `$`(id: CommitId): string {.borrow.}
 
 var
@@ -61,7 +61,7 @@ var
 
 proc `()`(cmd: string{lit}): string = cmd.execProcess.string.strip
 
-proc getMachine: MachineId =
+proc getMachine*(db: TDbConn): MachineId =
   var name = "hostname"()
   if name.len == 0:
     name = when defined(posix): getenv"HOSTNAME".string
@@ -76,7 +76,7 @@ proc getMachine: MachineId =
     result = db.insertId(sql"insert into Machine(name, os, cpu) values (?,?,?)",
                          name, system.hostOS, system.hostCPU).MachineId
 
-proc getCommit: CommitId =
+proc getCommit(db: TDbConn): CommitId =
   const commLen = "commit ".len
   let hash = "git log -n 1"()[commLen..commLen+10]
   let branch = "git symbolic-ref --short HEAD"()
@@ -115,7 +115,7 @@ proc open*() =
   db = open(connection="testament.db", user="testament", password="",
             database="testament")
   createDb()
-  thisMachine = getMachine()
-  thisCommit = getCommit()
+  thisMachine = getMachine(db)
+  thisCommit = getCommit(db)
 
 proc close*() = close(db)
diff --git a/tests/testament/categories.nim b/tests/testament/categories.nim
index 5dd841447..442dd1212 100644
--- a/tests/testament/categories.nim
+++ b/tests/testament/categories.nim
@@ -123,9 +123,14 @@ proc gcTests(r: var TResults, cat: Category, options: string) =
   test "gcleak2"
   test "gctest"
   test "gcleak3"
+  test "gcleak4"
+  test "gcleak5"
   test "weakrefs"
   test "cycleleak"
   test "closureleak"
+  test "refarrayleak"
+  test "stackrefleak"
+  
 
 # ------------------------- threading tests -----------------------------------
 
diff --git a/tests/testament/htmlgen.nim b/tests/testament/htmlgen.nim
index bc2d8bd37..eb674a171 100644
--- a/tests/testament/htmlgen.nim
+++ b/tests/testament/htmlgen.nim
@@ -159,3 +159,22 @@ proc generateHtml*(filename: string, commit: int) =
   outfile.write(HtmlEnd)
   close(db)
   close(outfile)
+
+proc generateJson*(filename: string, commit: int) =
+  const selRow = """select count(*),
+                           sum(result = 'reSuccess'), 
+                           sum(result = 'reIgnored')
+                    from TestResult
+                    where [commit] = ? and machine = ?
+                    order by category"""
+  var db = open(connection="testament.db", user="testament", password="",
+                database="testament")
+  let lastCommit = db.getCommit(commit)
+
+  var outfile = open(filename, fmWrite)
+
+  let data = db.getRow(sql(selRow), lastCommit, $backend.getMachine(db))
+
+  outfile.writeln("""{"total": $#, "passed": $#, "skipped": $#}""" % data)
+  close(db)
+  close(outfile)
diff --git a/tests/testament/tester.nim b/tests/testament/tester.nim
index 54a6de2d0..fac97cf2a 100644
--- a/tests/testament/tester.nim
+++ b/tests/testament/tester.nim
@@ -208,20 +208,6 @@ proc makeTest(test, options: string, cat: Category, action = actionCompile,
 
 include categories
 
-proc toJson(res: TResults): PJsonNode =
-  result = newJObject()
-  result["total"] = newJInt(res.total)
-  result["passed"] = newJInt(res.passed)
-  result["skipped"] = newJInt(res.skipped)
-
-proc outputJson(reject, compile, run: TResults) =
-  var doc = newJObject()
-  doc["reject"] = toJson(reject)
-  doc["compile"] = toJson(compile)
-  doc["run"] = toJson(run)
-  var s = pretty(doc)
-  writeFile(jsonFile, s)
-
 # proc runCaasTests(r: var TResults) =
 #   for test, output, status, mode in caasTestsRunner():
 #     r.addResult(test, "", output & "-> " & $mode,
@@ -259,6 +245,7 @@ proc main() =
     var commit = 0
     discard parseInt(p.cmdLineRest.string, commit)
     generateHtml(resultsFile, commit)
+    generateJson(jsonFile, commit)
   else:
     quit usage
 
diff --git a/tests/tester.nim b/tests/tester.nim
deleted file mode 100644
index 0e125b1bb..000000000
--- a/tests/tester.nim
+++ /dev/null
@@ -1,457 +0,0 @@
-#
-#
-#            Nimrod Tester
-#        (c) Copyright 2013 Andreas Rumpf
-#
-#    See the file "copying.txt", included in this
-#    distribution, for details about the copyright.
-#
-
-## This program verifies Nimrod against the testcases.
-
-import
-  parseutils, strutils, pegs, os, osproc, streams, parsecfg, browsers, json,
-  marshal, cgi, parseopt #, caas
-
-const
-  cmdTemplate = r"nimrod cc --hints:on $# $#"
-  resultsFile = "testresults.html"
-  jsonFile = "testresults.json"
-  Usage = "usage: tester [--print] " &
-                    "reject|compile|run|" &
-                    "merge|special|rodfiles| [nimrod options]\n" &
-          "   or: tester test|comp|rej singleTest"
-
-type
-  TTestAction = enum
-    actionCompile, actionRun, actionReject
-  TResultEnum = enum
-    reNimrodcCrash,     # nimrod compiler seems to have crashed
-    reMsgsDiffer,       # error messages differ
-    reFilesDiffer,      # expected and given filenames differ
-    reLinesDiffer,      # expected and given line numbers differ
-    reOutputsDiffer,
-    reExitcodesDiffer,
-    reInvalidPeg,
-    reCodegenFailure,
-    reCodeNotFound,
-    reExeNotFound,
-    reIgnored,          # test is ignored
-    reSuccess           # test was successful
-
-  TTarget = enum
-    targetC, targetCpp, targetObjC, targetJS
-
-  TSpec = object
-    action: TTestAction
-    file, cmd: string
-    outp: string
-    line, exitCode: int
-    msg: string
-    ccodeCheck: string
-    err: TResultEnum
-    substr: bool
-  TResults = object
-    total, passed, skipped: int
-    data: string
-
-# ----------------------- Spec parser ----------------------------------------
-
-when not defined(parseCfgBool):
-  # candidate for the stdlib:
-  proc parseCfgBool(s: string): bool =
-    case normalize(s)
-    of "y", "yes", "true", "1", "on": result = true
-    of "n", "no", "false", "0", "off": result = false
-    else: raise newException(EInvalidValue, "cannot interpret as a bool: " & s)
-
-proc extractSpec(filename: string): string =
-  const tripleQuote = "\"\"\""
-  var x = readFile(filename).string
-  var a = x.find(tripleQuote)
-  var b = x.find(tripleQuote, a+3)
-  # look for """ only in the first section
-  if a >= 0 and b > a and a < 40:
-    result = x.substr(a+3, b-1).replace("'''", tripleQuote)
-  else:
-    #echo "warning: file does not contain spec: " & filename
-    result = ""
-
-when not defined(nimhygiene):
-  {.pragma: inject.}
-
-template parseSpecAux(fillResult: stmt) {.immediate.} =
-  var ss = newStringStream(extractSpec(filename))
-  var p {.inject.}: TCfgParser
-  open(p, ss, filename, 1)
-  while true:
-    var e {.inject.} = next(p)
-    case e.kind
-    of cfgEof: break
-    of cfgSectionStart, cfgOption, cfgError:
-      echo ignoreMsg(p, e)
-    of cfgKeyValuePair:
-      fillResult
-  close(p)
-
-proc parseSpec(filename: string): TSpec =
-  result.file = filename
-  result.msg = ""
-  result.outp = ""
-  result.ccodeCheck = ""
-  result.cmd = cmdTemplate
-  parseSpecAux:
-    case normalize(e.key)
-    of "action":
-      case e.value.normalize
-      of "compile": result.action = actionCompile
-      of "run": result.action = actionRun
-      of "reject": result.action = actionReject
-      else: echo ignoreMsg(p, e)
-    of "file": result.file = e.value
-    of "line": discard parseInt(e.value, result.line)
-    of "output": result.outp = e.value
-    of "outputsub":
-      result.outp = e.value
-      result.substr = true
-    of "exitcode": 
-      discard parseInt(e.value, result.exitCode)
-    of "errormsg", "msg": result.msg = e.value
-    of "disabled":
-      if parseCfgBool(e.value): result.err = reIgnored
-    of "cmd": result.cmd = e.value
-    of "ccodecheck": result.ccodeCheck = e.value
-    else: echo ignoreMsg(p, e)
-
-# ----------------------------------------------------------------------------
-
-let
-  pegLineError = 
-    peg"{[^(]*} '(' {\d+} ', ' \d+ ') ' ('Error'/'Warning') ':' \s* {.*}"
-  pegOtherError = peg"'Error:' \s* {.*}"
-  pegSuccess = peg"'Hint: operation successful'.*"
-  pegOfInterest = pegLineError / pegOtherError
-
-proc callCompiler(cmdTemplate, filename, options: string): TSpec =
-  let c = parseCmdLine(cmdTemplate % [options, filename])
-  var p = startProcess(command=c[0], args=c[1.. -1],
-                       options={poStdErrToStdOut, poUseShell})
-  let outp = p.outputStream
-  var suc = ""
-  var err = ""
-  var x = newStringOfCap(120)
-  while outp.readLine(x.TaintedString) or running(p):
-    if x =~ pegOfInterest:
-      # `err` should contain the last error/warning message
-      err = x
-    elif x =~ pegSuccess:
-      suc = x
-  close(p)
-  result.msg = ""
-  result.file = ""
-  result.outp = ""
-  result.line = -1
-  if err =~ pegLineError:
-    result.file = extractFilename(matches[0])
-    result.line = parseInt(matches[1])
-    result.msg = matches[2]
-  elif err =~ pegOtherError:
-    result.msg = matches[0]
-  elif suc =~ pegSuccess:
-    result.err = reSuccess
-
-proc initResults: TResults =
-  result.total = 0
-  result.passed = 0
-  result.skipped = 0
-  result.data = ""
-
-proc readResults(filename: string): TResults =
-  result = marshal.to[TResults](readFile(filename).string)
-
-proc writeResults(filename: string, r: TResults) =
-  writeFile(filename, $$r)
-
-proc `$`(x: TResults): string =
-  result = ("Tests passed: $1 / $3 <br />\n" &
-            "Tests skipped: $2 / $3 <br />\n") %
-            [$x.passed, $x.skipped, $x.total]
-
-proc colorResult(r: TResultEnum): string =
-  case r
-  of reIgnored: result = "<span style=\"color:fuchsia\">ignored</span>"
-  of reSuccess: result = "<span style=\"color:green\">yes</span>"
-  else: result = "<span style=\"color:red\">no</span>"
-
-const
-  TableHeader4 = "<table border=\"1\"><tr><td>Test</td><td>Expected</td>" &
-                 "<td>Given</td><td>Success</td></tr>\n"
-  TableHeader3 = "<table border=\"1\"><tr><td>Test</td>" &
-                 "<td>Given</td><td>Success</td></tr>\n"
-  TableFooter = "</table>\n"
-  HtmlBegin = """<html>
-    <head> 
-      <title>Test results</title>
-      <style type="text/css">
-      <!--""" & slurp("css/boilerplate.css") & "\n" &
-                slurp("css/style.css") &
-      """-->
-    </style>
-
-    </head>
-    <body>"""
-  
-  HtmlEnd = "</body></html>"
-
-proc td(s: string): string =
-  result = s.substr(0, 200).XMLEncode
-
-proc addResult(r: var TResults, test, expected, given: string,
-               success: TResultEnum) =
-  r.data.addf("<tr><td>$#</td><td>$#</td><td>$#</td><td>$#</td></tr>\n", [
-    XMLEncode(test), td(expected), td(given), success.colorResult])
-
-proc addResult(r: var TResults, test, given: string,
-               success: TResultEnum) =
-  r.data.addf("<tr><td>$#</td><td>$#</td><td>$#</td></tr>\n", [
-    XMLEncode(test), td(given), success.colorResult])
-
-proc listResults(reject, compile, run: TResults) =
-  var s = HtmlBegin
-  s.add("<h1>Tests to Reject</h1>\n")
-  s.add($reject)
-  s.add(TableHeader4 & reject.data & TableFooter)
-  s.add("<br /><br /><br /><h1>Tests to Compile</h1>\n")
-  s.add($compile)
-  s.add(TableHeader3 & compile.data & TableFooter)
-  s.add("<br /><br /><br /><h1>Tests to Run</h1>\n")
-  s.add($run)
-  s.add(TableHeader4 & run.data & TableFooter)
-  s.add(HtmlEnd)
-  writeFile(resultsFile, s)
-
-proc cmpMsgs(r: var TResults, expected, given: TSpec, test: string) =
-  if strip(expected.msg) notin strip(given.msg):
-    r.addResult(test, expected.msg, given.msg, reMsgsDiffer)
-  elif extractFilename(expected.file) != extractFilename(given.file) and
-      "internal error:" notin expected.msg:
-    r.addResult(test, expected.file, given.file, reFilesDiffer)
-  elif expected.line != given.line and expected.line != 0:
-    r.addResult(test, $expected.line, $given.line, reLinesDiffer)
-  else:
-    r.addResult(test, expected.msg, given.msg, reSuccess)
-    inc(r.passed)
-
-proc rejectSingleTest(r: var TResults, test, options: string) =
-  let test = test.addFileExt(".nim")
-  var t = extractFilename(test)
-  inc(r.total)
-  echo t
-  var expected = parseSpec(test)
-  if expected.err == reIgnored:
-    r.addResult(t, "", "", reIgnored)
-    inc(r.skipped)
-  else:
-    var given = callCompiler(expected.cmd, test, options)
-    cmpMsgs(r, expected, given, t)
-
-proc reject(r: var TResults, dir, options: string) =
-  ## handle all the tests that the compiler should reject
-  for test in os.walkFiles(dir / "t*.nim"): rejectSingleTest(r, test, options)
-
-proc codegenCheck(test, check, ext: string, given: var TSpec) =
-  if check.len > 0:
-    try:
-      let (path, name, ext2) = test.splitFile
-      echo path / "nimcache" / name.changeFileExt(ext)
-      let contents = readFile(path / "nimcache" / name.changeFileExt(ext)).string
-      if contents.find(check.peg) < 0:
-        given.err = reCodegenFailure
-    except EInvalidValue:
-      given.err = reInvalidPeg
-    except EIO:
-      given.err = reCodeNotFound
-  
-proc codegenChecks(test: string, expected: TSpec, given: var TSpec) =
-  codegenCheck(test, expected.ccodeCheck, ".c", given)
-  
-proc compile(r: var TResults, pattern, options: string) =
-  for test in os.walkFiles(pattern):
-    let t = extractFilename(test)
-    echo t
-    inc(r.total)
-    let expected = parseSpec(test)
-    if expected.err == reIgnored:
-      r.addResult(t, "", reIgnored)
-      inc(r.skipped)
-    else:
-      var given = callCompiler(expected.cmd, test, options)
-      if given.err == reSuccess:
-        codegenChecks(test, expected, given)
-      r.addResult(t, given.msg, given.err)
-      if given.err == reSuccess: inc(r.passed)
-
-proc compileSingleTest(r: var TResults, test, options: string) =
-  # does not extract the spec because the file is not supposed to have any
-  let test = test.addFileExt(".nim")
-  let t = extractFilename(test)
-  inc(r.total)
-  echo t
-  let given = callCompiler(cmdTemplate, test, options)
-  r.addResult(t, given.msg, given.err)
-  if given.err == reSuccess: inc(r.passed)
-
-proc runSingleTest(r: var TResults, test, options: string, target: TTarget) =
-  var test = test.addFileExt(".nim")
-  var t = extractFilename(test)
-  echo t
-  inc(r.total)
-  var expected = parseSpec(test)
-  if expected.err == reIgnored:
-    r.addResult(t, "", "", reIgnored)
-    inc(r.skipped)
-  else:
-    var given = callCompiler(expected.cmd, test, options)
-    if given.err != reSuccess:
-      r.addResult(t, "", given.msg, given.err)
-    else:
-      var exeFile: string
-      if target == targetC:
-        exeFile = changeFileExt(test, ExeExt)
-      else:
-        let (dir, file, ext) = splitFile(test)
-        exeFile = dir / "nimcache" / file & ".js"
-      
-      if existsFile(exeFile):
-        var (buf, exitCode) = execCmdEx(
-          (if target==targetJS: "node " else: "") & exeFile)
-        if exitCode != expected.ExitCode:
-          r.addResult(t, "exitcode: " & $expected.ExitCode,
-                         "exitcode: " & $exitCode, reExitCodesDiffer)
-        else:
-          if strip(buf.string) != strip(expected.outp):
-            if not (expected.substr and expected.outp in buf.string):
-              given.err = reOutputsDiffer
-          if given.err == reSuccess:
-            codeGenChecks(test, expected, given)
-          if given.err == reSuccess: inc(r.passed)
-          r.addResult(t, expected.outp, buf.string, given.err)
-      else:
-        r.addResult(t, expected.outp, "executable not found", reExeNotFound)
-
-proc runSingleTest(r: var TResults, test, options: string) =
-  runSingleTest(r, test, options, targetC)
-
-proc run(r: var TResults, dir, options: string) =
-  for test in os.walkFiles(dir / "t*.nim"): runSingleTest(r, test, options)
-
-include specials
-
-proc compileExample(r: var TResults, pattern, options: string) =
-  for test in os.walkFiles(pattern): compileSingleTest(r, test, options)
-
-proc toJson(res: TResults): PJsonNode =
-  result = newJObject()
-  result["total"] = newJInt(res.total)
-  result["passed"] = newJInt(res.passed)
-  result["skipped"] = newJInt(res.skipped)
-
-proc outputJSON(reject, compile, run: TResults) =
-  var doc = newJObject()
-  doc["reject"] = toJson(reject)
-  doc["compile"] = toJson(compile)
-  doc["run"] = toJson(run)
-  var s = pretty(doc)
-  writeFile(jsonFile, s)
-
-# proc runCaasTests(r: var TResults) =
-#   for test, output, status, mode in caasTestsRunner():
-#     r.addResult(test, "", output & "-> " & $mode,
-#                 if status: reSuccess else: reOutputsDiffer)
-
-proc main() =
-  os.putenv "NIMTEST_NO_COLOR", "1"
-  os.putenv "NIMTEST_OUTPUT_LVL", "PRINT_FAILURES"
-
-  const
-    compileJson = "compile.json"
-    runJson = "run.json"
-    rejectJson = "reject.json"
-  
-  var optPrintResults = false
-  var p = initOptParser()
-  p.next()
-  if p.kind == cmdLongoption:
-    case p.key.string
-    of "print": optPrintResults = true
-    else: quit usage
-    p.next()
-  if p.kind != cmdArgument: quit usage
-  var action = p.key.string.normalize
-  p.next()
-  var r = initResults()
-  case action
-  of "reject":
-    reject(r, "tests/reject", p.cmdLineRest.string)
-    rejectSpecialTests(r, p.cmdLineRest.string)
-    writeResults(rejectJson, r)
-  of "compile":
-    compile(r, "tests/compile/t*.nim", p.cmdLineRest.string)
-    compile(r, "tests/ccg/t*.nim", p.cmdLineRest.string)
-    compile(r, "tests/js.nim", p.cmdLineRest.string)
-    compileExample(r, "lib/pure/*.nim", p.cmdLineRest.string)
-    compileExample(r, "examples/*.nim", p.cmdLineRest.string)
-    compileExample(r, "examples/gtk/*.nim", p.cmdLineRest.string)
-    compileExample(r, "examples/talk/*.nim", p.cmdLineRest.string)
-    compileSpecialTests(r, p.cmdLineRest.string)
-    writeResults(compileJson, r)
-  of "run":
-    run(r, "tests/run", p.cmdLineRest.string)
-    runSpecialTests(r, p.cmdLineRest.string)
-    writeResults(runJson, r)
-  of "special":
-    runSpecialTests(r, p.cmdLineRest.string)
-    # runCaasTests(r)
-    writeResults(runJson, r)
-  of "rodfiles":
-    runRodFiles(r, p.cmdLineRest.string)
-    writeResults(runJson, r)
-  of "js":
-    if existsFile(runJSon):
-      r = readResults(runJson)
-    runJsTests(r, p.cmdLineRest.string)
-    writeResults(runJson, r)
-  of "merge":
-    var rejectRes = readResults(rejectJson)
-    var compileRes = readResults(compileJson)
-    var runRes = readResults(runJson)
-    listResults(rejectRes, compileRes, runRes)
-    outputJSON(rejectRes, compileRes, runRes)
-  of "dll":
-    runDLLTests r, p.cmdLineRest.string
-  of "gc":
-    runGCTests(r, p.cmdLineRest.string)
-  of "test":
-    if p.kind != cmdArgument: quit usage
-    var testFile = p.key.string
-    p.next()
-    runSingleTest(r, testFile, p.cmdLineRest.string)
-  of "comp", "rej":
-    if p.kind != cmdArgument: quit usage
-    var testFile = p.key.string
-    p.next()
-    if peg"'/reject/'" in testFile or action == "rej":
-      rejectSingleTest(r, testFile, p.cmdLineRest.string)
-    elif peg"'/compile/'" in testFile or action == "comp":
-      compileSingleTest(r, testFile, p.cmdLineRest.string)
-    else:
-      runSingleTest(r, testFile, p.cmdLineRest.string)
-  else:
-    quit usage
-
-  if optPrintResults: echo r, r.data
-
-if paramCount() == 0:
-  quit usage
-main()
-
diff --git a/todo.txt b/todo.txt
index d0aec9c8c..44aa39791 100644
--- a/todo.txt
+++ b/todo.txt
@@ -1,9 +1,10 @@
 version 0.9.4
 =============
 
-- better debugging support for writes to locations
-- document new templating symbol binding rules
-- fix eval in macros.nim
+- fix GC issues
+- fix macros\tstringinterp.nim
+- test and fix showoff
+- fix closure iterators
 
 
 Bugs
@@ -16,7 +17,6 @@ Bugs
 - compilation of niminst takes way too long. looks like a regression
 - docgen: sometimes effects are listed twice
 - 'result' is not properly cleaned for NRVO --> use uninit checking instead
-- sneaking with qualifiedLookup() is really broken!
 - blocks can "export" an identifier but the CCG generates {} for them ...
 - osproc execProcesses can deadlock if all processes fail (as experienced
   in c++ mode)
@@ -25,6 +25,9 @@ Bugs
 version 0.9.x
 =============
 
+- implement 'union' and 'bits' pragmas
+- fix closures
+- test and fix exception handling
 - ensure (ref T)(a, b) works as a type conversion and type constructor
 - optimize 'genericReset'; 'newException' leads to code bloat
 - stack-less GC
diff --git a/web/nimrod.ini b/web/nimrod.ini
index 9af3bc226..71e36dcdc 100644
--- a/web/nimrod.ini
+++ b/web/nimrod.ini
@@ -62,7 +62,7 @@ srcdoc2: "pure/ftpclient;pure/memfiles;pure/subexes;pure/collections/critbits"
 srcdoc2: "pure/asyncio;pure/actors;core/locks;pure/oids;pure/endians;pure/uri"
 srcdoc2: "pure/nimprof;pure/unittest;packages/docutils/highlite"
 srcdoc2: "packages/docutils/rst;packages/docutils/rstast"
-srcdoc2: "packages/docutils/rstgen"
+srcdoc2: "packages/docutils/rstgen;pure/logging"
 
 webdoc: "wrappers/libcurl;pure/md5;wrappers/mysql;wrappers/iup"
 webdoc: "wrappers/sqlite3;wrappers/postgres;wrappers/tinyc"