summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--compiler/ast.nim2
-rw-r--r--compiler/ccgexprs.nim11
-rw-r--r--compiler/cgen.nim1
-rw-r--r--compiler/commands.nim48
-rw-r--r--compiler/evals.nim1502
-rw-r--r--compiler/lexer.nim35
-rw-r--r--compiler/modules.nim2
-rw-r--r--compiler/parser.nim21
-rw-r--r--compiler/patterns.nim2
-rw-r--r--compiler/pretty.nim62
-rw-r--r--compiler/renderer.nim25
-rw-r--r--compiler/sem.nim5
-rw-r--r--compiler/semcall.nim4
-rw-r--r--compiler/semexprs.nim30
-rw-r--r--compiler/semfold.nim13
-rw-r--r--compiler/semgnrc.nim37
-rw-r--r--compiler/semstmts.nim4
-rw-r--r--compiler/semtempl.nim2
-rw-r--r--compiler/semtypes.nim20
-rw-r--r--compiler/sigmatch.nim6
-rw-r--r--compiler/suggest.nim38
-rw-r--r--compiler/transf.nim5
-rw-r--r--compiler/vm.nim33
-rw-r--r--compiler/vmgen.nim146
-rw-r--r--doc/advopt.txt1
-rw-r--r--doc/backends.txt409
-rw-r--r--doc/grammar.txt5
-rw-r--r--doc/manual.txt31
-rw-r--r--doc/nimrodc.txt65
-rw-r--r--doc/trmacros.txt275
-rw-r--r--doc/tut1.txt12
-rw-r--r--lib/impure/db_mysql.nim9
-rw-r--r--lib/js/dom.nim3
-rw-r--r--lib/posix/posix.nim13
-rw-r--r--lib/pure/asyncdispatch.nim106
-rw-r--r--lib/pure/asynchttpserver.nim172
-rw-r--r--lib/pure/asyncnet.nim97
-rw-r--r--lib/pure/collections/sequtils.nim63
-rw-r--r--lib/pure/httpclient.nim2
-rw-r--r--lib/pure/math.nim3
-rw-r--r--lib/pure/net.nim71
-rw-r--r--lib/pure/os.nim18
-rw-r--r--lib/pure/rawsockets.nim5
-rw-r--r--lib/pure/selectors.nim2
-rw-r--r--lib/pure/strutils.nim2
-rw-r--r--lib/pure/times.nim3
-rw-r--r--lib/system.nim17
-rw-r--r--tests/async/tasyncawait.nim6
-rw-r--r--tests/async/tasyncdiscard.nim2
-rw-r--r--tests/async/tnestedpfuturetypeparam.nim2
-rw-r--r--tests/casestmt/tcase_arrayconstr.nim19
-rw-r--r--tests/exprs/tstmtexprs.nim32
-rw-r--r--tests/generics/mdotlookup.nim8
-rw-r--r--tests/generics/tdotlookup.nim7
-rw-r--r--tests/macros/tbindsym.nim25
-rw-r--r--tests/macros/tbug1149.nim20
-rw-r--r--tests/macros/tbugs.nim90
-rw-r--r--tests/metatype/tautoproc.nim16
-rw-r--r--tests/objects/tobjconstr2.nim12
-rw-r--r--tests/seq/tsequtils.nim4
-rw-r--r--tests/vm/tarrayboundeval.nim10
-rw-r--r--tests/vm/teval1.nim5
-rw-r--r--todo.txt7
-rw-r--r--web/babelpkglist.nim8
-rw-r--r--web/news.txt3
-rw-r--r--web/nimrod.ini4
66 files changed, 1443 insertions, 2275 deletions
diff --git a/compiler/ast.nim b/compiler/ast.nim
index 461854496..9b8218071 100644
--- a/compiler/ast.nim
+++ b/compiler/ast.nim
@@ -1049,7 +1049,7 @@ proc discardSons(father: PNode) =
   father.sons = nil
 
 when defined(useNodeIds):
-  const nodeIdToDebug* = 482228 # 612794
+  const nodeIdToDebug* = 310841 # 612794
   #612840 # 612905 # 614635 # 614637 # 614641
   # 423408
   #429107 # 430443 # 441048 # 441090 # 441153
diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim
index e6b22819f..4698082f1 100644
--- a/compiler/ccgexprs.nim
+++ b/compiler/ccgexprs.nim
@@ -714,11 +714,12 @@ proc genFieldCheck(p: BProc, e: PNode, obj: PRope, field: PSym) =
     assert(it.sons[0].kind == nkSym)
     let op = it.sons[0].sym
     if op.magic == mNot: it = it.sons[1]
-    assert(it.sons[2].kind == nkSym)
+    let disc = it.sons[2].skipConv
+    assert(disc.kind == nkSym)
     initLoc(test, locNone, it.typ, OnStack)
     initLocExpr(p, it.sons[1], u)
-    initLoc(v, locExpr, it.sons[2].typ, OnUnknown)
-    v.r = ropef("$1.$2", [obj, it.sons[2].sym.loc.r])
+    initLoc(v, locExpr, disc.typ, OnUnknown)
+    v.r = ropef("$1.$2", [obj, disc.sym.loc.r])
     genInExprAux(p, it, u, v, test)
     let id = nodeTableTestOrSet(p.module.dataCache,
                                newStrNode(nkStrLit, field.name.s), gBackendId)
@@ -1398,10 +1399,10 @@ proc genSetOp(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
     of mIncl:
       var ts = "NI" & $(size * 8)
       binaryStmtInExcl(p, e, d,
-          "$1 |=((" & ts & ")(1)<<(($2)%(sizeof(" & ts & ")*8)));$n")
+          "$1 |= ((" & ts & ")1)<<(($2)%(sizeof(" & ts & ")*8));$n")
     of mExcl:
       var ts = "NI" & $(size * 8)
-      binaryStmtInExcl(p, e, d, "$1 &= ~((" & ts & ")(1) << (($2) % (sizeof(" &
+      binaryStmtInExcl(p, e, d, "$1 &= ~(((" & ts & ")1) << (($2) % (sizeof(" &
           ts & ")*8)));$n")
     of mCard:
       if size <= 4: unaryExprChar(p, e, d, "#countBits32($1)")
diff --git a/compiler/cgen.nim b/compiler/cgen.nim
index a5852c735..e2f3b5ab0 100644
--- a/compiler/cgen.nim
+++ b/compiler/cgen.nim
@@ -1050,6 +1050,7 @@ proc getSomeInitName(m: PSym, suffix: string): PRope =
   assert m.owner.kind == skPackage
   if {sfSystemModule, sfMainModule} * m.flags == {}:
     result = m.owner.name.s.mangle.toRope
+    result.app "_"
   result.app m.name.s
   result.app suffix
   
diff --git a/compiler/commands.nim b/compiler/commands.nim
index 366019c19..38c8dd294 100644
--- a/compiler/commands.nim
+++ b/compiler/commands.nim
@@ -9,10 +9,34 @@
 
 # This module handles the parsing of command line arguments.
 
+
+# We do this here before the 'import' statement so 'defined' does not get
+# confused with 'TGCMode.gcGenerational' etc.
+template bootSwitch(name, expr, userString: expr): expr =
+  # Helper to build boot constants, for debugging you can 'echo' the else part.
+  const name = if expr: " " & userString else: ""
+
+bootSwitch(usedRelease, defined(release), "-d:release")
+bootSwitch(usedGnuReadline, defined(useGnuReadline), "-d:useGnuReadline")
+bootSwitch(usedNoCaas, defined(noCaas), "-d:noCaas")
+bootSwitch(usedBoehm, defined(boehmgc), "--gc:boehm")
+bootSwitch(usedMarkAndSweep, defined(gcmarkandsweep), "--gc:markAndSweep")
+bootSwitch(usedGenerational, defined(gcgenerational), "--gc:generational")
+bootSwitch(usedNoGC, defined(nogc), "--gc:none")
+
 import 
   os, msgs, options, nversion, condsyms, strutils, extccomp, platform, lists, 
   wordrecg, parseutils, babelcmd, idents
 
+# but some have deps to imported modules. Yay.
+bootSwitch(usedTinyC, hasTinyCBackend, "-d:tinyc")
+bootSwitch(usedAvoidTimeMachine, noTimeMachine, "-d:avoidTimeMachine")
+bootSwitch(usedNativeStacktrace,
+  defined(nativeStackTrace) and nativeStackTraceSupported,
+  "-d:nativeStackTrace")
+bootSwitch(usedFFI, hasFFI, "-d:useFFI")
+
+
 proc writeCommandLineUsage*()
 
 type 
@@ -50,30 +74,16 @@ proc writeAdvancedUsage(pass: TCmdLinePass) =
                                  CPU[platform.hostCPU].name]) & AdvancedUsage)
     quit(0)
 
-template bootSwitch(name, expr, userString: expr): expr =
-  # Helper to build boot constants, for debugging you can 'echo' the else part.
-  const name = if expr: " " & userString else: ""
-
-bootSwitch(usedAvoidTimeMachine, noTimeMachine, "-d:avoidTimeMachine")
-bootSwitch(usedRelease, defined(release), "-d:release")
-bootSwitch(usedTinyC, hasTinyCBackend, "-d:tinyc")
-bootSwitch(usedGnuReadline, defined(useGnuReadline), "-d:useGnuReadline")
-bootSwitch(usedNativeStacktrace,
-  defined(nativeStackTrace) and nativeStackTraceSupported,
-  "-d:nativeStackTrace")
-bootSwitch(usedNoCaas, defined(noCaas), "-d:noCaas")
-bootSwitch(usedFFI, hasFFI, "-d:useFFI")
-bootSwitch(usedBoehm, defined(boehmgc), "--gc:boehm")
-bootSwitch(usedMarkAndSweep, defined(gcmarkandsweep), "--gc:markAndSweep")
-bootSwitch(usedGenerational, defined(gcgenerational), "--gc:generational")
-bootSwitch(usedNoGC, defined(nogc), "--gc:none")
-
-
 proc writeVersionInfo(pass: TCmdLinePass) = 
   if pass == passCmd1:
     msgWriteln(`%`(HelpMessage, [VersionAsString, 
                                  platform.OS[platform.hostOS].name, 
                                  CPU[platform.hostCPU].name]))
+
+    const gitHash = gorge("git log -n 1 --format=%H")
+    if gitHash.strip.len == 40:
+      msgWriteln("git hash: " & gitHash)
+
     msgWriteln("active boot switches:" & usedRelease & usedAvoidTimeMachine &
       usedTinyC & usedGnuReadline & usedNativeStacktrace & usedNoCaas &
       usedFFI & usedBoehm & usedMarkAndSweep & usedGenerational & usedNoGC)
diff --git a/compiler/evals.nim b/compiler/evals.nim
deleted file mode 100644
index 151adf690..000000000
--- a/compiler/evals.nim
+++ /dev/null
@@ -1,1502 +0,0 @@
-#
-#
-#           The Nimrod Compiler
-#        (c) Copyright 2013 Andreas Rumpf
-#
-#    See the file "copying.txt", included in this
-#    distribution, for details about the copyright.
-#
-
-# This file implements the evaluator for Nimrod code.
-# The evaluator is very slow, but simple. Since this
-# is used mainly for evaluating macros and some other
-# stuff at compile time, performance is not that
-# important.
-
-import 
-  strutils, magicsys, lists, options, ast, astalgo, trees, treetab, nimsets, 
-  msgs, os, condsyms, idents, renderer, types, passes, semfold, transf, 
-  parser, ropes, rodread, idgen, osproc, streams, evaltempl
-
-when hasFFI:
-  import evalffi
-
-type 
-  PStackFrame* = ref TStackFrame
-  TStackFrame* = object
-    prc: PSym                 # current prc; proc that is evaluated
-    slots: TNodeSeq           # parameters passed to the proc + locals;
-                              # parameters come first
-    call: PNode
-    next: PStackFrame         # for stacking
-  
-  TEvalMode* = enum           ## reason for evaluation
-    emRepl,                   ## evaluate because in REPL mode
-    emConst,                  ## evaluate for 'const' according to spec
-    emOptimize,               ## evaluate for optimization purposes (same as
-                              ## emConst?)
-    emStatic                  ## evaluate for enforced compile time eval
-                              ## ('static' context)
-
-  TSandboxFlag* = enum        ## what the evaluation engine should allow
-    allowCast,                ## allow unsafe language feature: 'cast'
-    allowFFI,                 ## allow the FFI
-    allowInfiniteLoops        ## allow endless loops
-  TSandboxFlags* = set[TSandboxFlag]
-
-  TEvalContext* = object of passes.TPassContext
-    module*: PSym
-    tos*: PStackFrame         # top of stack
-    lastException*: PNode
-    callsite: PNode           # for 'callsite' magic
-    mode*: TEvalMode
-    features: TSandboxFlags
-    globals*: TIdNodeTable    # state of global vars
-    getType*: proc(n: PNode): PNode {.closure.}
-    handleIsOperator*: proc(n: PNode): PNode {.closure.}
-
-  PEvalContext* = ref TEvalContext
-
-  TEvalFlag = enum 
-    efNone, efLValue
-  TEvalFlags = set[TEvalFlag]
-
-const
-  evalMaxIterations = 500_000 # max iterations of all loops
-  evalMaxRecDepth = 10_000    # max recursion depth for evaluation
-
-# other idea: use a timeout! -> Wether code compiles depends on the machine
-# the compiler runs on then! Bad idea!
-
-proc newStackFrame*(): PStackFrame =
-  new(result)
-  result.slots = @[]
-
-proc newEvalContext*(module: PSym, mode: TEvalMode): PEvalContext =
-  new(result)
-  result.module = module
-  result.mode = mode
-  result.features = {allowFFI}
-  initIdNodeTable(result.globals)
-
-proc pushStackFrame*(c: PEvalContext, t: PStackFrame) {.inline.} = 
-  t.next = c.tos
-  c.tos = t
-
-proc popStackFrame*(c: PEvalContext) {.inline.} =
-  if c.tos != nil: c.tos = c.tos.next
-  else: InternalError("popStackFrame")
-
-proc evalMacroCall*(c: PEvalContext, n, nOrig: PNode, sym: PSym): PNode
-proc evalAux(c: PEvalContext, n: PNode, flags: TEvalFlags): PNode
-
-proc raiseCannotEval(c: PEvalContext, info: TLineInfo): PNode =
-  if defined(debug) and gVerbosity >= 3: writeStackTrace()
-  result = newNodeI(nkExceptBranch, info)
-  # creating a nkExceptBranch without sons 
-  # means that it could not be evaluated
-
-proc stackTraceAux(x: PStackFrame) =
-  if x != nil:
-    stackTraceAux(x.next)
-    var info = if x.call != nil: x.call.info else: UnknownLineInfo()
-    # we now use the same format as in system/except.nim
-    var s = toFilename(info)
-    var line = toLineNumber(info)
-    if line > 0:
-      add(s, '(')
-      add(s, $line)
-      add(s, ')')
-    if x.prc != nil:
-      for k in 1..max(1, 25-s.len): add(s, ' ')
-      add(s, x.prc.name.s)
-    MsgWriteln(s)
-
-proc stackTrace(c: PEvalContext, info: TLineInfo, msg: TMsgKind, arg = "") = 
-  MsgWriteln("stack trace: (most recent call last)")
-  stackTraceAux(c.tos)
-  LocalError(info, msg, arg)
-
-template isSpecial(n: PNode): bool = n.kind == nkExceptBranch
-template bailout() {.dirty.} =
-  if isSpecial(result): return
-
-template evalX(n, flags) {.dirty.} =
-  result = evalAux(c, n, flags)
-  bailout()
-
-proc myreset(n: PNode) =
-  when defined(system.reset): 
-    var oldInfo = n.info
-    reset(n[])
-    n.info = oldInfo
-
-proc evalIf(c: PEvalContext, n: PNode): PNode = 
-  var i = 0
-  var length = sonsLen(n)
-  while (i < length) and (sonsLen(n.sons[i]) >= 2): 
-    evalX(n.sons[i].sons[0], {})
-    if result.kind == nkIntLit and result.intVal != 0:
-      return evalAux(c, n.sons[i].sons[1], {})
-    inc(i)
-  if (i < length) and (sonsLen(n.sons[i]) < 2):
-    result = evalAux(c, n.sons[i].sons[0], {})
-  else:
-    result = emptyNode
-  
-proc evalCase(c: PEvalContext, n: PNode): PNode = 
-  evalX(n.sons[0], {})
-  var res = result
-  result = emptyNode
-  for i in countup(1, sonsLen(n) - 1): 
-    if n.sons[i].kind == nkOfBranch: 
-      for j in countup(0, sonsLen(n.sons[i]) - 2): 
-        if overlap(res, n.sons[i].sons[j]): 
-          return evalAux(c, lastSon(n.sons[i]), {})
-    else: 
-      result = evalAux(c, lastSon(n.sons[i]), {})
-
-var 
-  gWhileCounter: int # Use a counter to prevent endless loops!
-                     # We make this counter global, because otherwise
-                     # nested loops could make the compiler extremely slow.
-  gNestedEvals: int  # count the recursive calls to ``evalAux`` to prevent
-                     # endless recursion
-
-proc evalWhile(c: PEvalContext, n: PNode): PNode =
-  while true:
-    evalX(n.sons[0], {})
-    if getOrdValue(result) == 0:
-      result = emptyNode; break
-    result = evalAux(c, n.sons[1], {})
-    case result.kind
-    of nkBreakStmt: 
-      if result.sons[0].kind == nkEmpty: 
-        result = emptyNode    # consume ``break`` token
-      # Bugfix (see tmacro2): but break in any case!
-      break 
-    of nkExceptBranch, nkReturnToken: break 
-    else: nil
-    dec(gWhileCounter)
-    if gWhileCounter <= 0:
-      if allowInfiniteLoops in c.features:
-        gWhileCounter = 0
-      else:
-        stackTrace(c, n.info, errTooManyIterations)
-        break
-
-proc evalBlock(c: PEvalContext, n: PNode): PNode =
-  result = evalAux(c, n.sons[1], {})
-  if result.kind == nkBreakStmt:
-    if result.sons[0] != nil: 
-      assert(result.sons[0].kind == nkSym)
-      if n.sons[0].kind != nkEmpty: 
-        assert(n.sons[0].kind == nkSym)
-        if result.sons[0].sym.id == n.sons[0].sym.id: result = emptyNode
-    # blocks can only be left with an explicit label now!
-    #else: 
-    #  result = emptyNode      # consume ``break`` token
-  
-proc evalFinally(c: PEvalContext, n, exc: PNode): PNode = 
-  var finallyNode = lastSon(n)
-  if finallyNode.kind == nkFinally: 
-    result = evalAux(c, finallyNode, {})
-    if result.kind != nkExceptBranch: result = exc
-  else: 
-    result = exc
-  
-proc evalTry(c: PEvalContext, n: PNode): PNode = 
-  result = evalAux(c, n.sons[0], {})
-  case result.kind
-  of nkBreakStmt, nkReturnToken: 
-    nil
-  of nkExceptBranch: 
-    if sonsLen(result) >= 1: 
-      # creating a nkExceptBranch without sons means that it could not be
-      # evaluated
-      var exc = result
-      var i = 1
-      var length = sonsLen(n)
-      while (i < length) and (n.sons[i].kind == nkExceptBranch): 
-        var blen = sonsLen(n.sons[i])
-        if blen == 1: 
-          # general except section:
-          result = evalAux(c, n.sons[i].sons[0], {})
-          exc = result
-          break 
-        else: 
-          for j in countup(0, blen - 2): 
-            assert(n.sons[i].sons[j].kind == nkType)
-            let a = exc.typ.skipTypes(abstractPtrs)
-            let b = n.sons[i].sons[j].typ.skipTypes(abstractPtrs)
-            if a == b: 
-              result = evalAux(c, n.sons[i].sons[blen - 1], {})
-              exc = result
-              break 
-        inc(i)
-      result = evalFinally(c, n, exc)
-  else: result = evalFinally(c, n, emptyNode)
-  
-proc getNullValue(typ: PType, info: TLineInfo): PNode
-proc getNullValueAux(obj: PNode, result: PNode) = 
-  case obj.kind
-  of nkRecList:
-    for i in countup(0, sonsLen(obj) - 1): getNullValueAux(obj.sons[i], result)
-  of nkRecCase:
-    getNullValueAux(obj.sons[0], result)
-    for i in countup(1, sonsLen(obj) - 1): 
-      getNullValueAux(lastSon(obj.sons[i]), result)
-  of nkSym:
-    var s = obj.sym
-    var p = newNodeIT(nkExprColonExpr, result.info, s.typ)
-    addSon(p, newSymNode(s, result.info))
-    addSon(p, getNullValue(s.typ, result.info))
-    addSon(result, p)
-  else: InternalError(result.info, "getNullValueAux")
-  
-proc getNullValue(typ: PType, info: TLineInfo): PNode = 
-  var t = skipTypes(typ, abstractRange-{tyTypeDesc})
-  result = emptyNode
-  case t.kind
-  of tyBool, tyEnum, tyChar, tyInt..tyInt64: 
-    result = newNodeIT(nkIntLit, info, t)
-  of tyUInt..tyUInt64:
-    result = newNodeIT(nkUIntLit, info, t)
-  of tyFloat..tyFloat128: 
-    result = newNodeIt(nkFloatLit, info, t)
-  of tyVar, tyPointer, tyPtr, tyRef, tyCString, tySequence, tyString, tyExpr,
-     tyStmt, tyTypeDesc, tyStatic, tyProc:
-    result = newNodeIT(nkNilLit, info, t)
-  of tyObject: 
-    result = newNodeIT(nkPar, info, t)
-    getNullValueAux(t.n, result)
-    # initialize inherited fields:
-    var base = t.sons[0]
-    while base != nil:
-      getNullValueAux(skipTypes(base, skipPtrs).n, result)
-      base = base.sons[0]
-  of tyArray, tyArrayConstr: 
-    result = newNodeIT(nkBracket, info, t)
-    for i in countup(0, int(lengthOrd(t)) - 1): 
-      addSon(result, getNullValue(elemType(t), info))
-  of tyTuple:
-    # XXX nkExprColonExpr is out of fashion ...
-    result = newNodeIT(nkPar, info, t)
-    for i in countup(0, sonsLen(t) - 1):
-      var p = newNodeIT(nkExprColonExpr, info, t.sons[i])
-      var field = if t.n != nil: t.n.sons[i].sym else: newSym(
-        skField, getIdent(":tmp" & $i), t.owner, info)
-      addSon(p, newSymNode(field, info))
-      addSon(p, getNullValue(t.sons[i], info))
-      addSon(result, p)
-  of tySet:
-    result = newNodeIT(nkCurly, info, t)    
-  else: InternalError("getNullValue: " & $t.kind)
-  
-proc evalVarValue(c: PEvalContext, n: PNode): PNode =
-  result = evalAux(c, n, {})
-  if result.kind in {nkType..nkNilLit}: result = result.copyNode
-
-proc allocSlot(c: PStackFrame; sym: PSym): int =
-  result = sym.position + ord(sym.kind == skParam)
-  if result == 0 and sym.kind != skResult:
-    result = c.slots.len
-    if result == 0: result = 1
-    sym.position = result
-  setLen(c.slots, max(result+1, c.slots.len))
-
-proc setSlot(c: PStackFrame, sym: PSym, val: PNode) =
-  assert sym.owner == c.prc or sfFromGeneric in sym.flags
-  let idx = allocSlot(c, sym)
-  c.slots[idx] = val
-
-proc setVar(c: PEvalContext, v: PSym, n: PNode) =
-  if sfGlobal notin v.flags: setSlot(c.tos, v, n)
-  else: IdNodeTablePut(c.globals, v, n)
-
-proc evalVar(c: PEvalContext, n: PNode): PNode =
-  for i in countup(0, sonsLen(n) - 1):
-    let a = n.sons[i]
-    if a.kind == nkCommentStmt: continue
-    #assert(a.sons[0].kind == nkSym) can happen for transformed vars
-    if a.kind == nkVarTuple:
-      result = evalVarValue(c, a.lastSon)
-      if result.kind in {nkType..nkNilLit}:
-        result = result.copyNode
-      bailout()
-      if result.kind != nkPar:
-        return raiseCannotEval(c, n.info)
-      for i in 0 .. a.len-3:
-        var v = a.sons[i].sym
-        setVar(c, v, result.sons[i])
-    else:
-      if a.sons[2].kind != nkEmpty:
-        result = evalVarValue(c, a.sons[2])
-        bailout()
-      else:
-        result = getNullValue(a.sons[0].typ, a.sons[0].info)
-      if a.sons[0].kind == nkSym:
-        var v = a.sons[0].sym
-        setVar(c, v, result)
-      else:
-        # assign to a.sons[0]:
-        var x = result
-        evalX(a.sons[0], {})
-        myreset(x)
-        x.kind = result.kind
-        x.typ = result.typ
-        case x.kind
-        of nkCharLit..nkInt64Lit: x.intVal = result.intVal
-        of nkFloatLit..nkFloat64Lit: x.floatVal = result.floatVal
-        of nkStrLit..nkTripleStrLit: x.strVal = result.strVal
-        of nkIdent: x.ident = result.ident
-        of nkSym: x.sym = result.sym
-        else:
-          if x.kind notin {nkEmpty..nkNilLit}:
-            discardSons(x)
-            for j in countup(0, sonsLen(result) - 1): addSon(x, result.sons[j])
-  result = emptyNode
-
-proc aliasNeeded(n: PNode, flags: TEvalFlags): bool = 
-  result = efLValue in flags or n.typ == nil or 
-    n.typ.kind in {tyExpr, tyStatic, tyStmt, tyTypeDesc}
-
-proc evalVariable(c: PStackFrame, sym: PSym, flags: TEvalFlags): PNode =
-  # We need to return a node to the actual value,
-  # which can be modified.
-  assert sym.position != 0 or skResult == sym.kind
-  var x = c
-  while x != nil:
-    if sym.owner == x.prc:
-      result = x.slots[sym.position]
-      assert result != nil
-      if not aliasNeeded(result, flags):
-        result = copyTree(result)
-      return
-    x = x.next
-  #internalError(sym.info, "cannot eval " & sym.name.s & " " & $sym.position)
-  result = raiseCannotEval(nil, sym.info)
-  #result = emptyNode
-
-proc evalGlobalVar(c: PEvalContext, s: PSym, flags: TEvalFlags): PNode =
-  if sfCompileTime in s.flags or c.mode == emRepl or s.kind == skForVar:
-    result = IdNodeTableGet(c.globals, s)
-    if result != nil: 
-      if not aliasNeeded(result, flags): 
-        result = copyTree(result)
-    else:
-      when hasFFI:
-        if sfImportc in s.flags and allowFFI in c.features:
-          result = importcSymbol(s)
-          IdNodeTablePut(c.globals, s, result)
-          return result
-      
-      result = s.ast
-      if result == nil or result.kind == nkEmpty:
-        result = getNullValue(s.typ, s.info)
-      else:
-        result = evalAux(c, result, {})
-        if isSpecial(result): return
-      IdNodeTablePut(c.globals, s, result)
-  else:
-    result = raiseCannotEval(nil, s.info)
-
-proc optBody(c: PEvalContext, s: PSym): PNode =
-  result = s.getBody
-
-proc evalCall(c: PEvalContext, n: PNode): PNode = 
-  var d = newStackFrame()
-  d.call = n
-  var prc = n.sons[0]
-  let isClosure = prc.kind == nkClosure
-  setlen(d.slots, sonsLen(n) + ord(isClosure))
-  if isClosure:
-    #debug prc
-    evalX(prc.sons[1], {efLValue})
-    d.slots[sonsLen(n)] = result
-    result = evalAux(c, prc.sons[0], {})
-  else:
-    result = evalAux(c, prc, {})
-
-  if isSpecial(result): return 
-  prc = result
-  # bind the actual params to the local parameter of a new binding
-  if prc.kind != nkSym: 
-    InternalError(n.info, "evalCall " & n.renderTree)
-    return
-  d.prc = prc.sym
-  if prc.sym.kind notin {skProc, skConverter, skMacro}:
-    InternalError(n.info, "evalCall")
-    return
-  for i in countup(1, sonsLen(n) - 1): 
-    evalX(n.sons[i], {})
-    d.slots[i] = result
-  if n.typ != nil: d.slots[0] = getNullValue(n.typ, n.info)
-  
-  when hasFFI:
-    if sfImportc in prc.sym.flags and allowFFI in c.features:
-      var newCall = newNodeI(nkCall, n.info, n.len)
-      newCall.sons[0] = evalGlobalVar(c, prc.sym, {})
-      for i in 1 .. <n.len:
-        newCall.sons[i] = d.slots[i]
-      return callForeignFunction(newCall)
-  
-  pushStackFrame(c, d)
-  evalX(optBody(c, prc.sym), {})
-  if n.typ != nil: result = d.slots[0]
-  popStackFrame(c)
-
-proc evalArrayAccess(c: PEvalContext, n: PNode, flags: TEvalFlags): PNode = 
-  evalX(n.sons[0], flags)
-  var x = result
-  evalX(n.sons[1], {})
-  var idx = getOrdValue(result)
-  result = emptyNode
-  case x.kind
-  of nkPar:
-    if (idx >= 0) and (idx < sonsLen(x)): 
-      result = x.sons[int(idx)]
-      if result.kind == nkExprColonExpr: result = result.sons[1]
-      if not aliasNeeded(result, flags): result = copyTree(result)
-    else: 
-      stackTrace(c, n.info, errIndexOutOfBounds)
-  of nkBracket, nkMetaNode: 
-    if (idx >= 0) and (idx < sonsLen(x)): 
-      result = x.sons[int(idx)]
-      if not aliasNeeded(result, flags): result = copyTree(result)
-    else: 
-      stackTrace(c, n.info, errIndexOutOfBounds)
-  of nkStrLit..nkTripleStrLit:
-    if efLValue in flags: return raiseCannotEval(c, n.info)
-    result = newNodeIT(nkCharLit, x.info, getSysType(tyChar))
-    if (idx >= 0) and (idx < len(x.strVal)): 
-      result.intVal = ord(x.strVal[int(idx) + 0])
-    elif idx == len(x.strVal): 
-      nil
-    else: 
-      stackTrace(c, n.info, errIndexOutOfBounds)
-  else: stackTrace(c, n.info, errNilAccess)
-  
-proc evalFieldAccess(c: PEvalContext, n: PNode, flags: TEvalFlags): PNode =
-  # a real field access; proc calls have already been transformed
-  # XXX: field checks!
-  evalX(n.sons[0], flags)
-  var x = result
-  if x.kind != nkPar: return raiseCannotEval(c, n.info)
-  # this is performance critical:
-  var field = n.sons[1].sym
-  result = x.sons[field.position]
-  if result.kind == nkExprColonExpr: result = result.sons[1]
-  if not aliasNeeded(result, flags): result = copyTree(result)
-
-proc evalAsgn(c: PEvalContext, n: PNode): PNode =
-  var a = n.sons[0]
-  if a.kind == nkBracketExpr and a.sons[0].typ.kind in {tyString, tyCString}: 
-    evalX(a.sons[0], {efLValue})
-    var x = result
-    evalX(a.sons[1], {})
-    var idx = getOrdValue(result)
-
-    evalX(n.sons[1], {})
-    if result.kind notin {nkIntLit, nkCharLit}: return c.raiseCannotEval(n.info)
-
-    if idx >= 0 and idx < len(x.strVal):
-      x.strVal[int(idx)] = chr(int(result.intVal))
-    else:
-      stackTrace(c, n.info, errIndexOutOfBounds)
-  else:
-    evalX(n.sons[0], {efLValue})
-    var x = result
-    evalX(n.sons[1], {})
-    myreset(x)
-    x.kind = result.kind
-    x.typ = result.typ
-    case x.kind
-    of nkCharLit..nkInt64Lit: x.intVal = result.intVal
-    of nkFloatLit..nkFloat64Lit: x.floatVal = result.floatVal
-    of nkStrLit..nkTripleStrLit: x.strVal = result.strVal
-    of nkIdent: x.ident = result.ident
-    of nkSym: x.sym = result.sym
-    else:
-      if x.kind notin {nkEmpty..nkNilLit}:
-        discardSons(x)
-        for i in countup(0, sonsLen(result) - 1): addSon(x, result.sons[i])
-  result = emptyNode
-  assert result.kind == nkEmpty
-
-proc evalSwap(c: PEvalContext, n: PNode): PNode = 
-  evalX(n.sons[0], {efLValue})
-  var x = result
-  evalX(n.sons[1], {efLValue})
-  if x.kind != result.kind: 
-    stackTrace(c, n.info, errCannotInterpretNodeX, $n.kind)
-  else:
-    case x.kind
-    of nkCharLit..nkInt64Lit: swap(x.intVal, result.intVal)
-    of nkFloatLit..nkFloat64Lit: swap(x.floatVal, result.floatVal)
-    of nkStrLit..nkTripleStrLit: swap(x.strVal, result.strVal)
-    of nkIdent: swap(x.ident, result.ident)
-    of nkSym: swap(x.sym, result.sym)    
-    else: 
-      var tmpn = copyTree(x)
-      discardSons(x)
-      for i in countup(0, sonsLen(result) - 1): addSon(x, result.sons[i])
-      discardSons(result)
-      for i in countup(0, sonsLen(tmpn) - 1): addSon(result, tmpn.sons[i])
-  result = emptyNode
-  
-proc evalSym(c: PEvalContext, n: PNode, flags: TEvalFlags): PNode = 
-  var s = n.sym
-  case s.kind
-  of skProc, skConverter, skMacro, skType:
-    result = n
-    #result = s.getBody
-  of skVar, skLet, skForVar, skTemp, skResult:
-    if sfGlobal notin s.flags:
-      result = evalVariable(c.tos, s, flags)
-    else:
-      result = evalGlobalVar(c, s, flags)
-  of skParam:
-    # XXX what about LValue?
-    if s.position + 1 <% c.tos.slots.len:
-      result = c.tos.slots[s.position + 1]
-  of skConst: result = s.ast
-  of skEnumField: result = newIntNodeT(s.position, n)
-  else: result = nil
-  let mask = if hasFFI and allowFFI in c.features: {sfForward}
-             else: {sfImportc, sfForward}
-  if result == nil or mask * s.flags != {}:
-    result = raiseCannotEval(c, n.info)
-
-proc evalIncDec(c: PEvalContext, n: PNode, sign: biggestInt): PNode = 
-  evalX(n.sons[1], {efLValue})
-  var a = result
-  evalX(n.sons[2], {})
-  var b = result
-  case a.kind
-  of nkCharLit..nkInt64Lit: a.intval = a.intVal + sign * getOrdValue(b)
-  else: return raiseCannotEval(c, n.info)
-  result = emptyNode
-
-proc getStrValue(n: PNode): string = 
-  case n.kind
-  of nkStrLit..nkTripleStrLit: result = n.strVal
-  else: 
-    InternalError(n.info, "getStrValue")
-    result = ""
-
-proc evalEcho(c: PEvalContext, n: PNode): PNode = 
-  for i in countup(1, sonsLen(n) - 1): 
-    evalX(n.sons[i], {})
-    Write(stdout, getStrValue(result))
-  writeln(stdout, "")
-  result = emptyNode
-
-proc evalExit(c: PEvalContext, n: PNode): PNode = 
-  if c.mode in {emRepl, emStatic}:
-    evalX(n.sons[1], {})
-    Message(n.info, hintQuitCalled)
-    quit(int(getOrdValue(result)))
-  else:
-    result = raiseCannotEval(c, n.info)
-
-proc evalOr(c: PEvalContext, n: PNode): PNode = 
-  evalX(n.sons[1], {})
-  if result.intVal == 0: result = evalAux(c, n.sons[2], {})
-  
-proc evalAnd(c: PEvalContext, n: PNode): PNode = 
-  evalX(n.sons[1], {})
-  if result.intVal != 0: result = evalAux(c, n.sons[2], {})
-  
-proc evalNew(c: PEvalContext, n: PNode): PNode = 
-  #if c.mode == emOptimize: return raiseCannotEval(c, n.info)
-  
-  # we ignore the finalizer for now and most likely forever :-)
-  evalX(n.sons[1], {efLValue})
-  var a = result
-  var t = skipTypes(n.sons[1].typ, abstractVar)
-  if a.kind == nkEmpty: InternalError(n.info, "first parameter is empty")
-  myreset(a)
-  let u = getNullValue(t.sons[0], n.info)
-  a.kind = u.kind
-  a.typ = t
-  shallowCopy(a.sons, u.sons)
-  result = emptyNode
-  when false:
-    a.kind = nkRefTy
-    a.info = n.info
-    a.typ = t
-    a.sons = nil
-    addSon(a, getNullValue(t.sons[0], n.info))
-    result = emptyNode
-
-proc evalDeref(c: PEvalContext, n: PNode, flags: TEvalFlags): PNode = 
-  evalX(n.sons[0], {efLValue})
-  case result.kind
-  of nkNilLit: stackTrace(c, n.info, errNilAccess)
-  of nkRefTy: 
-    # XXX efLValue?
-    result = result.sons[0]
-  else:
-    if skipTypes(n.sons[0].typ, abstractInst).kind != tyRef:
-      result = raiseCannotEval(c, n.info)
-  
-proc evalAddr(c: PEvalContext, n: PNode, flags: TEvalFlags): PNode = 
-  evalX(n.sons[0], {efLValue})
-  var a = result
-  var t = newType(tyPtr, c.module)
-  addSonSkipIntLit(t, a.typ)
-  result = newNodeIT(nkRefTy, n.info, t)
-  addSon(result, a)
-
-proc evalConv(c: PEvalContext, n: PNode): PNode = 
-  result = evalAux(c, n.sons[1], {efLValue})
-  if isSpecial(result): return
-  if result.typ != nil:
-    var a = result
-    result = foldConv(n, a)
-    if result == nil: 
-      # foldConv() cannot deal with everything that we want to do here:
-      result = a
-
-proc evalCast(c: PEvalContext, n: PNode, flags: TEvalFlags): PNode =
-  if allowCast in c.features:
-    when hasFFI:
-      result = evalAux(c, n.sons[1], {efLValue})
-      if isSpecial(result): return
-      InternalAssert result.typ != nil
-      result = fficast(result, n.typ)
-    else:
-      result = evalConv(c, n)
-  else:
-    result = raiseCannotEval(c, n.info)
-
-proc evalCheckedFieldAccess(c: PEvalContext, n: PNode, 
-                            flags: TEvalFlags): PNode = 
-  result = evalAux(c, n.sons[0], flags)
-
-proc evalUpConv(c: PEvalContext, n: PNode, flags: TEvalFlags): PNode = 
-  result = evalAux(c, n.sons[0], flags)
-  if isSpecial(result): return 
-  var dest = skipTypes(n.typ, abstractPtrs)
-  var src = skipTypes(result.typ, abstractPtrs)
-  if inheritanceDiff(src, dest) > 0: 
-    stackTrace(c, n.info, errInvalidConversionFromTypeX, typeToString(src))
-  
-proc evalRangeChck(c: PEvalContext, n: PNode): PNode = 
-  evalX(n.sons[0], {})
-  var x = result
-  evalX(n.sons[1], {})
-  var a = result
-  evalX(n.sons[2], {})
-  var b = result
-  if leValueConv(a, x) and leValueConv(x, b): 
-    result = x                # a <= x and x <= b
-    result.typ = n.typ
-  else: 
-    stackTrace(c, n.info, errGenerated, 
-      msgKindToString(errIllegalConvFromXtoY) % [
-      typeToString(n.sons[0].typ), typeToString(n.typ)])
-  
-proc evalConvStrToCStr(c: PEvalContext, n: PNode): PNode = 
-  result = evalAux(c, n.sons[0], {})
-  if isSpecial(result): return 
-  result.typ = n.typ
-
-proc evalConvCStrToStr(c: PEvalContext, n: PNode): PNode = 
-  result = evalAux(c, n.sons[0], {})
-  if isSpecial(result): return 
-  result.typ = n.typ
-
-proc evalRaise(c: PEvalContext, n: PNode): PNode = 
-  if c.mode in {emRepl, emStatic}:
-    if n.sons[0].kind != nkEmpty: 
-      result = evalAux(c, n.sons[0], {})
-      if isSpecial(result): return 
-      var a = result
-      result = newNodeIT(nkExceptBranch, n.info, a.typ)
-      addSon(result, a)
-      c.lastException = result
-    elif c.lastException != nil: 
-      result = c.lastException
-    else: 
-      stackTrace(c, n.info, errExceptionAlreadyHandled)
-      result = newNodeIT(nkExceptBranch, n.info, nil)
-      addSon(result, ast.emptyNode)
-  else:
-    result = raiseCannotEval(c, n.info)
-
-proc evalReturn(c: PEvalContext, n: PNode): PNode = 
-  if n.sons[0].kind != nkEmpty: 
-    result = evalAsgn(c, n.sons[0])
-    if isSpecial(result): return 
-  result = newNodeIT(nkReturnToken, n.info, nil)
-
-proc evalProc(c: PEvalContext, n: PNode): PNode = 
-  if n.sons[genericParamsPos].kind == nkEmpty: 
-    var s = n.sons[namePos].sym
-    if (resultPos < sonsLen(n)) and (n.sons[resultPos].kind != nkEmpty): 
-      var v = n.sons[resultPos].sym
-      result = getNullValue(v.typ, n.info)
-      if c.tos.slots.len == 0: setLen(c.tos.slots, 1)
-      c.tos.slots[0] = result
-      #IdNodeTablePut(c.tos.mapping, v, result)
-      result = evalAux(c, s.getBody, {})
-      if result.kind == nkReturnToken:
-        result = c.tos.slots[0]
-    else:
-      result = evalAux(c, s.getBody, {})
-      if result.kind == nkReturnToken: 
-        result = emptyNode
-  else: 
-    result = emptyNode
-  
-proc evalHigh(c: PEvalContext, n: PNode): PNode = 
-  result = evalAux(c, n.sons[1], {})
-  if isSpecial(result): return 
-  case skipTypes(n.sons[1].typ, abstractVar).kind
-  of tyOpenArray, tySequence, tyVarargs: 
-    result = newIntNodeT(sonsLen(result)-1, n)
-  of tyString: result = newIntNodeT(len(result.strVal) - 1, n)
-  else: InternalError(n.info, "evalHigh")
-
-proc evalOf(c: PEvalContext, n: PNode): PNode = 
-  result = evalAux(c, n.sons[1], {})
-  if isSpecial(result): return 
-  result = newIntNodeT(ord(inheritanceDiff(result.typ, n.sons[2].typ) >= 0), n)
-
-proc evalSetLengthStr(c: PEvalContext, n: PNode): PNode = 
-  result = evalAux(c, n.sons[1], {efLValue})
-  if isSpecial(result): return 
-  var a = result
-  result = evalAux(c, n.sons[2], {})
-  if isSpecial(result): return 
-  var b = result
-  case a.kind
-  of nkStrLit..nkTripleStrLit: 
-    var newLen = int(getOrdValue(b))
-    setlen(a.strVal, newLen)
-  else: InternalError(n.info, "evalSetLengthStr")
-  result = emptyNode
-
-proc evalSetLengthSeq(c: PEvalContext, n: PNode): PNode = 
-  result = evalAux(c, n.sons[1], {efLValue})
-  if isSpecial(result): return 
-  var a = result
-  result = evalAux(c, n.sons[2], {})
-  if isSpecial(result): return 
-  var b = result
-  if a.kind != nkBracket: 
-    InternalError(n.info, "evalSetLengthSeq")
-    return
-  var newLen = int(getOrdValue(b))
-  var oldLen = sonsLen(a)
-  setlen(a.sons, newLen)
-  for i in countup(oldLen, newLen - 1): 
-    a.sons[i] = getNullValue(skipTypes(n.sons[1].typ, abstractVar), n.info)
-  result = emptyNode
-
-proc evalNewSeq(c: PEvalContext, n: PNode): PNode = 
-  result = evalAux(c, n.sons[1], {efLValue})
-  if isSpecial(result): return 
-  var a = result
-  result = evalAux(c, n.sons[2], {})
-  if isSpecial(result): return 
-  var b = result
-  var t = skipTypes(n.sons[1].typ, abstractVar)
-  if a.kind == nkEmpty: InternalError(n.info, "first parameter is empty")
-  myreset(a)
-  a.kind = nkBracket
-  a.info = n.info
-  a.typ = t
-  a.sons = nil
-  var L = int(getOrdValue(b))
-  newSeq(a.sons, L)
-  for i in countup(0, L-1): 
-    a.sons[i] = getNullValue(t.sons[0], n.info)
-  result = emptyNode
- 
-proc evalIncl(c: PEvalContext, n: PNode): PNode = 
-  result = evalAux(c, n.sons[1], {efLValue})
-  if isSpecial(result): return 
-  var a = result
-  result = evalAux(c, n.sons[2], {})
-  if isSpecial(result): return 
-  var b = result
-  if not inSet(a, b): addSon(a, copyTree(b))
-  result = emptyNode
-
-proc evalExcl(c: PEvalContext, n: PNode): PNode = 
-  result = evalAux(c, n.sons[1], {efLValue})
-  if isSpecial(result): return 
-  var a = result
-  result = evalAux(c, n.sons[2], {})
-  if isSpecial(result): return 
-  var b = newNodeIT(nkCurly, n.info, n.sons[1].typ)
-  addSon(b, result)
-  var r = diffSets(a, b)
-  discardSons(a)
-  for i in countup(0, sonsLen(r) - 1): addSon(a, r.sons[i])
-  result = emptyNode
-
-proc evalAppendStrCh(c: PEvalContext, n: PNode): PNode = 
-  result = evalAux(c, n.sons[1], {efLValue})
-  if isSpecial(result): return 
-  var a = result
-  result = evalAux(c, n.sons[2], {})
-  if isSpecial(result): return 
-  var b = result
-  case a.kind
-  of nkStrLit..nkTripleStrLit: add(a.strVal, chr(int(getOrdValue(b))))
-  else: return raiseCannotEval(c, n.info)
-  result = emptyNode
-
-proc evalConStrStr(c: PEvalContext, n: PNode): PNode = 
-  # we cannot use ``evalOp`` for this as we can here have more than 2 arguments
-  var a = newNodeIT(nkStrLit, n.info, n.typ)
-  a.strVal = ""
-  for i in countup(1, sonsLen(n) - 1): 
-    result = evalAux(c, n.sons[i], {})
-    if isSpecial(result): return 
-    a.strVal.add(getStrOrChar(result))
-  result = a
-
-proc evalAppendStrStr(c: PEvalContext, n: PNode): PNode = 
-  result = evalAux(c, n.sons[1], {efLValue})
-  if isSpecial(result): return 
-  var a = result
-  result = evalAux(c, n.sons[2], {})
-  if isSpecial(result): return 
-  var b = result
-  case a.kind
-  of nkStrLit..nkTripleStrLit: a.strVal = a.strVal & getStrOrChar(b)
-  else: return raiseCannotEval(c, n.info)
-  result = emptyNode
-
-proc evalAppendSeqElem(c: PEvalContext, n: PNode): PNode = 
-  result = evalAux(c, n.sons[1], {efLValue})
-  if isSpecial(result): return 
-  var a = result
-  result = evalAux(c, n.sons[2], {})
-  if isSpecial(result): return 
-  var b = result
-  if a.kind == nkBracket: addSon(a, copyTree(b))
-  else: return raiseCannotEval(c, n.info)
-  result = emptyNode
-
-proc evalRepr(c: PEvalContext, n: PNode): PNode = 
-  result = evalAux(c, n.sons[1], {})
-  if isSpecial(result): return 
-  result = newStrNodeT(renderTree(result, {renderNoComments}), n)
-
-proc isEmpty(n: PNode): bool =
-  result = n != nil and n.kind == nkEmpty
-
-proc evalParseExpr(c: PEvalContext, n: PNode): PNode =
-  var code = evalAux(c, n.sons[1], {})
-  var ast = parseString(code.getStrValue, code.info.toFilename,
-                        code.info.line.int)
-  if sonsLen(ast) != 1:
-    GlobalError(code.info, errExprExpected, "multiple statements")
-  result = ast.sons[0]
-  #result.typ = newType(tyExpr, c.module)
-
-proc evalParseStmt(c: PEvalContext, n: PNode): PNode =
-  var code = evalAux(c, n.sons[1], {})
-  result = parseString(code.getStrValue, code.info.toFilename,
-                       code.info.line.int)
-  #result.typ = newType(tyStmt, c.module)
-
-proc evalTypeTrait*(trait, operand: PNode, context: PSym): PNode =
-  let typ = operand.typ.skipTypes({tyTypeDesc})
-  case trait.sym.name.s.normalize
-  of "name":
-    result = newStrNode(nkStrLit, typ.typeToString(preferName))
-    result.typ = newType(tyString, context)
-    result.info = trait.info
-  of "arity":
-    result = newIntNode(nkIntLit, typ.n.len-1)
-    result.typ = newType(tyInt, context)
-    result.info = trait.info
-  else:
-    internalAssert false
-
-proc expectString(n: PNode) =
-  if n.kind notin nkStrKinds:
-    GlobalError(n.info, errStringLiteralExpected)
-
-proc evalSlurp*(e: PNode, module: PSym): PNode =
-  expectString(e)
-  result = newNodeIT(nkStrLit, e.info, getSysType(tyString))
-  try:
-    var filename = e.strVal.FindFile
-    result.strVal = readFile(filename)
-    # we produce a fake include statement for every slurped filename, so that
-    # the module dependencies are accurate:    
-    appendToModule(module, newNode(nkIncludeStmt, e.info, @[
-      newStrNode(nkStrLit, filename)]))
-  except EIO:
-    result.strVal = ""
-    LocalError(e.info, errCannotOpenFile, e.strVal)
-
-proc readOutput(p: PProcess): string =
-  result = ""
-  var output = p.outputStream
-  discard p.waitForExit
-  while not output.atEnd:
-    result.add(output.readLine)
-
-proc evalStaticExec*(cmd, input: PNode): PNode =
-  expectString(cmd)
-  var p = startCmd(cmd.strVal)
-  if input != nil:
-    expectString(input)
-    p.inputStream.write(input.strVal)
-    p.inputStream.close()
-  result = newStrNode(nkStrLit, p.readOutput)
-  result.typ = getSysType(tyString)
-  result.info = cmd.info
-
-proc evalExpandToAst(c: PEvalContext, original: PNode): PNode =
-  var
-    n = original.copyTree
-    macroCall = n.sons[1]
-    expandedSym = macroCall.sons[0].sym
-
-  for i in countup(1, macroCall.sonsLen - 1):
-    macroCall.sons[i] = evalAux(c, macroCall.sons[i], {})
-
-  case expandedSym.kind
-  of skTemplate:
-    let genSymOwner = if c.tos != nil and c.tos.prc != nil:
-                        c.tos.prc 
-                      else:
-                        c.module
-    result = evalTemplate(macroCall, expandedSym, genSymOwner)
-  of skMacro:
-    # At this point macroCall.sons[0] is nkSym node.
-    # To be completely compatible with normal macro invocation,
-    # we want to replace it with nkIdent node featuring
-    # the original unmangled macro name.
-    macroCall.sons[0] = newIdentNode(expandedSym.name, expandedSym.info)
-    result = evalMacroCall(c, macroCall, original, expandedSym)
-  else:
-    InternalError(macroCall.info,
-      "ExpandToAst: expanded symbol is no macro or template")
-    result = emptyNode
-
-proc evalMagicOrCall(c: PEvalContext, n: PNode): PNode = 
-  var m = getMagic(n)
-  case m
-  of mNone: result = evalCall(c, n)
-  of mOf: result = evalOf(c, n)
-  of mSizeOf: result = raiseCannotEval(c, n.info)
-  of mHigh: result = evalHigh(c, n)
-  of mExit: result = evalExit(c, n)
-  of mNew, mNewFinalize: result = evalNew(c, n)
-  of mNewSeq: result = evalNewSeq(c, n)
-  of mSwap: result = evalSwap(c, n)
-  of mInc: result = evalIncDec(c, n, 1)
-  of ast.mDec: result = evalIncDec(c, n, - 1)
-  of mEcho: result = evalEcho(c, n)
-  of mSetLengthStr: result = evalSetLengthStr(c, n)
-  of mSetLengthSeq: result = evalSetLengthSeq(c, n)
-  of mIncl: result = evalIncl(c, n)
-  of mExcl: result = evalExcl(c, n)
-  of mAnd: result = evalAnd(c, n)
-  of mOr: result = evalOr(c, n)
-  of mAppendStrCh: result = evalAppendStrCh(c, n)
-  of mAppendStrStr: result = evalAppendStrStr(c, n)
-  of mAppendSeqElem: result = evalAppendSeqElem(c, n)
-  of mParseExprToAst: result = evalParseExpr(c, n)
-  of mParseStmtToAst: result = evalParseStmt(c, n)
-  of mExpandToAst: result = evalExpandToAst(c, n)
-  of mTypeTrait:
-    let operand = evalAux(c, n.sons[1], {})
-    result = evalTypeTrait(n[0], operand, c.module)
-  of mIs:
-    n.sons[1] = evalAux(c, n.sons[1], {})
-    result = c.handleIsOperator(n)
-  of mSlurp: result = evalSlurp(evalAux(c, n.sons[1], {}), c.module)
-  of mStaticExec:
-    let cmd = evalAux(c, n.sons[1], {})
-    let input = if n.sonsLen == 3: evalAux(c, n.sons[2], {}) else: nil
-    result = evalStaticExec(cmd, input)
-  of mNLen:
-    result = evalAux(c, n.sons[1], {efLValue})
-    if isSpecial(result): return 
-    var a = result
-    result = newNodeIT(nkIntLit, n.info, n.typ)
-    case a.kind
-    of nkEmpty..nkNilLit: nil
-    else: result.intVal = sonsLen(a)
-  of mNChild:
-    result = evalAux(c, n.sons[1], {efLValue})
-    if isSpecial(result): return 
-    var a = result
-    result = evalAux(c, n.sons[2], {efLValue})
-    if isSpecial(result): return 
-    var k = getOrdValue(result)
-    if not (a.kind in {nkEmpty..nkNilLit}) and (k >= 0) and (k < sonsLen(a)): 
-      result = a.sons[int(k)]
-      if result == nil: result = newNode(nkEmpty)
-    else: 
-      stackTrace(c, n.info, errIndexOutOfBounds)
-      result = emptyNode
-  of mNSetChild: 
-    result = evalAux(c, n.sons[1], {efLValue})
-    if isSpecial(result): return 
-    var a = result
-    result = evalAux(c, n.sons[2], {efLValue})
-    if isSpecial(result): return 
-    var b = result
-    result = evalAux(c, n.sons[3], {efLValue})
-    if isSpecial(result): return 
-    var k = getOrdValue(b)
-    if (k >= 0) and (k < sonsLen(a)) and not (a.kind in {nkEmpty..nkNilLit}): 
-      a.sons[int(k)] = result
-    else: 
-      stackTrace(c, n.info, errIndexOutOfBounds)
-    result = emptyNode
-  of mNAdd: 
-    result = evalAux(c, n.sons[1], {efLValue})
-    if isSpecial(result): return 
-    var a = result
-    result = evalAux(c, n.sons[2], {efLValue})
-    if isSpecial(result): return 
-    addSon(a, result)
-    result = a
-  of mNAddMultiple: 
-    result = evalAux(c, n.sons[1], {efLValue})
-    if isSpecial(result): return 
-    var a = result
-    result = evalAux(c, n.sons[2], {efLValue})
-    if isSpecial(result): return 
-    for i in countup(0, sonsLen(result) - 1): addSon(a, result.sons[i])
-    result = a
-  of mNDel: 
-    result = evalAux(c, n.sons[1], {efLValue})
-    if isSpecial(result): return 
-    var a = result
-    result = evalAux(c, n.sons[2], {efLValue})
-    if isSpecial(result): return 
-    var b = result
-    result = evalAux(c, n.sons[3], {efLValue})
-    if isSpecial(result): return 
-    for i in countup(0, int(getOrdValue(result)) - 1): 
-      delSon(a, int(getOrdValue(b)))
-    result = emptyNode
-  of mNKind: 
-    result = evalAux(c, n.sons[1], {})
-    if isSpecial(result): return 
-    var a = result
-    result = newNodeIT(nkIntLit, n.info, n.typ)
-    result.intVal = ord(a.kind)
-  of mNIntVal: 
-    result = evalAux(c, n.sons[1], {})
-    if isSpecial(result): return 
-    var a = result
-    result = newNodeIT(nkIntLit, n.info, n.typ)
-    case a.kind
-    of nkCharLit..nkInt64Lit: result.intVal = a.intVal
-    else: stackTrace(c, n.info, errFieldXNotFound, "intVal")
-  of mNFloatVal: 
-    result = evalAux(c, n.sons[1], {})
-    if isSpecial(result): return 
-    var a = result
-    result = newNodeIT(nkFloatLit, n.info, n.typ)
-    case a.kind
-    of nkFloatLit..nkFloat64Lit: result.floatVal = a.floatVal
-    else: stackTrace(c, n.info, errFieldXNotFound, "floatVal")
-  of mNSymbol: 
-    result = evalAux(c, n.sons[1], {efLValue})
-    if isSpecial(result): return 
-    if result.kind != nkSym: stackTrace(c, n.info, errFieldXNotFound, "symbol")
-  of mNIdent: 
-    result = evalAux(c, n.sons[1], {})
-    if isSpecial(result): return 
-    if result.kind != nkIdent: stackTrace(c, n.info, errFieldXNotFound, "ident")
-  of mNGetType:
-    var ast = evalAux(c, n.sons[1], {})
-    InternalAssert c.getType != nil
-    result = c.getType(ast)
-  of mNStrVal: 
-    result = evalAux(c, n.sons[1], {})
-    if isSpecial(result): return 
-    var a = result
-    result = newNodeIT(nkStrLit, n.info, n.typ)
-    case a.kind
-    of nkStrLit..nkTripleStrLit: result.strVal = a.strVal
-    else: stackTrace(c, n.info, errFieldXNotFound, "strVal")
-  of mNSetIntVal: 
-    result = evalAux(c, n.sons[1], {efLValue})
-    if isSpecial(result): return 
-    var a = result
-    result = evalAux(c, n.sons[2], {})
-    if isSpecial(result): return
-    if a.kind in {nkCharLit..nkInt64Lit} and 
-        result.kind in {nkCharLit..nkInt64Lit}:
-      a.intVal = result.intVal
-    else: 
-      stackTrace(c, n.info, errFieldXNotFound, "intVal")
-    result = emptyNode
-  of mNSetFloatVal: 
-    result = evalAux(c, n.sons[1], {efLValue})
-    if isSpecial(result): return 
-    var a = result
-    result = evalAux(c, n.sons[2], {})
-    if isSpecial(result): return 
-    if a.kind in {nkFloatLit..nkFloat64Lit} and
-        result.kind in {nkFloatLit..nkFloat64Lit}:
-      a.floatVal = result.floatVal
-    else:
-      stackTrace(c, n.info, errFieldXNotFound, "floatVal")
-    result = emptyNode
-  of mNSetSymbol: 
-    result = evalAux(c, n.sons[1], {efLValue})
-    if isSpecial(result): return 
-    var a = result
-    result = evalAux(c, n.sons[2], {efLValue})
-    if isSpecial(result): return 
-    if a.kind == nkSym and result.kind == nkSym:
-      a.sym = result.sym
-    else:
-      stackTrace(c, n.info, errFieldXNotFound, "symbol")
-    result = emptyNode
-  of mNSetIdent: 
-    result = evalAux(c, n.sons[1], {efLValue})
-    if isSpecial(result): return 
-    var a = result
-    result = evalAux(c, n.sons[2], {efLValue})
-    if isSpecial(result): return 
-    if a.kind == nkIdent and result.kind == nkIdent:
-      a.ident = result.ident
-    else:
-      stackTrace(c, n.info, errFieldXNotFound, "ident")
-    result = emptyNode
-  of mNSetType: 
-    result = evalAux(c, n.sons[1], {efLValue})
-    if isSpecial(result): return 
-    var a = result
-    result = evalAux(c, n.sons[2], {efLValue})
-    if isSpecial(result): return 
-    InternalAssert result.kind == nkSym and result.sym.kind == skType
-    a.typ = result.sym.typ
-    result = emptyNode
-  of mNSetStrVal:
-    result = evalAux(c, n.sons[1], {efLValue})
-    if isSpecial(result): return 
-    var a = result
-    result = evalAux(c, n.sons[2], {})
-    if isSpecial(result): return
-    
-    if a.kind in {nkStrLit..nkTripleStrLit} and
-        result.kind in {nkStrLit..nkTripleStrLit}:
-      a.strVal = result.strVal
-    else: stackTrace(c, n.info, errFieldXNotFound, "strVal")
-    result = emptyNode
-  of mNNewNimNode: 
-    result = evalAux(c, n.sons[1], {})
-    if isSpecial(result): return 
-    var k = getOrdValue(result)
-    result = evalAux(c, n.sons[2], {efLValue})
-    if result.kind == nkExceptBranch: return 
-    var a = result
-    if k < 0 or k > ord(high(TNodeKind)): 
-      internalError(n.info, "request to create a NimNode with invalid kind")
-    result = newNodeI(TNodeKind(int(k)), 
-      if a.kind == nkNilLit: n.info else: a.info)
-  of mNCopyNimNode:
-    result = evalAux(c, n.sons[1], {efLValue})
-    if isSpecial(result): return 
-    result = copyNode(result)
-  of mNCopyNimTree: 
-    result = evalAux(c, n.sons[1], {efLValue})
-    if isSpecial(result): return 
-    result = copyTree(result)
-  of mNBindSym:
-    # trivial implementation:
-    result = n.sons[1]
-  of mNGenSym:
-    evalX(n.sons[1], {efLValue})
-    let k = getOrdValue(result)
-    evalX(n.sons[2], {efLValue})
-    let b = result
-    let name = if b.strVal.len == 0: ":tmp" else: b.strVal
-    if k < 0 or k > ord(high(TSymKind)):
-      internalError(n.info, "request to create a symbol with invalid kind")
-    result = newSymNode(newSym(k.TSymKind, name.getIdent, c.module, n.info))
-    incl(result.sym.flags, sfGenSym)
-  of mStrToIdent: 
-    result = evalAux(c, n.sons[1], {})
-    if isSpecial(result): return 
-    if not (result.kind in {nkStrLit..nkTripleStrLit}): 
-      stackTrace(c, n.info, errFieldXNotFound, "strVal")
-      return
-    var a = result
-    result = newNodeIT(nkIdent, n.info, n.typ)
-    result.ident = getIdent(a.strVal)
-  of mIdentToStr: 
-    result = evalAux(c, n.sons[1], {})
-    if isSpecial(result): return 
-    var a = result
-    result = newNodeIT(nkStrLit, n.info, n.typ)
-    if a.kind == nkSym:
-      result.strVal = a.sym.name.s
-    else:
-      if a.kind != nkIdent: InternalError(n.info, "no ident node")
-      result.strVal = a.ident.s
-  of mEqIdent: 
-    result = evalAux(c, n.sons[1], {})
-    if isSpecial(result): return 
-    var a = result
-    result = evalAux(c, n.sons[2], {})
-    if isSpecial(result): return 
-    var b = result
-    result = newNodeIT(nkIntLit, n.info, n.typ)
-    if (a.kind == nkIdent) and (b.kind == nkIdent): 
-      if a.ident.id == b.ident.id: result.intVal = 1
-  of mEqNimrodNode: 
-    result = evalAux(c, n.sons[1], {efLValue})
-    if isSpecial(result): return 
-    var a = result
-    result = evalAux(c, n.sons[2], {efLValue})
-    if isSpecial(result): return 
-    var b = result
-    result = newNodeIT(nkIntLit, n.info, n.typ)
-    if (a == b) or
-        (b.kind in {nkNilLit, nkEmpty}) and (a.kind in {nkNilLit, nkEmpty}): 
-      result.intVal = 1
-  of mNLineInfo:
-    result = evalAux(c, n.sons[1], {})
-    if isSpecial(result): return
-    result = newStrNodeT(result.info.toFileLineCol, n)
-  of mNHint: 
-    result = evalAux(c, n.sons[1], {})
-    if isSpecial(result): return 
-    Message(n.info, hintUser, getStrValue(result))
-    result = emptyNode
-  of mNWarning: 
-    result = evalAux(c, n.sons[1], {})
-    if isSpecial(result): return 
-    Message(n.info, warnUser, getStrValue(result))
-    result = emptyNode
-  of mNError: 
-    result = evalAux(c, n.sons[1], {})
-    if isSpecial(result): return 
-    stackTrace(c, n.info, errUser, getStrValue(result))
-    result = emptyNode
-  of mConStrStr: 
-    result = evalConStrStr(c, n)
-  of mRepr: 
-    result = evalRepr(c, n)
-  of mNewString: 
-    result = evalAux(c, n.sons[1], {})
-    if isSpecial(result): return 
-    var a = result
-    result = newNodeIT(nkStrLit, n.info, n.typ)
-    result.strVal = newString(int(getOrdValue(a)))
-  of mNewStringOfCap:
-    result = evalAux(c, n.sons[1], {})
-    if isSpecial(result): return 
-    var a = result
-    result = newNodeIT(nkStrLit, n.info, n.typ)
-    result.strVal = newString(0)
-  of mNCallSite:
-    if c.callsite != nil: result = c.callsite
-    else: stackTrace(c, n.info, errFieldXNotFound, "callsite")
-  else:
-    result = evalAux(c, n.sons[1], {})
-    if isSpecial(result): return 
-    var a = result
-    var b: PNode = nil
-    var cc: PNode = nil
-    if sonsLen(n) > 2: 
-      result = evalAux(c, n.sons[2], {})
-      if isSpecial(result): return 
-      b = result
-      if sonsLen(n) > 3: 
-        result = evalAux(c, n.sons[3], {})
-        if isSpecial(result): return 
-        cc = result
-    if isEmpty(a) or isEmpty(b) or isEmpty(cc): result = emptyNode
-    else: result = evalOp(m, n, a, b, cc)
-
-proc evalAux(c: PEvalContext, n: PNode, flags: TEvalFlags): PNode =   
-  result = emptyNode
-  dec(gNestedEvals)
-  if gNestedEvals <= 0: stackTrace(c, n.info, errTooManyIterations)
-  case n.kind
-  of nkSym: result = evalSym(c, n, flags)
-  of nkType..nkNilLit, nkTypeOfExpr:
-    # nkStrLit is VERY common in the traces, so we should avoid
-    # the 'copyNode' here.
-    result = n #.copyNode
-  of nkAsgn, nkFastAsgn: result = evalAsgn(c, n)
-  of nkCommand..nkHiddenCallConv:
-    result = evalMagicOrCall(c, n)
-  of nkDotExpr: result = evalFieldAccess(c, n, flags)
-  of nkBracketExpr:
-    result = evalArrayAccess(c, n, flags)
-  of nkDerefExpr, nkHiddenDeref: result = evalDeref(c, n, flags)
-  of nkAddr, nkHiddenAddr: result = evalAddr(c, n, flags)
-  of nkHiddenStdConv, nkHiddenSubConv, nkConv: result = evalConv(c, n)
-  of nkCurly, nkBracket, nkRange:
-    # flags need to be passed here for mNAddMultiple :-(
-    # XXX this is not correct in every case!
-    var a = copyNode(n)
-    for i in countup(0, sonsLen(n) - 1): 
-      result = evalAux(c, n.sons[i], flags)
-      if isSpecial(result): return 
-      addSon(a, result)
-    result = a
-  of nkPar, nkClosure: 
-    var a = copyTree(n)
-    for i in countup(0, sonsLen(n) - 1): 
-      var it = n.sons[i]
-      if it.kind == nkExprColonExpr:
-        result = evalAux(c, it.sons[1], flags)
-        if isSpecial(result): return 
-        a.sons[i].sons[1] = result
-      else:
-        result = evalAux(c, it, flags)
-        if isSpecial(result): return 
-        a.sons[i] = result
-    result = a
-  of nkObjConstr:
-    let t = skipTypes(n.typ, abstractInst)
-    var a: PNode
-    if t.kind == tyRef:
-      result = newNodeIT(nkRefTy, n.info, t)
-      a = getNullValue(t.sons[0], n.info)
-      addSon(result, a)
-    else:
-      a = getNullValue(t, n.info)
-      result = a
-    for i in countup(1, sonsLen(n) - 1):
-      let it = n.sons[i]
-      if it.kind == nkExprColonExpr:
-        let value = evalAux(c, it.sons[1], flags)
-        if isSpecial(value): return value
-        a.sons[it.sons[0].sym.position] = value
-      else: return raiseCannotEval(c, n.info)
-  of nkWhenStmt, nkIfStmt, nkIfExpr: result = evalIf(c, n)
-  of nkWhileStmt: result = evalWhile(c, n)
-  of nkCaseStmt: result = evalCase(c, n)
-  of nkVarSection, nkLetSection: result = evalVar(c, n)
-  of nkTryStmt: result = evalTry(c, n)
-  of nkRaiseStmt: result = evalRaise(c, n)
-  of nkReturnStmt: result = evalReturn(c, n)
-  of nkBreakStmt, nkReturnToken: result = n
-  of nkBlockExpr, nkBlockStmt: result = evalBlock(c, n)
-  of nkDiscardStmt: result = evalAux(c, n.sons[0], {})
-  of nkCheckedFieldExpr: result = evalCheckedFieldAccess(c, n, flags)
-  of nkObjDownConv: result = evalAux(c, n.sons[0], flags)
-  of nkObjUpConv: result = evalUpConv(c, n, flags)
-  of nkChckRangeF, nkChckRange64, nkChckRange: result = evalRangeChck(c, n)
-  of nkStringToCString: result = evalConvStrToCStr(c, n)
-  of nkCStringToString: result = evalConvCStrToStr(c, n)
-  of nkStmtListExpr, nkStmtList: 
-    for i in countup(0, sonsLen(n) - 1): 
-      result = evalAux(c, n.sons[i], flags)
-      case result.kind
-      of nkExceptBranch, nkReturnToken, nkBreakStmt: break 
-      else: nil
-  of nkProcDef, nkMethodDef, nkMacroDef, nkCommentStmt, nkPragma,
-     nkTypeSection, nkTemplateDef, nkConstSection, nkIteratorDef,
-     nkConverterDef, nkIncludeStmt, nkImportStmt, nkFromStmt: 
-    nil
-  of nkMetaNode:
-    result = copyTree(n.sons[0])
-    result.typ = n.typ
-  of nkPragmaBlock:
-    result = evalAux(c, n.sons[1], flags)
-  of nkCast:
-    result = evalCast(c, n, flags)
-  of nkIdentDefs, nkYieldStmt, nkAsmStmt, nkForStmt, nkPragmaExpr, 
-     nkLambdaKinds, nkContinueStmt, nkIdent, nkParForStmt, nkBindStmt,
-     nkClosedSymChoice, nkOpenSymChoice:
-    result = raiseCannotEval(c, n.info)
-  of nkRefTy:
-    result = evalAux(c, n.sons[0], flags)
-  of nkEmpty: 
-    # nkEmpty occurs once in each trace that I looked at
-    result = n
-  else: InternalError(n.info, "evalAux: " & $n.kind)
-  if result == nil:
-    InternalError(n.info, "evalAux: returned nil " & $n.kind)
-  inc(gNestedEvals)
-
-proc tryEval(c: PEvalContext, n: PNode): PNode =
-  #internalAssert nfTransf in n.flags
-  var n = transformExpr(c.module, n)
-  gWhileCounter = evalMaxIterations
-  gNestedEvals = evalMaxRecDepth
-  result = evalAux(c, n, {})
-  
-proc eval*(c: PEvalContext, n: PNode): PNode = 
-  ## eval never returns nil! This simplifies the code a lot and
-  ## makes it faster too.
-  result = tryEval(c, n)
-  if result.kind == nkExceptBranch:
-    if sonsLen(result) >= 1: 
-      stackTrace(c, n.info, errUnhandledExceptionX, typeToString(result.typ))
-    else:
-      stackTrace(c, result.info, errCannotInterpretNodeX, renderTree(n))
-
-proc evalConstExprAux*(p: PEvalContext, module, prc: PSym, e: PNode): PNode =
-  var s = newStackFrame()
-  s.call = e
-  s.prc = prc
-  pushStackFrame(p, s)
-  result = tryEval(p, e)
-  if result != nil and result.kind == nkExceptBranch: result = nil
-  popStackFrame(p)
-
-proc setupMacroParam(x: PNode): PNode =
-  result = x
-  if result.kind in {nkHiddenSubConv, nkHiddenStdConv}: result = result.sons[1]
-
-proc evalMacroCall(c: PEvalContext, n, nOrig: PNode, sym: PSym): PNode =
-  # XXX GlobalError() is ugly here, but I don't know a better solution for now
-  inc(evalTemplateCounter)
-  if evalTemplateCounter > 100:
-    GlobalError(n.info, errTemplateInstantiationTooNested)
-
-  c.callsite = nOrig
-  var s = newStackFrame()
-  s.call = n
-  s.prc = sym
-  var L = n.safeLen
-  if L == 0: L = 1
-  setlen(s.slots, L)
-  # return value:
-  s.slots[0] = newNodeIT(nkNilLit, n.info, sym.typ.sons[0])
-  # setup parameters:
-  for i in 1 .. < L: s.slots[i] = setupMacroParam(n.sons[i])
-  pushStackFrame(c, s)
-  discard eval(c, optBody(c, sym))
-  result = s.slots[0]
-  popStackFrame(c)
-  if cyclicTree(result): GlobalError(n.info, errCyclicTree)
-  dec(evalTemplateCounter)
-  c.callsite = nil
-
-proc myOpen(module: PSym): PPassContext =
-  var c = newEvalContext(module, emRepl)
-  c.features = {allowCast, allowFFI, allowInfiniteLoops}
-  pushStackFrame(c, newStackFrame())
-  result = c
-
-var oldErrorCount: int
-
-proc myProcess(c: PPassContext, n: PNode): PNode =
-  # don't eval errornous code:
-  if oldErrorCount == msgs.gErrorCounter:
-    result = eval(PEvalContext(c), n)
-  else:
-    result = n
-  oldErrorCount = msgs.gErrorCounter
-
-const evalPass* = makePass(myOpen, nil, myProcess, myProcess)
-
diff --git a/compiler/lexer.nim b/compiler/lexer.nim
index 2bfd8d1eb..0e4dfc2ac 100644
--- a/compiler/lexer.nim
+++ b/compiler/lexer.nim
@@ -347,7 +347,7 @@ proc getNumber(L: var TLexer): TToken =
         result.base = base2
         while true: 
           case L.buf[pos]
-          of 'A'..'Z', 'a'..'z', '2'..'9', '.': 
+          of '2'..'9', '.': 
             lexMessage(L, errInvalidNumber, result.literal)
             inc(pos)
           of '_': 
@@ -363,7 +363,7 @@ proc getNumber(L: var TLexer): TToken =
         result.base = base8
         while true: 
           case L.buf[pos]
-          of 'A'..'Z', 'a'..'z', '8'..'9', '.': 
+          of '8'..'9', '.': 
             lexMessage(L, errInvalidNumber, result.literal)
             inc(pos)
           of '_': 
@@ -377,25 +377,22 @@ proc getNumber(L: var TLexer): TToken =
           else: break 
       of 'O': 
         lexMessage(L, errInvalidNumber, result.literal)
-      of 'x', 'X': 
+      of 'x', 'X':
         result.base = base16
-        while true: 
+        while true:
           case L.buf[pos]
-          of 'G'..'Z', 'g'..'z': 
-            lexMessage(L, errInvalidNumber, result.literal)
-            inc(pos)
-          of '_': 
-            if L.buf[pos+1] notin {'0'..'9', 'a'..'f', 'A'..'F'}: 
+          of '_':
+            if L.buf[pos+1] notin {'0'..'9', 'a'..'f', 'A'..'F'}:
               lexMessage(L, errInvalidToken, "_")
               break
             inc(pos)
-          of '0'..'9': 
+          of '0'..'9':
             xi = `shl`(xi, 4) or (ord(L.buf[pos]) - ord('0'))
             inc(pos)
-          of 'a'..'f': 
+          of 'a'..'f':
             xi = `shl`(xi, 4) or (ord(L.buf[pos]) - ord('a') + 10)
             inc(pos)
-          of 'A'..'F': 
+          of 'A'..'F':
             xi = `shl`(xi, 4) or (ord(L.buf[pos]) - ord('A') + 10)
             inc(pos)
           else: break 
@@ -424,8 +421,14 @@ proc getNumber(L: var TLexer): TToken =
       if (result.iNumber < low(int32)) or (result.iNumber > high(int32)):
         if result.tokType == tkIntLit:
           result.tokType = tkInt64Lit
-        elif result.tokType in {tkInt8Lit, tkInt16Lit}:
-          lexMessage(L, errInvalidNumber, result.literal)
+        elif result.tokType in {tkInt8Lit, tkInt16Lit, tkInt32Lit}:
+          lexMessage(L, errNumberOutOfRange, result.literal)
+      elif result.tokType == tkInt8Lit and
+          (result.iNumber < int8.low or result.iNumber > int8.high):
+        lexMessage(L, errNumberOutOfRange, result.literal)
+      elif result.tokType == tkInt16Lit and
+          (result.iNumber < int16.low or result.iNumber > int16.high):
+        lexMessage(L, errNumberOutOfRange, result.literal)
   except EInvalidValue:
     lexMessage(L, errInvalidNumber, result.literal)
   except EOverflow, EOutOfRange:
@@ -537,6 +540,10 @@ proc getString(L: var TLexer, tok: var TToken, rawMode: bool) =
     tok.tokType = tkTripleStrLit # long string literal:
     inc(pos, 2)               # skip ""
     # skip leading newline:
+    if buf[pos] in {' ', '\t'}:
+      var newpos = pos+1
+      while buf[newpos] in {' ', '\t'}: inc newpos
+      if buf[newpos] in {CR, LF}: pos = newpos
     pos = handleCRLF(L, pos)
     buf = L.buf
     while true: 
diff --git a/compiler/modules.nim b/compiler/modules.nim
index fb1940741..b102224cd 100644
--- a/compiler/modules.nim
+++ b/compiler/modules.nim
@@ -115,7 +115,7 @@ proc newModule(fileIdx: int32): PSym =
   new(result)
   result.id = - 1             # for better error checking
   result.kind = skModule
-  let filename = fileIdx.toFilename
+  let filename = fileIdx.toFullPath
   result.name = getIdent(splitFile(filename).name)
   if not isNimrodIdentifier(result.name.s):
     rawMessage(errInvalidModuleName, result.name.s)
diff --git a/compiler/parser.nim b/compiler/parser.nim
index 18de1570a..6ff0c2dfc 100644
--- a/compiler/parser.nim
+++ b/compiler/parser.nim
@@ -63,7 +63,7 @@ proc optInd*(p: var TParser, n: PNode)
 proc indAndComment*(p: var TParser, n: PNode)
 proc setBaseFlags*(n: PNode, base: TNumericalBase)
 proc parseSymbol*(p: var TParser, allowNil = false): PNode
-proc parseTry(p: var TParser): PNode
+proc parseTry(p: var TParser; isExpr: bool): PNode
 proc parseCase(p: var TParser): PNode
 # implementation
 
@@ -845,7 +845,7 @@ proc parseIdentColonEquals(p: var TParser, flags: TDeclaredIdentFlags): PNode =
     addSon(result, parseTypeDesc(p))
   else: 
     addSon(result, ast.emptyNode)
-    if (p.tok.tokType != tkEquals) and not (withBothOptional in flags): 
+    if p.tok.tokType != tkEquals and withBothOptional notin flags: 
       parMessage(p, errColonOrEqualsExpected, p.tok)
   if p.tok.tokType == tkEquals: 
     getTok(p)
@@ -1004,13 +1004,13 @@ proc parseExpr(p: var TParser): PNode =
   #| expr = (ifExpr
   #|       | whenExpr
   #|       | caseExpr
-  #|       | tryStmt)
+  #|       | tryExpr)
   #|       / simpleExpr
   case p.tok.tokType:
   of tkIf: result = parseIfExpr(p, nkIfExpr)
   of tkWhen: result = parseIfExpr(p, nkWhenExpr)
   of tkCase: result = parseCase(p)
-  of tkTry: result = parseTry(p)
+  of tkTry: result = parseTry(p, isExpr=true)
   else: result = simpleExpr(p)
 
 proc parseEnum(p: var TParser): PNode
@@ -1363,22 +1363,25 @@ proc parseCase(p: var TParser): PNode =
   if wasIndented:
     p.currInd = oldInd
     
-proc parseTry(p: var TParser): PNode =
+proc parseTry(p: var TParser; isExpr: bool): PNode =
   #| tryStmt = 'try' colcom stmt &(IND{=}? 'except'|'finally')
   #|            (IND{=}? 'except' exprList colcom stmt)*
   #|            (IND{=}? 'finally' colcom stmt)?
+  #| tryExpr = 'try' colcom stmt &(optInd 'except'|'finally')
+  #|            (optInd 'except' exprList colcom stmt)*
+  #|            (optInd 'finally' colcom stmt)?
   result = newNodeP(nkTryStmt, p)
   getTok(p)
   eat(p, tkColon)
   skipComment(p, result)
   addSon(result, parseStmt(p))
   var b: PNode = nil
-  while sameOrNoInd(p):
+  while sameOrNoInd(p) or isExpr:
     case p.tok.tokType
-    of tkExcept: 
+    of tkExcept:
       b = newNodeP(nkExceptBranch, p)
       exprList(p, tkColon, b)
-    of tkFinally: 
+    of tkFinally:
       b = newNodeP(nkFinally, p)
       getTokNoInd(p)
       eat(p, tkColon)
@@ -1877,7 +1880,7 @@ proc complexOrSimpleStmt(p: var TParser): PNode =
   of tkIf: result = parseIfOrWhen(p, nkIfStmt)
   of tkWhile: result = parseWhile(p)
   of tkCase: result = parseCase(p)
-  of tkTry: result = parseTry(p)
+  of tkTry: result = parseTry(p, isExpr=false)
   of tkFinally: result = parseExceptBlock(p, nkFinally)
   of tkExcept: result = parseExceptBlock(p, nkExceptBranch)
   of tkFor: result = parseFor(p)
diff --git a/compiler/patterns.nim b/compiler/patterns.nim
index d262790ab..5e21289b5 100644
--- a/compiler/patterns.nim
+++ b/compiler/patterns.nim
@@ -287,7 +287,7 @@ proc applyRule*(c: PContext, s: PSym, n: PNode): PNode =
         # constraint not fullfilled:
         if not ok: return nil
 
-  markUsed(n, s)
+  markUsed(n.info, s)
   if ctx.subMatch:
     assert m.len == 3
     m.sons[1] = result
diff --git a/compiler/pretty.nim b/compiler/pretty.nim
index 3a5bfe197..17311f9e6 100644
--- a/compiler/pretty.nim
+++ b/compiler/pretty.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.
@@ -149,8 +149,8 @@ proc checkDef(c: PGen; n: PNode) =
   if n.kind != nkSym: return
   checkDef(n, n.sym)
 
-proc checkUse*(n: PNode, s: PSym) =
-  if n.info.fileIndex < 0: return
+proc checkUse*(info: TLineInfo; s: PSym) =
+  if info.fileIndex < 0: return
   # we simply convert it to what it looks like in the definition
   # for consistency
   
@@ -159,10 +159,10 @@ proc checkUse*(n: PNode, s: PSym) =
   if s.kind in {skType, skGenericParam} and sfAnon in s.flags: return
   let newName = s.name.s
   
-  loadFile(n.info)
+  loadFile(info)
   
-  let line = gSourceFiles[n.info.fileIndex].lines[n.info.line-1]
-  var first = min(n.info.col.int, line.len)
+  let line = gSourceFiles[info.fileIndex].lines[info.line-1]
+  var first = min(info.col.int, line.len)
   if first < 0: return
   #inc first, skipIgnoreCase(line, "proc ", first)
   while first > 0 and line[first-1] in Letters: dec first
@@ -179,8 +179,8 @@ proc checkUse*(n: PNode, s: PSym) =
       if x.match(peg"\s* {\ident} \s* '=' \s* y$1 ('#' .*)?"):
         x = ""
     
-    system.shallowCopy(gSourceFiles[n.info.fileIndex].lines[n.info.line-1], x)
-    gSourceFiles[n.info.fileIndex].dirty = true
+    system.shallowCopy(gSourceFiles[info.fileIndex].lines[info.line-1], x)
+    gSourceFiles[info.fileIndex].dirty = true
 
 when false:
   var cannotRename = initIntSet()
@@ -220,53 +220,9 @@ when false:
         result.add s[i]
       inc i
 
-  proc checkUse(c: PGen; n: PNode) =
-    if n.info.fileIndex < 0: return
-    let s = n.sym
-    # operators stay as they are:
-    if s.kind in {skResult, skTemp} or s.name.s[0] notin Letters: return
-    if s.kind in {skType, skGenericParam} and sfAnon in s.flags: return
-    
-    if s.id in cannotRename: return
-    
-    let newName = if rules.hasKey(s.name.s): rules[s.name.s]
-                  else: beautifyName(s.name.s, n.sym.kind)
-    
-    loadFile(n.info)
-    
-    let line = gSourceFiles[n.info.fileIndex].lines[n.info.line-1]
-    var first = min(n.info.col.int, line.len)
-    if first < 0: return
-    #inc first, skipIgnoreCase(line, "proc ", first)
-    while first > 0 and line[first-1] in Letters: dec first
-    if first < 0: return
-    if line[first] == '`': inc first
-    
-    if {sfImportc, sfExportc} * s.flags != {}:
-      # careful, we must ensure the resulting name still matches the external
-      # name:
-      if newName != s.name.s and newName != s.loc.r.ropeToStr and
-          lfFullExternalName notin s.loc.flags:
-        #Message(n.info, errGenerated, 
-        #  "cannot rename $# to $# due to external name" % [s.name.s, newName])
-        cannotRename.incl(s.id)
-        return
-    let last = first+identLen(line, first)-1
-    if differ(line, first, last, newName):
-      # last-first+1 != newName.len or 
-      var x = line.subStr(0, first-1) & newName & line.substr(last+1)
-      when removeTP:
-        # the WinAPI module is full of 'TX = X' which after the substitution
-        # becomes 'X = X'. We remove those lines:
-        if x.match(peg"\s* {\ident} \s* '=' \s* y$1 ('#' .*)?"):
-          x = ""
-      
-      system.shallowCopy(gSourceFiles[n.info.fileIndex].lines[n.info.line-1], x)
-      gSourceFiles[n.info.fileIndex].dirty = true
-
 proc check(c: PGen, n: PNode) =
   case n.kind
-  of nkSym: checkUse(n, n.sym)
+  of nkSym: checkUse(n.info, n.sym)
   of nkBlockStmt, nkBlockExpr, nkBlockType:
     checkDef(c, n[0])
     check(c, n.sons[1])
diff --git a/compiler/renderer.nim b/compiler/renderer.nim
index 6b62c48c5..0b1312ccc 100644
--- a/compiler/renderer.nim
+++ b/compiler/renderer.nim
@@ -146,28 +146,29 @@ proc makeNimString(s: string): string =
   for i in countup(0, len(s)-1): add(result, toNimChar(s[i]))
   add(result, '\"')
 
-proc putComment(g: var TSrcGen, s: string) = 
+proc putComment(g: var TSrcGen, s: string) =
+  if s.isNil: return
   var i = 0
   var comIndent = 1
   var isCode = (len(s) >= 2) and (s[1] != ' ')
   var ind = g.lineLen
   var com = ""
-  while true: 
+  while true:
     case s[i]
-    of '\0': 
-      break 
-    of '\x0D': 
+    of '\0':
+      break
+    of '\x0D':
       put(g, tkComment, com)
       com = ""
       inc(i)
       if s[i] == '\x0A': inc(i)
       optNL(g, ind)
-    of '\x0A': 
+    of '\x0A':
       put(g, tkComment, com)
       com = ""
       inc(i)
       optNL(g, ind)
-    of '#': 
+    of '#':
       add(com, s[i])
       inc(i)
       comIndent = 0
@@ -175,10 +176,10 @@ proc putComment(g: var TSrcGen, s: string) =
         add(com, s[i])
         inc(i)
         inc(comIndent)
-    of ' ', '\x09': 
+    of ' ', '\x09':
       add(com, s[i])
       inc(i)
-    else: 
+    else:
       # we may break the comment into a multi-line comment if the line
       # gets too long:
       # compute length of the following word:
@@ -195,10 +196,10 @@ proc putComment(g: var TSrcGen, s: string) =
   optNL(g)
 
 proc maxLineLength(s: string): int = 
-  result = 0
+  if s.isNil: return 0
   var i = 0
   var lineLen = 0
-  while true: 
+  while true:
     case s[i]
     of '\0': 
       break 
@@ -459,7 +460,7 @@ proc lsub(n: PNode): int =
   of nkBreakStmt: result = lsub(n.sons[0]) + len("break_")
   of nkContinueStmt: result = lsub(n.sons[0]) + len("continue_")
   of nkPragma: result = lcomma(n) + 4
-  of nkCommentStmt: result = len(n.comment)
+  of nkCommentStmt: result = if n.comment.isNil: 0 else: len(n.comment)
   of nkOfBranch: result = lcomma(n, 0, - 2) + lsub(lastSon(n)) + len("of_:_")
   of nkImportAs: result = lsub(n.sons[0]) + len("_as_") + lsub(n.sons[1])
   of nkElifBranch: result = lsons(n) + len("elif_:_")
diff --git a/compiler/sem.nim b/compiler/sem.nim
index e4ef6473f..8025ef70d 100644
--- a/compiler/sem.nim
+++ b/compiler/sem.nim
@@ -305,7 +305,9 @@ proc semAfterMacroCall(c: PContext, n: PNode, s: PSym,
 
 proc semMacroExpr(c: PContext, n, nOrig: PNode, sym: PSym,
                   flags: TExprFlags = {}): PNode =
-  markUsed(n, sym)
+  pushInfoContext(nOrig.info)
+
+  markUsed(n.info, sym)
   if sym == c.p.owner:
     globalError(n.info, errRecursiveDependencyX, sym.name.s)
 
@@ -315,6 +317,7 @@ proc semMacroExpr(c: PContext, n, nOrig: PNode, sym: PSym,
   result = evalMacroCall(c.module, n, nOrig, sym)
   if efNoSemCheck notin flags:
     result = semAfterMacroCall(c, result, sym, flags)
+  popInfoContext()
 
 proc forceBool(c: PContext, n: PNode): PNode = 
   result = fitNode(c, getSysType(tyBool), n)
diff --git a/compiler/semcall.nim b/compiler/semcall.nim
index 88a7f976c..65a2d7ab8 100644
--- a/compiler/semcall.nim
+++ b/compiler/semcall.nim
@@ -251,7 +251,7 @@ proc inferWithMetatype(c: PContext, formal: PType,
 proc semResolvedCall(c: PContext, n: PNode, x: TCandidate): PNode =
   assert x.state == csMatch
   var finalCallee = x.calleeSym
-  markUsed(n.sons[0], finalCallee)
+  markUsed(n.sons[0].info, finalCallee)
   if finalCallee.ast == nil:
     internalError(n.info, "calleeSym.ast is nil") # XXX: remove this check!
   if finalCallee.ast.sons[genericParamsPos].kind != nkEmpty:
@@ -283,7 +283,7 @@ proc explicitGenericSym(c: PContext, n: PNode, s: PSym): PNode =
   var m: TCandidate
   initCandidate(c, m, s, n)
   var newInst = generateInstance(c, s, m.bindings, n.info)
-  markUsed(n, s)
+  markUsed(n.info, s)
   result = newSymNode(newInst, n.info)
 
 proc explicitGenericInstantiation(c: PContext, n: PNode, s: PSym): PNode = 
diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim
index 078e95fbe..7f97124e1 100644
--- a/compiler/semexprs.nim
+++ b/compiler/semexprs.nim
@@ -12,7 +12,7 @@
 
 proc semTemplateExpr(c: PContext, n: PNode, s: PSym,
                      flags: TExprFlags = {}): PNode =
-  markUsed(n, s)
+  markUsed(n.info, s)
   pushInfoContext(n.info)
   result = evalTemplate(n, s, getCurrOwner())
   if efNoSemCheck notin flags: result = semAfterMacroCall(c, result, s, flags)
@@ -78,7 +78,7 @@ proc inlineConst(n: PNode, s: PSym): PNode {.inline.} =
 proc semSym(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode = 
   case s.kind
   of skConst:
-    markUsed(n, s)
+    markUsed(n.info, s)
     case skipTypes(s.typ, abstractInst-{tyTypeDesc}).kind
     of  tyNil, tyChar, tyInt..tyInt64, tyFloat..tyFloat128, 
         tyTuple, tySet, tyUInt..tyUInt64:
@@ -101,7 +101,7 @@ proc semSym(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode =
   of skMacro: result = semMacroExpr(c, n, n, s, flags)
   of skTemplate: result = semTemplateExpr(c, n, s, flags)
   of skVar, skLet, skResult, skParam, skForVar:
-    markUsed(n, s)
+    markUsed(n.info, s)
     # if a proc accesses a global variable, it is not side effect free:
     if sfGlobal in s.flags:
       incl(c.p.owner.flags, sfSideEffect)
@@ -123,13 +123,13 @@ proc semSym(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode =
       n.typ = s.typ
       return n
   of skType:
-    markUsed(n, s)
+    markUsed(n.info, s)
     if s.typ.kind == tyStatic and s.typ.n != nil:
       return s.typ.n
     result = newSymNode(s, n.info)
     result.typ = makeTypeDesc(c, s.typ)
   else:
-    markUsed(n, s)
+    markUsed(n.info, s)
     result = newSymNode(s, n.info)
 
 type
@@ -253,7 +253,7 @@ proc semConv(c: PContext, n: PNode): PNode =
       let it = op.sons[i]
       let status = checkConvertible(c, result.typ, it.typ)
       if status in {convOK, convNotNeedeed}:
-        markUsed(n, it.sym)
+        markUsed(n.info, it.sym)
         markIndirect(c, it.sym)
         return it
     localError(n.info, errUseQualifier, op.sons[0].sym.name.s)
@@ -792,6 +792,10 @@ proc semIndirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode =
       n.flags.incl nfExprCall
       result = semOverloadedCallAnalyseEffects(c, n, nOrig, flags)
       if result == nil: return errorNode(c, n)
+    elif result.kind notin nkCallKinds:
+      # the semExpr() in overloadedCallOpr can even break this condition!
+      # See bug #904 of how to trigger it:
+      return result
   #result = afterCallActions(c, result, nOrig, flags)
   fixAbstractType(c, result)
   analyseIfAddressTakenInCall(c, result)
@@ -971,7 +975,7 @@ proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode =
 
   var s = qualifiedLookUp(c, n, {checkAmbiguity, checkUndeclared})
   if s != nil:
-    markUsed(n.sons[1], s)
+    markUsed(n.sons[1].info, s)
     return semSym(c, n, s, flags)
 
   n.sons[0] = semExprWithType(c, n.sons[0], flags+{efDetermineType})
@@ -994,7 +998,7 @@ proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode =
         result = newSymNode(f)
         result.info = n.info
         result.typ = ty
-        markUsed(n, f)
+        markUsed(n.info, f)
         return
     of tyTypeParamsHolders:
       return readTypeParameter(c, ty, i, n.info)
@@ -1026,7 +1030,7 @@ proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode =
     if f != nil:
       if fieldVisible(c, f):
         # is the access to a public field or in the same module or in a friend?
-        markUsed(n.sons[1], f)
+        markUsed(n.sons[1].info, f)
         n.sons[0] = makeDeref(n.sons[0])
         n.sons[1] = newSymNode(f) # we now have the correct field
         n.typ = f.typ
@@ -1039,7 +1043,7 @@ proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode =
   elif ty.kind == tyTuple and ty.n != nil: 
     f = getSymFromList(ty.n, i)
     if f != nil:
-      markUsed(n.sons[1], f)
+      markUsed(n.sons[1].info, f)
       n.sons[0] = makeDeref(n.sons[0])
       n.sons[1] = newSymNode(f)
       n.typ = f.typ
@@ -1450,7 +1454,7 @@ proc semExpandToAst(c: PContext, n: PNode): PNode =
   if expandedSym.kind == skError: return n
 
   macroCall.sons[0] = newSymNode(expandedSym, macroCall.info)
-  markUsed(n, expandedSym)
+  markUsed(n.info, expandedSym)
 
   for i in countup(1, macroCall.len-1):
     macroCall.sons[i] = semExprWithType(c, macroCall[i], {})
@@ -1881,7 +1885,7 @@ proc semBlock(c: PContext, n: PNode): PNode =
     if sfGenSym notin labl.flags:
       addDecl(c, labl)
       n.sons[0] = newSymNode(labl, n.sons[0].info)
-    suggestSym(n.sons[0], labl)
+    suggestSym(n.sons[0].info, labl)
   n.sons[1] = semExpr(c, n.sons[1])
   n.typ = n.sons[1].typ
   if isEmptyType(n.typ): n.kind = nkBlockStmt
@@ -2001,7 +2005,7 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
     var s = qualifiedLookUp(c, n.sons[0], mode)
     if s != nil: 
       if gCmd == cmdPretty and n.sons[0].kind == nkDotExpr:
-        pretty.checkUse(n.sons[0].sons[1], s)
+        pretty.checkUse(n.sons[0].sons[1].info, s)
       case s.kind
       of skMacro:
         if sfImmediate notin s.flags:
diff --git a/compiler/semfold.nim b/compiler/semfold.nim
index 712d2efd2..30e02dcc9 100644
--- a/compiler/semfold.nim
+++ b/compiler/semfold.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.
@@ -537,17 +537,18 @@ proc foldArrayAccess(m: PSym, n: PNode): PNode =
   var idx = getOrdValue(y)
   case x.kind
   of nkPar: 
-    if (idx >= 0) and (idx < sonsLen(x)): 
+    if idx >= 0 and idx < sonsLen(x):
       result = x.sons[int(idx)]
       if result.kind == nkExprColonExpr: result = result.sons[1]
     else:
       localError(n.info, errIndexOutOfBounds)
-  of nkBracket: 
-    if (idx >= 0) and (idx < sonsLen(x)): result = x.sons[int(idx)]
+  of nkBracket:
+    idx = idx - x.typ.firstOrd
+    if idx >= 0 and idx < x.len: result = x.sons[int(idx)]
     else: localError(n.info, errIndexOutOfBounds)
-  of nkStrLit..nkTripleStrLit: 
+  of nkStrLit..nkTripleStrLit:
     result = newNodeIT(nkCharLit, x.info, n.typ)
-    if (idx >= 0) and (idx < len(x.strVal)): 
+    if idx >= 0 and idx < len(x.strVal): 
       result.intVal = ord(x.strVal[int(idx)])
     elif idx == len(x.strVal): 
       discard
diff --git a/compiler/semgnrc.nim b/compiler/semgnrc.nim
index 353017bdd..934434951 100644
--- a/compiler/semgnrc.nim
+++ b/compiler/semgnrc.nim
@@ -82,7 +82,37 @@ proc lookup(c: PContext, n: PNode, flags: TSemGenericFlags,
     else:
       result = semGenericStmtSymbol(c, n, s)
   # else: leave as nkIdent
+
+proc newDot(n, b: PNode): PNode =
+  result = newNodeI(nkDotExpr, n.info)
+  result.add(n.sons[0])
+  result.add(b)
+
+proc fuzzyLookup(c: PContext, n: PNode, flags: TSemGenericFlags, 
+                 ctx: var TIntSet): PNode =
+  assert n.kind == nkDotExpr
+  let luf = if withinMixin notin flags: {checkUndeclared} else: {}
   
+  var s = qualifiedLookUp(c, n, luf)
+  if s != nil:
+    result = semGenericStmtSymbol(c, n, s)
+  else:
+    result = n
+    let n = n[1]
+    let ident = considerQuotedIdent(n)
+    var s = searchInScopes(c, ident)
+    if s != nil and s.kind in routineKinds:
+      if withinBind in flags:
+        result = newDot(result, symChoice(c, n, s, scClosed))
+      elif s.name.id in ctx:
+        result = newDot(result, symChoice(c, n, s, scForceOpen))
+      else:
+        let sym = semGenericStmtSymbol(c, n, s)
+        if sym.kind == nkSym:
+          result = newDot(result, symChoice(c, n, s, scForceOpen))
+        else:
+          result = newDot(result, sym)
+
 proc semGenericStmt(c: PContext, n: PNode, 
                     flags: TSemGenericFlags, ctx: var TIntSet): PNode =
   result = n
@@ -91,10 +121,11 @@ proc semGenericStmt(c: PContext, n: PNode,
   of nkIdent, nkAccQuoted:
     result = lookup(c, n, flags, ctx)
   of nkDotExpr:
-    let luf = if withinMixin notin flags: {checkUndeclared} else: {}
-    var s = qualifiedLookUp(c, n, luf)
-    if s != nil: result = semGenericStmtSymbol(c, n, s)
+    #let luf = if withinMixin notin flags: {checkUndeclared} else: {}
+    #var s = qualifiedLookUp(c, n, luf)
+    #if s != nil: result = semGenericStmtSymbol(c, n, s)
     # XXX for example: ``result.add`` -- ``add`` needs to be looked up here...
+    result = fuzzyLookup(c, n, flags, ctx)
   of nkEmpty, nkSym..nkNilLit:
     # see tests/compile/tgensymgeneric.nim:
     # We need to open the gensym'ed symbol again so that the instantiation
diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim
index 11399b38b..3cb9691eb 100644
--- a/compiler/semstmts.nim
+++ b/compiler/semstmts.nim
@@ -33,7 +33,7 @@ proc semBreakOrContinue(c: PContext, n: PNode): PNode =
       x.info = n.info
       incl(s.flags, sfUsed)
       n.sons[0] = x
-      suggestSym(x, s)
+      suggestSym(x.info, s)
     else:
       localError(n.info, errInvalidControlFlowX, s.name.s)
   elif (c.p.nestedLoopCounter <= 0) and (c.p.nestedBlockCounter <= 0): 
@@ -319,7 +319,7 @@ proc semIdentDef(c: PContext, n: PNode, kind: TSymKind): PSym =
     incl(result.flags, sfGlobal)
   else:
     result = semIdentWithPragma(c, kind, n, {})
-  suggestSym(n, result)
+  suggestSym(n.info, result)
 
 proc checkNilable(v: PSym) =
   if sfGlobal in v.flags and {tfNotNil, tfNeedsInit} * v.typ.flags != {}:
diff --git a/compiler/semtempl.nim b/compiler/semtempl.nim
index 84281dad5..ee8b1ccb8 100644
--- a/compiler/semtempl.nim
+++ b/compiler/semtempl.nim
@@ -59,7 +59,7 @@ proc symChoice(c: PContext, n: PNode, s: PSym, r: TSymChoiceRule): PNode =
     # (s.kind notin routineKinds or s.magic != mNone):
     # for instance 'nextTry' is both in tables.nim and astalgo.nim ...
     result = newSymNode(s, n.info)
-    markUsed(n, s)
+    markUsed(n.info, s)
   else:
     # semantic checking requires a type; ``fitNode`` deals with it
     # appropriately
diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim
index 9d38c4619..53fe4e266 100644
--- a/compiler/semtypes.nim
+++ b/compiler/semtypes.nim
@@ -281,7 +281,7 @@ proc semTypeIdent(c: PContext, n: PNode): PSym =
   else:
     result = qualifiedLookUp(c, n, {checkAmbiguity, checkUndeclared})
     if result != nil:
-      markUsed(n, result)
+      markUsed(n.info, result)
       if result.kind == skParam and result.typ.kind == tyTypeDesc:
         # This is a typedesc param. is it already bound?
         # it's not bound when it's used multiple times in the
@@ -443,14 +443,14 @@ proc semCaseBranch(c: PContext, t, branch: PNode, branchIndex: int,
     elif isRange(b):
       branch.sons[i] = semCaseBranchRange(c, t, b, covered)
     else:
+      # constant sets and arrays are allowed:
       var r = semConstExpr(c, b)
       # for ``{}`` we want to trigger the type mismatch in ``fitNode``:
-      if r.kind != nkCurly or len(r) == 0:
+      if r.kind notin {nkCurly, nkBracket} or len(r) == 0:
         checkMinSonsLen(t, 1)
         branch.sons[i] = skipConv(fitNode(c, t.sons[0].typ, r))
         inc(covered)
       else:
-        # constant sets have special rules
         # first element is special and will overwrite: branch.sons[i]:
         branch.sons[i] = semCaseBranchSetElem(c, t, r[0], covered)
         # other elements have to be added to ``branch``
@@ -562,7 +562,7 @@ proc semRecordNodeAux(c: PContext, n: PNode, check: var TIntSet, pos: var int,
     let rec = rectype.sym
     for i in countup(0, sonsLen(n)-3):
       var f = semIdentWithPragma(c, skField, n.sons[i], {sfExported})
-      suggestSym(n.sons[i], f)
+      suggestSym(n.sons[i].info, f)
       f.typ = typ
       f.position = pos
       if (rec != nil) and ({sfImportc, sfExportc} * rec.flags != {}) and
@@ -827,7 +827,7 @@ proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode,
       result = addImplicitGeneric(newTypeS(tyAnything, c))
   
   of tyGenericParam:
-    markUsed(genericParams, paramType.sym)
+    markUsed(info, paramType.sym)
     if tfWildcard in paramType.flags:
       paramType.flags.excl tfWildcard
       paramType.sym.kind = skType
@@ -864,7 +864,13 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode,
   var counter = 0
   for i in countup(1, n.len - 1):
     var a = n.sons[i]
-    if a.kind != nkIdentDefs: illFormedAst(a)
+    if a.kind != nkIdentDefs:
+      # for some generic instantiations the passed ':env' parameter
+      # for closures has already been produced (see bug #898). We simply
+      # skip this parameter here. It'll then be re-generated in another LL
+      # pass over this instantiation:
+      if a.kind == nkSym and sfFromGeneric in a.sym.flags: continue
+      illFormedAst(a)
     checkMinSonsLen(a, 3)
     var
       typ: PType = nil
@@ -1181,7 +1187,7 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
       else: 
         assignType(prev, t)
         result = prev
-      markUsed(n, n.sym)
+      markUsed(n.info, n.sym)
     else:
       if n.sym.kind != skError: localError(n.info, errTypeExpected)
       result = newOrPrevType(tyError, prev, c)
diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim
index 551e21d78..e5bf08097 100644
--- a/compiler/sigmatch.nim
+++ b/compiler/sigmatch.nim
@@ -62,7 +62,7 @@ type
 const
   isNilConversion = isConvertible # maybe 'isIntConv' fits better?
     
-proc markUsed*(n: PNode, s: PSym)
+proc markUsed*(info: TLineInfo, s: PSym)
 
 proc initCandidateAux(ctx: PContext,
                       c: var TCandidate, callee: PType) {.inline.} =
@@ -1058,7 +1058,7 @@ proc userConvMatch(c: PContext, m: var TCandidate, f, a: PType,
       dest = generateTypeInstance(c, m.bindings, arg, dest)
     let fdest = typeRel(m, f, dest)
     if fdest in {isEqual, isGeneric}: 
-      markUsed(arg, c.converters[i])
+      markUsed(arg.info, c.converters[i])
       var s = newSymNode(c.converters[i])
       s.typ = c.converters[i].typ
       s.info = arg.info
@@ -1271,7 +1271,7 @@ proc paramTypesMatch*(m: var TCandidate, f, a: PType,
       result = nil
     else: 
       # only one valid interpretation found:
-      markUsed(arg, arg.sons[best].sym)
+      markUsed(arg.info, arg.sons[best].sym)
       result = paramTypesMatchAux(m, f, arg.sons[best].typ, arg.sons[best],
                                   argOrig)
 
diff --git a/compiler/suggest.nim b/compiler/suggest.nim
index db95c480f..c2bdfc5c3 100644
--- a/compiler/suggest.nim
+++ b/compiler/suggest.nim
@@ -246,18 +246,18 @@ var
   usageSym*: PSym
   lastLineInfo: TLineInfo
 
-proc findUsages(node: PNode, s: PSym) =
-  if usageSym == nil and isTracked(node.info, s.name.s.len):
+proc findUsages(info: TLineInfo; s: PSym) =
+  if usageSym == nil and isTracked(info, s.name.s.len):
     usageSym = s
     suggestWriteln(symToStr(s, isLocal=false, sectionUsage))
   elif s == usageSym:
-    if lastLineInfo != node.info:
-      suggestWriteln(symToStr(s, isLocal=false, sectionUsage, node.info))
-    lastLineInfo = node.info
+    if lastLineInfo != info:
+      suggestWriteln(symToStr(s, isLocal=false, sectionUsage, info))
+    lastLineInfo = info
 
-proc findDefinition(node: PNode, s: PSym) =
-  if node.isNil or s.isNil: return
-  if isTracked(node.info, s.name.s.len):
+proc findDefinition(info: TLineInfo; s: PSym) =
+  if s.isNil: return
+  if isTracked(info, s.name.s.len):
     suggestWriteln(symToStr(s, isLocal=false, sectionDef))
     suggestQuit()
 
@@ -316,26 +316,26 @@ proc defFromSourceMap*(i: TLineInfo) =
   
   defFromLine(gSourceMaps[i.fileIndex].lines[i.line].entries, i.col)
 
-proc suggestSym*(n: PNode, s: PSym) {.inline.} =
+proc suggestSym*(info: TLineInfo; s: PSym) {.inline.} =
   ## misnamed: should be 'symDeclared'
   if optUsages in gGlobalOptions:
-    findUsages(n, s)
+    findUsages(info, s)
   if optDef in gGlobalOptions:
-    findDefinition(n, s)
-  if isServing and not n.isNil:
-    addToSourceMap(s, n.info)
+    findDefinition(info, s)
+  if isServing:
+    addToSourceMap(s, info)
 
-proc markUsed(n: PNode, s: PSym) =
+proc markUsed(info: TLineInfo; s: PSym) =
   incl(s.flags, sfUsed)
   if {sfDeprecated, sfError} * s.flags != {}:
-    if sfDeprecated in s.flags: message(n.info, warnDeprecated, s.name.s)
-    if sfError in s.flags: localError(n.info, errWrongSymbolX, s.name.s)
-  suggestSym(n, s)
-  if gCmd == cmdPretty: checkUse(n, s)
+    if sfDeprecated in s.flags: message(info, warnDeprecated, s.name.s)
+    if sfError in s.flags: localError(info, errWrongSymbolX, s.name.s)
+  suggestSym(info, s)
+  if gCmd == cmdPretty: checkUse(info, s)
 
 proc useSym*(sym: PSym): PNode =
   result = newSymNode(sym)
-  markUsed(result, sym)
+  markUsed(result.info, sym)
 
 proc suggestExpr*(c: PContext, node: PNode) = 
   var cp = msgs.inCheckpoint(node.info)
diff --git a/compiler/transf.nim b/compiler/transf.nim
index fb5e321b6..dece1ac18 100644
--- a/compiler/transf.nim
+++ b/compiler/transf.nim
@@ -546,7 +546,7 @@ proc flattenTree(root: PNode): PNode =
     flattenTreeAux(result, root, op)
   else: 
     result = root
-  
+
 proc transformCall(c: PTransf, n: PNode): PTransNode = 
   var n = flattenTree(n)
   var op = getMergeOp(n)
@@ -565,6 +565,9 @@ proc transformCall(c: PTransf, n: PNode): PTransNode =
           inc(j)
       add(result, a.PTransNode)
     if len(result) == 2: result = result[1]
+  elif getMagic(n) == mNBindSym:
+    # for bindSym(myconst) we MUST NOT perform constant folding:
+    result = n.PTransNode
   else:
     let s = transformSons(c, n).PNode
     # bugfix: check after 'transformSons' if it's still a method call:
diff --git a/compiler/vm.nim b/compiler/vm.nim
index 0c2c23987..66595856a 100644
--- a/compiler/vm.nim
+++ b/compiler/vm.nim
@@ -138,6 +138,9 @@ proc createStrKeepNode(x: var TFullReg) =
 template createStr(x) =
   x.node = newNode(nkStrLit)
 
+template createSet(x) =
+  x.node = newNode(nkCurly)
+
 proc moveConst(x: var TFullReg, y: TFullReg) =
   if x.kind != y.kind:
     myreset(x)
@@ -435,7 +438,6 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
       if regs[rc].intVal > high(int):
         stackTrace(c, tos, pc, errIndexOutOfBounds)
       let idx = regs[rc].intVal.int
-      # XXX what if the array is not 0-based? -> codegen should insert a sub
       let src = regs[rb].node
       if src.kind notin {nkEmpty..nkNilLit} and idx <% src.len:
         regs[ra].node = src.sons[idx]
@@ -501,13 +503,13 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
       else:
         stackTrace(c, tos, pc, errNilAccess)
     of opcWrDeref:
-      # a[] = b
+      # a[] = c; b unused
       let ra = instr.regA
-      let rb = instr.regB
+      let rc = instr.regC
       case regs[ra].kind
-      of rkNodeAddr: putIntoNode(regs[ra].nodeAddr[], regs[rb])
-      of rkRegisterAddr: regs[ra].regAddr[] = regs[rb]
-      of rkNode: putIntoNode(regs[ra].node, regs[rb])
+      of rkNodeAddr: putIntoNode(regs[ra].nodeAddr[], regs[rc])
+      of rkRegisterAddr: regs[ra].regAddr[] = regs[rc]
+      of rkNode: putIntoNode(regs[ra].node, regs[rc])
       else: stackTrace(c, tos, pc, errNilAccess)
     of opcAddInt:
       decodeBC(rkInt)
@@ -669,14 +671,11 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
     of opcLtu:
       decodeBC(rkInt)
       regs[ra].intVal = ord(regs[rb].intVal <% regs[rc].intVal)
-    of opcEqRef:
+    of opcEqRef, opcEqNimrodNode:
       decodeBC(rkInt)
       regs[ra].intVal = ord((regs[rb].node.kind == nkNilLit and
                              regs[rc].node.kind == nkNilLit) or
                              regs[rb].node == regs[rc].node)
-    of opcEqNimrodNode:
-      decodeBC(rkInt)
-      regs[ra].intVal = ord(regs[rb].node == regs[rc].node)
     of opcXor:
       decodeBC(rkInt)
       regs[ra].intVal = ord(regs[rb].intVal != regs[rc].intVal)
@@ -722,18 +721,22 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
       regs[ra].intVal = ord(containsSets(a, b) and not equalSets(a, b))
     of opcMulSet:
       decodeBC(rkNode)
+      createSet(regs[ra])
       move(regs[ra].node.sons, 
             nimsets.intersectSets(regs[rb].node, regs[rc].node).sons)
     of opcPlusSet: 
       decodeBC(rkNode)
+      createSet(regs[ra])
       move(regs[ra].node.sons,
            nimsets.unionSets(regs[rb].node, regs[rc].node).sons)
     of opcMinusSet:
       decodeBC(rkNode)
+      createSet(regs[ra])
       move(regs[ra].node.sons,
            nimsets.diffSets(regs[rb].node, regs[rc].node).sons)
     of opcSymdiffSet:
       decodeBC(rkNode)
+      createSet(regs[ra])
       move(regs[ra].node.sons,
            nimsets.symdiffSets(regs[rb].node, regs[rc].node).sons)    
     of opcConcatStr:
@@ -744,11 +747,11 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
         regs[ra].node.strVal.add getstr(regs[i])
     of opcAddStrCh:
       decodeB(rkNode)
-      createStrKeepNode regs[ra]
+      #createStrKeepNode regs[ra]
       regs[ra].node.strVal.add(regs[rb].intVal.chr)
     of opcAddStrStr:
       decodeB(rkNode)
-      createStrKeepNode regs[ra]
+      #createStrKeepNode regs[ra]
       regs[ra].node.strVal.add(regs[rb].node.strVal)
     of opcAddSeqElem:
       decodeB(rkNode)
@@ -899,10 +902,10 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
       c.exceptionInstr = pc
       let (newPc, newTos) = cleanUpOnException(c, tos)
       # -1 because of the following 'inc'
-      if pc-1 < 0:
+      if newPc-1 < 0:
         bailOut(c, tos)
         return
-      pc = newPc -1
+      pc = newPc-1
       if tos != newTos:
         tos = newTos
         move(regs, tos.slots)
@@ -985,7 +988,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
         return TFullReg(kind: rkNone)
     of opcSetLenStr:
       decodeB(rkNode)
-      createStrKeepNode regs[ra]
+      #createStrKeepNode regs[ra]
       regs[ra].node.strVal.setLen(regs[rb].intVal.int)
     of opcOf:
       decodeBC(rkInt)
diff --git a/compiler/vmgen.nim b/compiler/vmgen.nim
index 305ea7f9e..c1ec637dd 100644
--- a/compiler/vmgen.nim
+++ b/compiler/vmgen.nim
@@ -9,6 +9,24 @@
 
 ## This module implements the code generator for the VM.
 
+# Important things to remember:
+# - The VM does not distinguish between definitions ('var x = y') and
+#   assignments ('x = y'). For simple data types that fit into a register
+#   this doesn't matter. However it matters for strings and other complex
+#   types that use the 'node' field; the reason is that slots are
+#   re-used in a register based VM. Example:
+# 
+# .. code-block:: nimrod
+#   let s = a & b  # no matter what, create fresh node
+#   s = a & b  # no matter what, keep the node
+#
+# Also *stores* into non-temporary memory need to perform deep copies:
+# a.b = x.y
+# We used to generate opcAsgn for the *load* of 'x.y' but this is clearly
+# wrong! We need to produce opcAsgn (the copy) for the *store*. This also
+# solves the opcLdConst vs opcAsgnConst issue. Of course whether we need
+# this copy depends on the involved types.
+
 import
   unsigned, strutils, ast, astalgo, types, msgs, renderer, vmdef, 
   trees, intsets, rodread, magicsys, options, lowerings
@@ -84,21 +102,27 @@ proc gABI(c: PCtx; n: PNode; opc: TOpcode; a, b: TRegister; imm: BiggestInt) =
   # Takes the `b` register and the immediate `imm`, appies the operation `opc`,
   # and stores the output value into `a`.
   # `imm` is signed and must be within [-127, 128]
-  assert(imm >= -127 and imm <= 128)
-  let ins = (opc.uint32 or (a.uint32 shl 8'u32) or
-                           (b.uint32 shl 16'u32) or
-                           (imm+byteExcess).uint32 shl 24'u32).TInstr
-  c.code.add(ins)
-  c.debug.add(n.info)
+  if imm >= -127 and imm <= 128:
+    let ins = (opc.uint32 or (a.uint32 shl 8'u32) or
+                             (b.uint32 shl 16'u32) or
+                             (imm+byteExcess).uint32 shl 24'u32).TInstr
+    c.code.add(ins)
+    c.debug.add(n.info)
+  else:
+    localError(n.info, errGenerated,
+      "VM: immediate value does not fit into an int8")
 
 proc gABx(c: PCtx; n: PNode; opc: TOpcode; a: TRegister = 0; bx: int) =
   # Applies `opc` to `bx` and stores it into register `a`
   # `bx` must be signed and in the range [-32767, 32768]
-  assert(bx >= -32767 and bx <= 32768)
-  let ins = (opc.uint32 or a.uint32 shl 8'u32 or 
-            (bx+wordExcess).uint32 shl 16'u32).TInstr
-  c.code.add(ins)
-  c.debug.add(n.info)
+  if bx >= -32767 and bx <= 32768:
+    let ins = (opc.uint32 or a.uint32 shl 8'u32 or 
+              (bx+wordExcess).uint32 shl 16'u32).TInstr
+    c.code.add(ins)
+    c.debug.add(n.info)
+  else:
+    localError(n.info, errGenerated,
+      "VM: immediate value does not fit into an int16")
 
 proc xjmp(c: PCtx; n: PNode; opc: TOpcode; a: TRegister = 0): TPosition =
   #assert opc in {opcJmp, opcFJmp, opcTJmp}
@@ -485,11 +509,22 @@ proc genField(n: PNode): TRegister =
         "too large offset! cannot generate code for: " & s.name.s)
   result = s.position
 
+proc genIndex(c: PCtx; n: PNode; arr: PType): TRegister =
+  if arr.skipTypes(abstractInst).kind == tyArray and (let x = firstOrd(arr);
+      x != 0):
+    let tmp = c.genx(n)
+    # freeing the temporary here means we can produce:  regA = regA - Imm
+    c.freeTemp(tmp)
+    result = c.getTemp(n.typ)
+    c.gABI(n, opcSubImmInt, result, tmp, x.int)
+  else:
+    result = c.genx(n)
+
 proc genAsgnPatch(c: PCtx; le: PNode, value: TRegister) =
   case le.kind
   of nkBracketExpr:
     let dest = c.genx(le.sons[0], {gfAddrOf})
-    let idx = c.genx(le.sons[1])
+    let idx = c.genIndex(le.sons[1], le.sons[0].typ)
     c.gABC(le, opcWrArr, dest, idx, value)
     c.freeTemp(dest)
     c.freeTemp(idx)
@@ -502,12 +537,12 @@ proc genAsgnPatch(c: PCtx; le: PNode, value: TRegister) =
     c.freeTemp(dest)
   of nkDerefExpr, nkHiddenDeref:
     let dest = c.genx(le.sons[0], {gfAddrOf})
-    c.gABC(le, opcWrDeref, dest, value)
+    c.gABC(le, opcWrDeref, dest, 0, value)
     c.freeTemp(dest)
   of nkSym:
     if le.sym.isGlobal:
       let dest = c.genx(le, {gfAddrOf})
-      c.gABC(le, opcWrDeref, dest, value)
+      c.gABC(le, opcWrDeref, dest, 0, value)
       c.freeTemp(dest)
   else:
     discard
@@ -1068,17 +1103,36 @@ proc checkCanEval(c: PCtx; n: PNode) =
         not s.isOwnedBy(c.prc.sym) and s.owner != c.module:
       cannotEval(n)
 
+proc isTemp(c: PCtx; dest: TDest): bool =
+  result = dest >= 0 and c.prc.slots[dest].kind >= slotTempUnknown
+
+template needsAdditionalCopy(n): expr =
+  not c.isTemp(dest) and not fitsRegister(n.typ)
+
+proc preventFalseAlias(c: PCtx; n: PNode; opc: TOpcode;
+                       dest, idx, value: TRegister) =
+  # opcLdObj et al really means "load address". We sometimes have to create a
+  # copy in order to not introduce false aliasing:
+  # mylocal = a.b  # needs a copy of the data!
+  if needsAdditionalCopy(n):
+    var cc = c.getTemp(n.typ)
+    c.gABC(n, whichAsgnOpc(n), cc, value)
+    c.gABC(n, opc, dest, idx, cc)
+    c.freeTemp(cc)
+  else:
+    c.gABC(n, opc, dest, idx, value)
+
 proc genAsgn(c: PCtx; le, ri: PNode; requiresCopy: bool) =
   case le.kind
   of nkBracketExpr:
     let dest = c.genx(le.sons[0], {gfAddrOf})
-    let idx = c.genx(le.sons[1])
+    let idx = c.genIndex(le.sons[1], le.sons[0].typ)
     let tmp = c.genx(ri)
     if le.sons[0].typ.skipTypes(abstractVarRange-{tyTypeDesc}).kind in {
         tyString, tyCString}:
-      c.gABC(le, opcWrStrIdx, dest, idx, tmp)
+      c.preventFalseAlias(le, opcWrStrIdx, dest, idx, tmp)
     else:
-      c.gABC(le, opcWrArr, dest, idx, tmp)
+      c.preventFalseAlias(le, opcWrArr, dest, idx, tmp)
     c.freeTemp(tmp)
   of nkDotExpr, nkCheckedFieldExpr:
     # XXX field checks here
@@ -1086,12 +1140,12 @@ proc genAsgn(c: PCtx; le, ri: PNode; requiresCopy: bool) =
     let dest = c.genx(left.sons[0], {gfAddrOf})
     let idx = genField(left.sons[1])
     let tmp = c.genx(ri)
-    c.gABC(left, opcWrObj, dest, idx, tmp)
+    c.preventFalseAlias(left, opcWrObj, dest, idx, tmp)
     c.freeTemp(tmp)
   of nkDerefExpr, nkHiddenDeref:
     let dest = c.genx(le.sons[0], {gfAddrOf})
     let tmp = c.genx(ri)
-    c.gABC(le, opcWrDeref, dest, tmp)
+    c.preventFalseAlias(le, opcWrDeref, dest, 0, tmp)
     c.freeTemp(tmp)
   of nkSym:
     let s = le.sym
@@ -1100,24 +1154,32 @@ proc genAsgn(c: PCtx; le, ri: PNode; requiresCopy: bool) =
       withTemp(tmp, le.typ):
         c.gen(le, tmp, {gfAddrOf})
         let val = c.genx(ri)
-        c.gABC(le, opcWrDeref, tmp, val)
+        c.preventFalseAlias(le, opcWrDeref, tmp, 0, val)
         c.freeTemp(val)
     else:
       if s.kind == skForVar: c.setSlot s
       internalAssert s.position > 0 or (s.position == 0 and
                                         s.kind in {skParam,skResult})
       var dest: TRegister = s.position + ord(s.kind == skParam)
-      gen(c, ri, dest)
+      if needsAdditionalCopy(le) and s.kind in {skResult, skVar, skParam}:
+        var cc = c.getTemp(le.typ)
+        gen(c, ri, cc)
+        c.gABC(le, whichAsgnOpc(le), dest, cc)
+        c.freeTemp(cc)
+      else:
+        gen(c, ri, dest)
   else:
     let dest = c.genx(le, {gfAddrOf})
     genAsgn(c, dest, ri, requiresCopy)
 
 proc genLit(c: PCtx; n: PNode; dest: var TDest) =
-  var opc = opcLdConst
+  # opcLdConst is now always valid. We produce the necessary copy in the
+  # assignments now:
+  #var opc = opcLdConst
   if dest < 0: dest = c.getTemp(n.typ)
-  elif c.prc.slots[dest].kind == slotFixedVar: opc = opcAsgnConst
+  #elif c.prc.slots[dest].kind == slotFixedVar: opc = opcAsgnConst
   let lit = genLiteral(c, n)
-  c.gABx(n, opc, dest, lit)
+  c.gABx(n, opcLdConst, dest, lit)
 
 proc genTypeLit(c: PCtx; t: PType; dest: var TDest) =
   var n = newNode(nkType)
@@ -1146,7 +1208,7 @@ proc genGlobalInit(c: PCtx; n: PNode; s: PSym) =
   let dest = c.getTemp(s.typ)
   c.gABx(n, opcLdGlobal, dest, s.position)
   let tmp = c.genx(s.ast)
-  c.gABC(n, opcWrDeref, dest, tmp)
+  c.preventFalseAlias(n, opcWrDeref, dest, 0, tmp)
   c.freeTemp(dest)
   c.freeTemp(tmp)
 
@@ -1182,12 +1244,15 @@ proc genRdVar(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags) =
       # see tests/t99bott for an example that triggers it:
       cannotEval(n)
 
+template needsRegLoad(): expr =
+  gfAddrOf notin flags and fitsRegister(n.typ.skipTypes({tyVar}))
+
 proc genArrAccess2(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], {})
+  let b = c.genIndex(n.sons[1], n.sons[0].typ)
   if dest < 0: dest = c.getTemp(n.typ)
-  if gfAddrOf notin flags and fitsRegister(n.typ):
+  if needsRegLoad():
     var cc = c.getTemp(n.typ)
     c.gABC(n, opc, cc, a, b)
     c.gABC(n, opcNodeToReg, dest, cc)
@@ -1203,7 +1268,7 @@ proc genObjAccess(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags) =
   let a = c.genx(n.sons[0], flags)
   let b = genField(n.sons[1])
   if dest < 0: dest = c.getTemp(n.typ)
-  if gfAddrOf notin flags and fitsRegister(n.typ.skipTypes({tyVar})):
+  if needsRegLoad():
     var cc = c.getTemp(n.typ)
     c.gABC(n, opcLdObj, cc, a, b)
     c.gABC(n, opcNodeToReg, dest, cc)
@@ -1303,7 +1368,7 @@ proc genVarSection(c: PCtx; n: PNode) =
         if a.sons[2].kind != nkEmpty:
           let tmp = c.genx(a.sons[0], {gfAddrOf})
           let val = c.genx(a.sons[2])
-          c.gABC(a, opcWrDeref, tmp, val)
+          c.preventFalseAlias(a, opcWrDeref, tmp, 0, val)
           c.freeTemp(val)
           c.freeTemp(tmp)
       else:
@@ -1311,7 +1376,16 @@ proc genVarSection(c: PCtx; n: PNode) =
         if a.sons[2].kind == nkEmpty:
           c.gABx(a, ldNullOpcode(s.typ), s.position, c.genType(s.typ))
         else:
-          gen(c, a.sons[2], s.position.TRegister)
+          if not fitsRegister(s.typ):
+            c.gABx(a, ldNullOpcode(s.typ), s.position, c.genType(s.typ))
+          let le = a.sons[0]
+          if not fitsRegister(le.typ) and s.kind in {skResult, skVar, skParam}:
+            var cc = c.getTemp(le.typ)
+            gen(c, a.sons[2], cc)
+            c.gABC(le, whichAsgnOpc(le), s.position.TRegister, cc)
+            c.freeTemp(cc)
+          else:
+            gen(c, a.sons[2], s.position.TRegister)
     else:
       # assign to a.sons[0]; happens for closures
       if a.sons[2].kind == nkEmpty:
@@ -1339,7 +1413,7 @@ proc genArrayConstr(c: PCtx, n: PNode, dest: var TDest) =
     c.gABx(n, opcLdNullReg, tmp, c.genType(intType))
     for x in n:
       let a = c.genx(x)
-      c.gABC(n, whichAsgnOpc(x, opcWrArr), dest, tmp, a)
+      c.preventFalseAlias(n, whichAsgnOpc(x, opcWrArr), dest, tmp, a)
       c.gABI(n, opcAddImmInt, tmp, tmp, 1)
       c.freeTemp(a)
     c.freeTemp(tmp)
@@ -1371,7 +1445,8 @@ proc genObjConstr(c: PCtx, n: PNode, dest: var TDest) =
     if it.kind == nkExprColonExpr and it.sons[0].kind == nkSym:
       let idx = genField(it.sons[0])
       let tmp = c.genx(it.sons[1])
-      c.gABC(it, whichAsgnOpc(it.sons[1], opcWrObj), dest, idx, tmp)
+      c.preventFalseAlias(it.sons[1], whichAsgnOpc(it.sons[1], opcWrObj),
+                          dest, idx, tmp)
       c.freeTemp(tmp)
     else:
       internalError(n.info, "invalid object constructor")
@@ -1385,11 +1460,12 @@ proc genTupleConstr(c: PCtx, n: PNode, dest: var TDest) =
     if it.kind == nkExprColonExpr:
       let idx = genField(it.sons[0])
       let tmp = c.genx(it.sons[1])
-      c.gABC(it, whichAsgnOpc(it.sons[1], opcWrObj), dest, idx, tmp)
+      c.preventFalseAlias(it.sons[1], whichAsgnOpc(it.sons[1], opcWrObj),
+                          dest, idx, tmp)
       c.freeTemp(tmp)
     else:
       let tmp = c.genx(it)
-      c.gABC(it, whichAsgnOpc(it, opcWrObj), dest, i.TRegister, tmp)
+      c.preventFalseAlias(it, whichAsgnOpc(it, opcWrObj), dest, i.TRegister, tmp)
       c.freeTemp(tmp)
 
 proc genProc*(c: PCtx; s: PSym): int
@@ -1627,7 +1703,7 @@ 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 == "find":
+    #if s.name.s == "calc":
     #  echo renderTree(body)
     #  c.echoCode(result)
     c.prc = oldPrc
diff --git a/doc/advopt.txt b/doc/advopt.txt
index f5ff90791..08465e457 100644
--- a/doc/advopt.txt
+++ b/doc/advopt.txt
@@ -2,6 +2,7 @@ Advanced commands:
   //compileToC, cc          compile project with C code generator
   //compileToCpp, cpp       compile project to C++ code
   //compileToOC, objc       compile project to Objective C code
+  //js                      compile project to Javascript
   //rst2html                convert a reStructuredText file to HTML
   //rst2tex                 convert a reStructuredText file to TeX
   //jsondoc                 extract the documentation to a json file
diff --git a/doc/backends.txt b/doc/backends.txt
new file mode 100644
index 000000000..26576e733
--- /dev/null
+++ b/doc/backends.txt
@@ -0,0 +1,409 @@
+================================
+   Nimrod Backend Integration
+================================
+
+:Author: Puppet Master
+:Version: |nimrodversion|
+
+.. contents::
+  "Heresy grows from idleness." -- Unknown.
+
+
+Introduction
+============
+
+The `Nimrod Compiler User Guide <nimrodc.html>`_ documents the typical
+compiler invocation, using the ``compile`` or ``c`` command to transform a
+``.nim`` file into one or more ``.c`` files which are then compiled with the
+platform's C compiler into a static binary. However there are other commands
+to compile to C++, Objective-C or JavaScript. This document tries to
+concentrate in a single place all the backend and interfacing options.
+
+The Nimrod compiler supports mainly two backend families: the C, C++ and
+Objective-C targets and the JavaScript target. `The C like targets`_ creates
+source files which can be compiled into a library or a final executable. `The
+JavaScript target`_ can generate a ``.js`` file which you reference from an
+HTML file or create a `standalone nodejs program <http://nodejs.org>`_.
+
+On top of generating libraries or standalone applications, Nimrod offers
+bidirectional interfacing with the backend targets through generic and
+specific pragmas.
+
+
+Backends
+========
+
+The C like targets
+------------------
+
+The commands to compile to either C, C++ or Objective-C are:
+
+  //compileToC, cc          compile project with C code generator
+  //compileToCpp, cpp       compile project to C++ code
+  //compileToOC, objc       compile project to Objective C code
+
+The most significant difference between these commands is that if you look
+into the ``nimcache`` directory you will find ``.c``, ``.cpp`` or ``.m``
+files, other than that all of them will produce a native binary for your
+project.  This allows you to take the generated code and place it directly
+into a project using any of these languages. Here are some typical command
+line invocations::
+
+    $ nimrod c hallo.nim
+    $ nimrod cpp hallo.nim
+    $ nimrod objc hallo.nim
+
+The compiler commands select the target backend, but if needed you can
+`specify additional switches for cross compilation
+<nimrodc.html#cross-compilation>`_ to select the target CPU, operative system
+or compiler/linker commands.
+
+
+The JavaScript target
+---------------------
+
+Nimrod can also generate `JavaScript`:idx: code through the ``js`` command.
+However, the JavaScript code generator is experimental!
+
+Nimrod targets JavaScript 1.5 which is supported by any widely used browser.
+Since JavaScript does not have a portable means to include another module,
+Nimrod just generates a long ``.js`` file.
+
+Features or modules that the JavaScript platform does not support are not
+available. This includes:
+
+* manual memory management (``alloc``, etc.)
+* casting and other unsafe operations (``cast`` operator, ``zeroMem``, etc.)
+* file management
+* most modules of the Standard library
+* proper 64 bit integer arithmetic
+* unsigned integer arithmetic
+
+However, the modules `strutils <strutils.html>`_, `math <math.html>`_, and
+`times <times.html>`_ are available! To access the DOM, use the `dom
+<dom.html>`_ module that is only available for the JavaScript platform.
+
+To compile a Nimrod module into a ``.js`` file use the ``js`` command; the
+default is a ``.js`` file that is supposed to be referenced in an ``.html``
+file. However, you can also run the code with `nodejs`:idx:, a `software
+platform for easily building fast, scalable network applications
+<http://nodejs.org>`_::
+
+  nimrod js -d:nodejs -r examples/hallo.nim
+
+
+Interfacing
+===========
+
+Nimrod offers bidirectional interfacing with the target backend. This means
+that you can call backend code from Nimrod and Nimrod code can be called by
+the backend code. Usually the direction of which calls which depends on your
+software architecture (is Nimrod your main program or is Nimrod providing a
+component?).
+
+
+Nimrod code calling the backend
+--------------------------------
+
+Nimrod code can interface with the backend through the `Foreign function
+interface <manual.html#foreign-function-interface>`_ mainly through the
+`importc pragma <manual.html#importc-pragma>`_. The ``importc`` pragma is the
+*generic* way of making backend symbols available in Nimrod and is available
+in all the target backends (JavaScript too).  The C++ or Objective-C backends
+have their respective `ImportCpp <nimrodc.html#importcpp-pragma>`_ and
+`ImportObjC <nimrodc.html#importobjc-pragma>`_ pragmas to call methods from
+classes.
+
+Whenever you use any of these pragmas you need to integrate native code into
+your final binary. In the case of JavaScript this is no problem at all, the
+same html file which hosts the generated JavaScript will likely provide other
+JavaScript functions which you are importing with ``importc``.
+
+However, for the C like targets you need to link external code either
+statically or dynamically. The preferred way of integrating native code is to
+use dynamic linking because it allows you to compile Nimrod programs without
+the need for having the related development libraries installed. This is done
+through the `dynlib pragma for import
+<manual.html#dynlib-pragma-for-import>`_, though more specific control can be
+gained using the `dynlib module <dynlib.html>`_.
+
+The `dynlibOverride <nimrodc.html#dynliboverride>`_ command line switch allows
+to avoid dynamic linking if you need to statically link something instead.
+Nimrod wrappers designed to statically link source files can use the `compile
+pragma <nimrodc.html#compile-pragma>`_ if there are few sources or providing
+them along the Nimrod code is easier than using a system library. Libraries
+installed on the host system can be linked in with the `PassL pragma
+<nimrodc.html#passl-pragma>`_.
+
+To wrap native code, take a look at the `c2nim tool <c2nim.html>`_ which helps
+with the process of scanning and transforming header files into a Nimrod
+interface.
+
+C invocation example
+~~~~~~~~~~~~~~~~~~~~
+
+Create a ``logic.c`` file with the following content:
+
+.. code-block:: c
+  int addTwoIntegers(int a, int b)
+  {
+    return a + b;
+  }
+
+Create a ``calculator.nim`` file with the following content:
+
+.. code-block:: nimrod
+
+  {.compile: "logic.c".}
+  proc addTwoIntegers(a, b: cint): cint {.importc.}
+
+  when isMainModule:
+    echo addTwoIntegers(3, 7)
+
+With these two files in place, you can run ``nimrod c -r calculator.nim`` and
+the Nimrod compiler will compile the ``logic.c`` file in addition to
+``calculator.nim`` and link both into an executable, which outputs ``10`` when
+run. Another way to link the C file statically and get the same effect would
+be remove the line with the ``compile`` pragma and run the following typical
+Unix commands::
+
+    $ gcc -c logic.c
+    $ ar rvs mylib.a logic.o
+    $ nimrod c --passL:mylib.a -r calculator.nim
+
+Just like in this example we pass the path to the ``mylib.a`` library (and we
+could as well pass ``logic.o``) we could be passing switches to link any other
+static C library.
+
+
+JavaScript invocation example
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Create a ``host.html`` file with the following content:
+
+.. code-block::
+
+  <html><body>
+  <script type="text/javascript">
+  function addTwoIntegers(a, b)
+  {
+    return a + b;
+  }
+  </script>
+  <script type="text/javascript" src="calculator.js"></script>
+  </body></html>
+
+Create a ``calculator.nim`` file with the following content (or reuse the one
+from the previous section):
+
+.. code-block:: nimrod
+
+  proc addTwoIntegers(a, b: int): int {.importc.}
+
+  when isMainModule:
+    echo addTwoIntegers(3, 7)
+
+Compile the Nimrod code to JavaScript with ``nimrod js -o:calculator.js
+calculator.nim`` and open ``host.html`` in a browser. If the browser supports
+javascript, you should see the value ``10``. In JavaScript the `echo proc
+<system.html#echo>`_ will modify the HTML DOM and append the string. Use the
+`dom module <dom.html>`_ for specific DOM querying and modification procs.
+
+
+Backend code calling Nimrod
+---------------------------
+
+Backend code can interface with Nimrod code exposed through the `exportc
+pragma <manual.html#exportc-pragma>`_. The ``exportc`` pragma is the *generic*
+way of making Nimrod symbols available to the backends. By default the Nimrod
+compiler will mangle all the Nimrod symbols to avoid any name collision, so
+the most significant thing the ``exportc`` pragma does is maintain the Nimrod
+symbol name, or if specified, use an alternative symbol for the backend in
+case the symbol rules don't match.
+
+The JavaScript target doesn't have any further interfacing considerations
+since it also has garbage collection, but the C targets require you to
+initialize Nimrod's internals, which is done calling a ``NimMain`` function.
+Also, C code requires you to specify a forward declaration for functions or
+the compiler will asume certain types for the return value and parameters
+which will likely make your program crash at runtime.
+
+The Nimrod compiler can generate a C interface header through the ``--header``
+command line switch. The generated header will contain all the exported
+symbols and the ``NimMain`` proc which you need to call before any other
+Nimrod code.
+
+
+Nimrod invocation example from C
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Create a ``fib.nim`` file with the following content:
+
+.. code-block:: nimrod
+
+  proc fib(a: cint): cint {.exportc.} =
+    if a <= 2:
+      result = 1
+    else:
+      result = fib(a - 1) + fib(a - 2)
+
+Create a ``maths.c`` file with the following content:
+
+.. code-block:: c
+
+  #include "fib.h"
+  #include <stdio.h>
+
+  int main(void)
+  {
+    NimMain();
+    for (int f = 0; f < 10; f++)
+      printf("Fib of %d is %d\n", f, fib(f));
+    return 0;
+  }
+
+Now you can run the following Unix like commands to first generate C sources
+form the Nimrod code, then link them into a static binary along your main C
+program::
+
+  $ nimrod c --noMain --noLinking --header:fib.h fib.nim
+  $ gcc -o m -Inimcache -Ipath/to/nimrod/lib nimcache/*.c maths.c
+
+The first command runs the Nimrod compiler with three special options to avoid
+generating a ``main()`` function in the generated files, avoid linking the
+object files into a final binary, and explicitly generate a header file for C
+integration. All the generated files are placed into the ``nimcache``
+directory. That's why the next command compiles the ``maths.c`` source plus
+all the ``.c`` files form ``nimcache``. In addition to this path, you also
+have to tell the C compiler where to find Nimrod's ``nimbase.h`` header file.
+
+Instead of depending on the generation of the individual ``.c`` files you can
+also ask the Nimrod compiler to generate a statically linked library::
+
+  $ nimrod c --app:staticLib --noMain --header fib.nim
+  $ gcc -o m -Inimcache -Ipath/to/nimrod/lib libfib.nim.a maths.c
+
+The Nimrod compiler will handle linking the source files generated in the
+``nimcache`` directory into the ``libfib.nim.a`` static library, which you can
+then link into your C program.  Note that these commands are generic and will
+vary for each system. For instance, on Linux systems you will likely need to
+use ``-ldl`` too to link in required dlopen functionality.
+
+
+Nimrod invocation example from JavaScript
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Create a ``mhost.html`` file with the following content:
+
+.. code-block::
+
+  <html><body>
+  <script type="text/javascript" src="fib.js"></script>
+  <script type="text/javascript">
+  alert("Fib for 9 is " + fib(9));
+  </script>
+  </body></html>
+
+Create a ``fib.nim`` file with the following content (or reuse the one
+from the previous section):
+
+.. code-block:: nimrod
+
+  proc fib(a: cint): cint {.exportc.} =
+    if a <= 2:
+      result = 1
+    else:
+      result = fib(a - 1) + fib(a - 2)
+
+Compile the Nimrod code to JavaScript with ``nimrod js -o:fib.js fib.nim`` and
+open ``mhost.html`` in a browser. If the browser supports javascript, you
+should see an alert box displaying the text ``Fib for 9 is 34``. As mentioned
+earlier, JavaScript doesn't require an initialisation call to ``NimMain`` or
+similar function and you can call the exported Nimrod proc directly.
+
+
+Memory management
+=================
+
+In the previous sections the ``NimMain()`` function reared its head. Since
+JavaScript already provides automatic memory management, you can freely pass
+objects between the two language without problems. In C and derivate languages
+you need to be careful about what you do and how you share memory. The
+previous examples only dealt with simple scalar values, but passing a Nimrod
+string to C, or reading back a C string in Nimrod already requires you to be
+aware of who controls what to avoid crashing.
+
+
+Strings and C strings
+---------------------
+
+The manual mentions that `Nimrod strings are implicitly convertible to
+cstrings <manual.html#cstring-type>`_ which makes interaction usually
+painless. Most C functions accepting a Nimrod string converted to a
+``cstring`` will likely not need to keep this string around and by the time
+they return the string won't be needed any more. However, for the rare cases
+where a Nimrod string has to be preserved and made available to the C backend
+as a ``cstring``, you will need to manually prevent the string data from being
+freed with `GC_ref <system.html#GC_ref>`_ and `GC_unref
+<system.html#GC_unref>`_.
+
+A similar thing happens with C code invoking Nimrod code which returns a
+``cstring``. Consider the following proc:
+
+.. code-block:: nimrod
+
+  proc gimme(): cstring {.exportc.} =
+    result = "Hey there C code! " & $random(100)
+
+Since Nimrod's garbage collector is not aware of the C code, once the
+``gimme`` proc has finished it can reclaim the memory of the ``cstring``.
+However, from a practical standpoint, the C code invoking the ``gimme``
+function directly will be able to use it since Nimrod's garbage collector has
+not had a chance to run *yet*. This gives you enough time to make a copy for
+the C side of the program, as calling any further Nimrod procs *might* trigger
+garbage collection making the previously returned string garbage. Or maybe you
+are `triggering yourself the collection <gc.html>`_.
+
+
+Custom data types
+-----------------
+
+Just like strings, custom data types that are to be shared between Nimrod and
+the backend will need careful consideration of who controlls who. If you want
+to hand a Nimrod reference to C code, you will need to use `GC_ref
+<system.html#GC_ref>`_ to mark the reference as used, so it does not get
+freed. And for the C backend you will need to expose the `GC_unref
+<system.html#GC_unref>`_ proc to clean up this memory when it is not required
+any more.
+
+Again, if you are wrapping a library which *mallocs* and *frees* data
+structures, you need to expose the appropriate *free* function to Nimrod so
+you can clean it up. And of course, once cleaned you should avoid accessing it
+from Nimrod (or C for that matter). Typically C data structures have their own
+``malloc_structure`` and ``free_structure`` specific functions, so wrapping
+these for the Nimrod side should be enough.
+
+
+Thread coordination
+-------------------
+
+When the ``NimMain()`` function is called Nimrod initializes the garbage
+collector to the current thread, which is usually the main thread of your
+application. If your C code later spawns a different thread and calls Nimrod
+code, the garbage collector will fail to work properly and you will crash.
+
+As long as you don't use the threadvar emulation Nimrod uses native thread
+variables, of which you get a fresh version whenever you create a thread. You
+can then attach a GC to this thread via
+
+.. code-block:: nimrod
+
+  setStackBottom(addr(someLocal))
+  initGC()
+
+At the moment this support is still experimental so you need to expose these
+functions yourself or submit patches to request a public API. 
+
+It is **not** safe to disable the garbage collector and enable it after the
+call from your background thread even if the code you are calling is short
+lived.
diff --git a/doc/grammar.txt b/doc/grammar.txt
index 47ae095f6..a54428678 100644
--- a/doc/grammar.txt
+++ b/doc/grammar.txt
@@ -86,7 +86,7 @@ distinct = 'distinct' optInd typeDesc
 expr = (ifExpr
       | whenExpr
       | caseExpr
-      | tryStmt)
+      | tryExpr)
       / simpleExpr
 typeKeyw = 'var' | 'ref' | 'ptr' | 'shared' | 'type' | 'tuple'
          | 'proc' | 'iterator' | 'distinct' | 'object' | 'enum'
@@ -135,6 +135,9 @@ caseStmt = 'case' expr ':'? COMMENT?
 tryStmt = 'try' colcom stmt &(IND{=}? 'except'|'finally')
            (IND{=}? 'except' exprList colcom stmt)*
            (IND{=}? 'finally' colcom stmt)?
+tryExpr = 'try' colcom stmt &(optInd 'except'|'finally')
+           (optInd 'except' exprList colcom stmt)*
+           (optInd 'finally' colcom stmt)?
 exceptBlock = 'except' colcom stmt
 forStmt = 'for' (identWithPragma ^+ comma) 'in' expr colcom stmt
 blockStmt = 'block' symbol? colcom stmt
diff --git a/doc/manual.txt b/doc/manual.txt
index e96e50999..32b0541e9 100644
--- a/doc/manual.txt
+++ b/doc/manual.txt
@@ -263,15 +263,16 @@ String literals can also be delimited by three double quotes
 ``"""`` ... ``"""``.
 Literals in this form may run for several lines, may contain ``"`` and do not
 interpret any escape sequences.
-For convenience, when the opening ``"""`` is immediately followed by a newline,
-the newline is not included in the string. The ending of the string literal is
-defined by the pattern ``"""[^"]``, so this:
-  
+For convenience, when the opening ``"""`` is followed by a newline (there may
+be whitespace between the opening ``"""`` and the newline),
+the newline (and the preceding whitespace) is not included in the string. The
+ending of the string literal is defined by the pattern ``"""[^"]``, so this:
+
 .. code-block:: nimrod 
   """"long string within quotes""""
-  
+
 Produces::
-  
+
   "long string within quotes"
 
 
@@ -1089,7 +1090,8 @@ types with no overhead and few abstraction possibilities. The constructor ``()``
 can be used to construct tuples. The order of the fields in the constructor
 must match the order of the tuple's definition. Different tuple-types are
 *equivalent* if they specify the same fields of the same type in the same
-order.
+order. The *names* of the fields also have to be identical but this might
+change in a future version of the language.
 
 The assignment operator for tuples copies each component.
 The default assignment operator for objects copies each component. Overloading
@@ -2226,12 +2228,12 @@ type.
 If the expression is not of an ordinal type, and no ``else`` part is
 given, control passes after the ``case`` statement.
 
-To suppress the static error in the ordinal case an ``else`` part with a ``nil``
-statement can be used.
+To suppress the static error in the ordinal case an ``else`` part with an
+empty ``discard`` statement can be used.
 
 As a special semantic extension, an expression in an ``of`` branch of a case
-statement may evaluate to a set constructor; the set is then expanded into 
-a list of its elements:
+statement may evaluate to a set or array constructor; the set or array is then
+expanded into a list of its elements:
 
 .. code-block:: nimrod
   const
@@ -5464,7 +5466,7 @@ and warning message contains a symbol in brackets. This is the message's
 identifier that can be used to enable or disable it:
 
 .. code-block:: Nimrod
-  {.warning[LineTooLong]: off.} # turn off warning about too long lines
+  {.hint[LineTooLong]: off.} # turn off the hint about too long lines
 
 This is often better than disabling all warnings at once.
 
@@ -5488,7 +5490,10 @@ spelled*:
   proc printf(formatstr: cstring) {.header: "<stdio.h>", importc: "printf", varargs.}
 
 Note that this pragma is somewhat of a misnomer: Other backends will provide
-the same feature under the same name.
+the same feature under the same name. Also, if you are interfacing with C++
+you can use the `ImportCpp pragma <nimrodc.html#importcpp-pragma>`_ and
+interfacing with Objective-C the `ImportObjC pragma
+<nimrodc.html#importobjc-pragma>`_.
 
 
 Exportc pragma
diff --git a/doc/nimrodc.txt b/doc/nimrodc.txt
index fea1037da..428c42f39 100644
--- a/doc/nimrodc.txt
+++ b/doc/nimrodc.txt
@@ -384,10 +384,11 @@ Example:
 

 ImportCpp pragma

 ----------------

-The ``importcpp`` pragma can be used to import `C++`:idx: methods. The

-generated code then uses the C++ method calling syntax: ``obj->method(arg)``.

-In addition with the ``header`` and ``emit`` pragmas this allows *sloppy*

-interfacing with libraries written in C++:

+Similar to the `importc pragma for C <manual.html#importc-pragma>`_, the
+``importcpp`` pragma can be used to import `C++`:idx: methods. The generated
+code then uses the C++ method calling syntax: ``obj->method(arg)``.  In
+addition with the ``header`` and ``emit`` pragmas this allows *sloppy*
+interfacing with libraries written in C++:
 

 .. code-block:: Nimrod

   # Horrible example of how to interface with a C++ engine ... ;-)

@@ -422,11 +423,11 @@ emits C++ code.
 

 ImportObjC pragma

 -----------------

-The ``importobjc`` pragma can be used to import `Objective C`:idx: methods. 

-The generated code then uses the Objective C method calling 

-syntax: ``[obj method param1: arg]``.

-In addition with the ``header`` and ``emit`` pragmas this allows *sloppy*

-interfacing with libraries written in Objective C:

+Similar to the `importc pragma for C <manual.html#importc-pragma>`_, the
+``importobjc`` pragma can be used to import `Objective C`:idx: methods.  The
+generated code then uses the Objective C method calling syntax: ``[obj method
+param1: arg]``.  In addition with the ``header`` and ``emit`` pragmas this
+allows *sloppy* interfacing with libraries written in Objective C:
 

 .. code-block:: Nimrod

   # horrible example of how to interface with GNUStep ...

@@ -550,8 +551,18 @@ against. For instance, to link statically against Lua this command might work
 on Linux::
 
   nimrod c --dynlibOverride:lua --passL:liblua.lib program.nim
-

-

+
+
+Backend language options
+========================
+
+The typical compiler usage involves using the ``compile`` or ``c`` command to
+transform a ``.nim`` file into one or more ``.c`` files which are then
+compiled with the platform's C compiler into a static binary. However there
+are other commands to compile to C++, Objective-C or Javascript. More details
+can be read in the `Nimrod Backend Integration document <backends.html>`_.
+
+
 Nimrod documentation tools
 ==========================
 
@@ -695,35 +706,3 @@ efficient:
     else: quit(errorStr(p, "expected: console or gui"))

   of "license": c.license = UnixToNativePath(k.value)

   else: quit(errorStr(p, "unknown variable: " & k.key))

-
-
-The JavaScript target
-=====================
-
-Nimrod can also generate `JavaScript`:idx: code. However, the
-JavaScript code generator is experimental!
-
-Nimrod targets JavaScript 1.5 which is supported by any widely used browser.
-Since JavaScript does not have a portable means to include another module,
-Nimrod just generates a long ``.js`` file.
-
-Features or modules that the JavaScript platform does not support are not
-available. This includes:
-
-* manual memory management (``alloc``, etc.)
-* casting and other unsafe operations (``cast`` operator, ``zeroMem``, etc.)
-* file management
-* most modules of the Standard library
-* proper 64 bit integer arithmetic
-* unsigned integer arithmetic
-
-However, the modules `strutils`:idx:, `math`:idx:, and `times`:idx: are
-available! To access the DOM, use the `dom`:idx: module that is only
-available for the JavaScript platform.
-
-To compile a Nimrod module into a ``.js`` file use the ``js`` command; the
-default is a  ``.js`` file that is supposed to be referenced in an ``.html``
-file. However, you can also run the code with `nodejs`:idx:\:  
-
-  nimrod js -d:nodejs -r examples/hallo.nim
-
diff --git a/doc/trmacros.txt b/doc/trmacros.txt
deleted file mode 100644
index d5ad74e6e..000000000
--- a/doc/trmacros.txt
+++ /dev/null
@@ -1,275 +0,0 @@
-=========================================================
-   Term rewriting macros for Nimrod
-=========================================================
-
-:Author: Andreas Rumpf
-
-Term rewriting macros are macros or templates that have not only a *name* but
-also a *pattern* that is searched for after the semantic checking phase of
-the compiler: This means they provide an easy way to enhance the compilation
-pipeline with user defined optimizations:
-
-.. code-block:: nimrod
-  template optMul{`*`(a, 2)}(a: int): int = a+a
-  
-  let x = 3
-  echo x * 2
-
-The compiler now rewrites ``x * 2`` as ``x + x``. The code inside the
-curlies is the pattern to match against. The operators ``*``,  ``**``,
-``|``, ``~`` have a special meaning in patterns if they are written in infix 
-notation, so to match verbatim against ``*`` the ordinary function call syntax
-needs to be used.
-
-
-Unfortunately optimizations are hard to get right and even the tiny example
-is **wrong**: 
-
-.. code-block:: nimrod
-  template optMul{`*`(a, 2)}(a: int): int = a+a
-  
-  proc f(): int =
-    echo "side effect!"
-    result = 55
-  
-  echo f() * 2
-
-We cannot duplicate 'a' if it denotes an expression that has a side effect!
-Fortunately Nimrod supports side effect analysis:
-
-.. code-block:: nimrod
-  template optMul{`*`(a, 2)}(a: int{noSideEffect}): int = a+a
-  
-  proc f(): int =
-    echo "side effect!"
-    result = 55
-  
-  echo f() * 2 # not optimized ;-)
-
-So what about ``2 * a``? We should tell the compiler ``*`` is commutative. We
-cannot really do that however as the following code only swaps arguments
-blindly:
-
-.. code-block:: nimrod
-  template mulIsCommutative{`*`(a, b)}(a, b: int): int = b*a
-  
-What optimizers really need to do is a *canonicalization*:
-
-.. code-block:: nimrod
-  template canonMul{`*`(a, b)}(a: int{lit}, b: int): int = b*a
-
-The ``int{lit}`` parameter pattern matches against an expression of 
-type ``int``, but only if it's a literal.
-
-
-
-Parameter constraints
-=====================
-
-The parameter constraint expression can use the operators ``|`` (or), 
-``&`` (and) and ``~`` (not) and the following predicates:
-
-===================      =====================================================
-Predicate                Meaning
-===================      =====================================================
-``atom``                 The matching node has no children.
-``lit``                  The matching node is a literal like "abc", 12.
-``sym``                  The matching node must be a symbol (a bound 
-                         identifier).
-``ident``                The matching node must be an identifier (an unbound
-                         identifier).
-``call``                 The matching AST must be a call/apply expression.
-``lvalue``               The matching AST must be an lvalue.
-``sideeffect``           The matching AST must have a side effect.
-``nosideeffect``         The matching AST must have no side effect.
-``param``                A symbol which is a parameter.
-``genericparam``         A symbol which is a generic parameter.
-``module``               A symbol which is a module.
-``type``                 A symbol which is a type.
-``var``                  A symbol which is a variable.
-``let``                  A symbol which is a ``let`` variable.
-``const``                A symbol which is a constant.
-``result``               The special ``result`` variable.
-``proc``                 A symbol which is a proc.
-``method``               A symbol which is a method.
-``iterator``             A symbol which is an iterator.
-``converter``            A symbol which is a converter.
-``macro``                A symbol which is a macro.
-``template``             A symbol which is a template.
-``field``                A symbol which is a field in a tuple or an object.
-``enumfield``            A symbol which is a field in an enumeration.
-``forvar``               A for loop variable.
-``label``                A label (used in ``block`` statements).
-``nk*``                  The matching AST must have the specified kind. 
-                         (Example: ``nkIfStmt`` denotes an ``if`` statement.)
-``alias``                States that the marked parameter needs to alias 
-                         with *some* other parameter.
-``noalias``              States that *every* other parameter must not alias
-                         with the marked parameter.
-===================      =====================================================
-
-The ``alias`` and ``noalias`` predicates refer not only to the matching AST,
-but also to every other bound parameter; syntactially they need to occur after
-the ordinary AST predicates:
-
-.. code-block:: nimrod
-  template ex{a = b + c}(a: int{noalias}, b, c: int) =
-    # this transformation is only valid if 'b' and 'c' do not alias 'a':
-    a = b
-    inc a, b
-
-
-Pattern operators
-=================
-
-The operators ``*``,  ``**``, ``|``, ``~`` have a special meaning in patterns
-if they are written in infix notation.
-
-
-The ``|`` operator
-------------------
-
-The ``|`` operator if used as infix operator creates an ordered choice:
-
-.. code-block:: nimrod
-  template t{0|1}(): expr = 3
-  let a = 1
-  # outputs 3:
-  echo a
-
-The matching is performed after the compiler performed some optimizations like
-constant folding, so the following does not work:
-
-.. code-block:: nimrod
-  template t{0|1}(): expr = 3
-  # outputs 1:
-  echo 1
-
-The reason is that the compiler already transformed the 1 into "1" for
-the ``echo`` statement. However, a term rewriting macro should not change the
-semantics anyway. In fact they can be deactived with the ``--patterns:off``
-command line option or temporarily with the ``patterns`` pragma. 
-
-
-The ``{}`` operator
--------------------
-
-A pattern expression can be bound to a pattern parameter via the ``expr{param}``
-notation: 
-
-.. code-block:: nimrod
-  template t{(0|1|2){x}}(x: expr): expr = x+1
-  let a = 1
-  # outputs 2:
-  echo a
-
-
-The ``~`` operator
-------------------
-
-The ``~`` operator is the **not** operator in patterns:
-
-.. code-block:: nimrod
-  template t{x = (~x){y} and (~x){z}}(x, y, z: bool): stmt =
-    x = y
-    if x: x = z
-  
-  var
-    a = false
-    b = true
-    c = false
-  a = b and c
-  echo a
-
-
-The ``*`` operator
-------------------
-
-The ``*`` operator can *flatten* a nested binary expression like ``a & b & c``
-to ``&(a, b, c)``: 
-
-.. code-block:: nimrod
-  var
-    calls = 0
-    
-  proc `&&`(s: varargs[string]): string =
-    result = s[0]
-    for i in 1..len(s)-1: result.add s[i]
-    inc calls
-
-  template optConc{ `&&` * a }(a: string): expr = &&a
-
-  let space = " "
-  echo "my" && (space & "awe" && "some " ) && "concat"
-
-  # check that it's been optimized properly:
-  doAssert calls == 1
-
-
-The second operator of `*` must be a parameter; it is used to gather all the
-arguments. The expression ``"my" && (space & "awe" && "some " ) && "concat"``
-is passed to ``optConc`` in ``a`` as a special list (of kind ``nkArgList``) 
-which is flattened into a call expression; thus the invocation of ``optConc`` 
-produces:
-
-.. code-block:: nimrod
-   `&&`("my", space & "awe", "some ", "concat")
-
-
-The ``**`` operator
--------------------
-
-The ``**`` is much like the ``*`` operator, except that it gathers not only
-all the arguments, but also the matched operators in reverse polish notation:
-
-.. code-block:: nimrod
-  import macros
-
-  type
-    TMatrix = object
-      dummy: int
-
-  proc `*`(a, b: TMatrix): TMatrix = nil
-  proc `+`(a, b: TMatrix): TMatrix = nil
-  proc `-`(a, b: TMatrix): TMatrix = nil
-  proc `$`(a: TMatrix): string = result = $a.dummy
-  proc mat21(): TMatrix =
-    result.dummy = 21
-
-  macro optM{ (`+`|`-`|`*`) ** a }(a: TMatrix): expr =
-    echo treeRepr(a)
-    result = newCall(bindSym"mat21")
-
-  var x, y, z: TMatrix
-
-  echo x + y * z - x 
-
-This passes the expression ``x + y * z - x`` to the ``optM`` macro as
-an ``nnkArgList`` node containing::
-
-  Arglist
-    Sym "x"
-    Sym "y"
-    Sym "z"
-    Sym "*"
-    Sym "+"
-    Sym "x"
-    Sym "-"
-
-(Which is the reverse polish notation of ``x + y * z - x``.)
-
-
-Parameters
-==========
-
-Parameters in a pattern are type checked in the matching process. If a 
-parameter is of the type ``varargs`` it is treated specially and it can match
-0 or more arguments in the AST to be matched against:
-
-.. code-block:: nimrod
-  template optWrite{
-    write(f, x)
-    ((write|writeln){w})(f, y)
-  }(x, y: varargs[expr], f: TFile, w: expr) =
-    w(f, x, y)
-  
diff --git a/doc/tut1.txt b/doc/tut1.txt
index 9874f267b..a2aa835ee 100644
--- a/doc/tut1.txt
+++ b/doc/tut1.txt
@@ -1,4 +1,4 @@
-========================
+========================
 Nimrod Tutorial (Part I)
 ========================
 
@@ -1521,17 +1521,13 @@ techniques.
 Example:
 
 .. code-block:: nimrod
+  proc echoItem(x: int) = echo(x)
 
-  type
-    TCallback = proc (x: int)
-
-  proc echoItem(x: Int) = echo(x)
-
-  proc forEach(callback: TCallback) =
+  proc forEach(action: proc (x: int)) =
     const
       data = [2, 3, 5, 7, 11]
     for d in items(data):
-      callback(d)
+      action(d)
 
   forEach(echoItem)
 
diff --git a/lib/impure/db_mysql.nim b/lib/impure/db_mysql.nim
index 32cda3e4d..eec4daf00 100644
--- a/lib/impure/db_mysql.nim
+++ b/lib/impure/db_mysql.nim
@@ -24,6 +24,15 @@ type
   FReadDb* = object of FDb   ## effect that denotes a read operation
   FWriteDb* = object of FDb  ## effect that denotes a write operation
 
+proc sql*(query: string): TSqlQuery {.noSideEffect, inline.} =
+  ## constructs a TSqlQuery from the string `query`. This is supposed to be 
+  ## used as a raw-string-literal modifier:
+  ## ``sql"update user set counter = counter + 1"``
+  ##
+  ## If assertions are turned off, it does nothing. If assertions are turned 
+  ## on, later versions will check the string for valid syntax.
+  result = TSqlQuery(query)
+
 proc dbError(db: TDbConn) {.noreturn.} = 
   ## raises an EDb exception.
   var e: ref EDb
diff --git a/lib/js/dom.nim b/lib/js/dom.nim
index d90067176..951d8e835 100644
--- a/lib/js/dom.nim
+++ b/lib/js/dom.nim
@@ -7,7 +7,8 @@
 #    distribution, for details about the copyright.
 #
 
-## Declaration of the Document Object Model for the JavaScript backend.
+## Declaration of the Document Object Model for the `JavaScript backend
+## <backends.html#the-javascript-target>`_.
 
 when not defined(js) and not defined(Nimdoc):
   {.error: "This module only works on the JavaScript platform".}
diff --git a/lib/posix/posix.nim b/lib/posix/posix.nim
index cdca826ca..8e66336c2 100644
--- a/lib/posix/posix.nim
+++ b/lib/posix/posix.nim
@@ -1578,8 +1578,17 @@ var
     ## Terminates a record (if supported by the protocol).
   MSG_OOB* {.importc, header: "<sys/socket.h>".}: cint
     ## Out-of-band data.
-  MSG_NOSIGNAL* {.importc, header: "<sys/socket.h>".}: cint
-    ## No SIGPIPE generated when an attempt to send is made on a stream-oriented socket that is no longer connected.
+
+when defined(macosx):
+  var
+    MSG_HAVEMORE* {.importc, header: "<sys/socket.h>".}: cint
+    MSG_NOSIGNAL* = MSG_HAVEMORE
+else:
+  var
+    MSG_NOSIGNAL* {.importc, header: "<sys/socket.h>".}: cint
+      ## No SIGPIPE generated when an attempt to send is made on a stream-oriented socket that is no longer connected.
+
+var
   MSG_PEEK* {.importc, header: "<sys/socket.h>".}: cint
     ## Leave received data in queue.
   MSG_TRUNC* {.importc, header: "<sys/socket.h>".}: cint
diff --git a/lib/pure/asyncdispatch.nim b/lib/pure/asyncdispatch.nim
index 6292bfc12..d410f8ce1 100644
--- a/lib/pure/asyncdispatch.nim
+++ b/lib/pure/asyncdispatch.nim
@@ -11,8 +11,9 @@ include "system/inclrtl"
 
 import os, oids, tables, strutils, macros
 
-import rawsockets
-export TPort
+import rawsockets, net
+
+export TPort, TSocketFlags
 
 #{.injectStmt: newGcInvariant().}
 
@@ -40,6 +41,7 @@ type
     cb: proc () {.closure,gcsafe.}
     finished: bool
     error*: ref EBase
+    stackTrace: string ## For debugging purposes only.
 
   PFuture*[T] = ref object of PFutureBase
     value: T
@@ -48,10 +50,23 @@ proc newFuture*[T](): PFuture[T] =
   ## Creates a new future.
   new(result)
   result.finished = false
+  result.stackTrace = getStackTrace()
+
+proc checkFinished[T](future: PFuture[T]) =
+  if future.finished:
+    echo("<----->")
+    echo(future.stackTrace)
+    echo("-----")
+    when T is string:
+      echo("Contents: ", future.value.repr)
+    echo("<----->")
+    echo("Future already finished, cannot finish twice.")
+    assert false
 
 proc complete*[T](future: PFuture[T], val: T) =
   ## Completes ``future`` with value ``val``.
-  assert(not future.finished, "Future already finished, cannot finish twice.")
+  #assert(not future.finished, "Future already finished, cannot finish twice.")
+  checkFinished(future)
   assert(future.error == nil)
   future.value = val
   future.finished = true
@@ -60,7 +75,8 @@ proc complete*[T](future: PFuture[T], val: T) =
 
 proc complete*(future: PFuture[void]) =
   ## Completes a void ``future``.
-  assert(not future.finished, "Future already finished, cannot finish twice.")
+  #assert(not future.finished, "Future already finished, cannot finish twice.")
+  checkFinished(future)
   assert(future.error == nil)
   future.finished = true
   if future.cb != nil:
@@ -68,7 +84,8 @@ proc complete*(future: PFuture[void]) =
 
 proc fail*[T](future: PFuture[T], error: ref EBase) =
   ## Completes ``future`` with ``error``.
-  assert(not future.finished, "Future already finished, cannot finish twice.")
+  #assert(not future.finished, "Future already finished, cannot finish twice.")
+  checkFinished(future)
   future.finished = true
   future.error = error
   if future.cb != nil:
@@ -126,6 +143,15 @@ proc failed*(future: PFutureBase): bool =
   ## Determines whether ``future`` completed with an error.
   future.error != nil
 
+proc asyncCheck*[T](future: PFuture[T]) =
+  ## Sets a callback on ``future`` which raises an exception if the future
+  ## finished with an error.
+  ##
+  ## This should be used instead of ``discard`` to discard void futures.
+  future.callback =
+    proc () =
+      if future.failed: raise future.error
+
 when defined(windows) or defined(nimdoc):
   import winlean, sets, hashes
   type
@@ -344,7 +370,7 @@ when defined(windows) or defined(nimdoc):
     return retFuture
 
   proc recv*(socket: TAsyncFD, size: int,
-             flags: int = 0): PFuture[string] =
+             flags = {TSocketFlags.SafeDisconn}): PFuture[string] =
     ## Reads **up to** ``size`` bytes from ``socket``. Returned future will
     ## complete once all the data requested is read, a part of the data has been
     ## read, or the socket has disconnected in which case the future will
@@ -364,7 +390,7 @@ when defined(windows) or defined(nimdoc):
     dataBuf.len = size
     
     var bytesReceived: DWord
-    var flagsio = flags.DWord
+    var flagsio = flags.toOSFlags().DWord
     var ol = PCustomOverlapped()
     GC_ref(ol)
     ol.data = TCompletionData(sock: socket, cb:
@@ -394,7 +420,10 @@ when defined(windows) or defined(nimdoc):
           dealloc dataBuf.buf
           dataBuf.buf = nil
         GC_unref(ol)
-        retFuture.fail(newException(EOS, osErrorMsg(err)))
+        if flags.isDisconnectionError(err):
+          retFuture.complete("")
+        else:
+          retFuture.fail(newException(EOS, osErrorMsg(err)))
     elif ret == 0 and bytesReceived == 0 and dataBuf.buf[0] == '\0':
       # We have to ensure that the buffer is empty because WSARecv will tell
       # us immediatelly when it was disconnected, even when there is still
@@ -425,7 +454,8 @@ when defined(windows) or defined(nimdoc):
       # free ``ol``.
     return retFuture
 
-  proc send*(socket: TAsyncFD, data: string): PFuture[void] =
+  proc send*(socket: TAsyncFD, data: string,
+             flags = {TSocketFlags.SafeDisconn}): PFuture[void] =
     ## Sends ``data`` to ``socket``. The returned future will complete once all
     ## data has been sent.
     verifyPresence(socket)
@@ -435,7 +465,7 @@ when defined(windows) or defined(nimdoc):
     dataBuf.buf = data # since this is not used in a callback, this is fine
     dataBuf.len = data.len
 
-    var bytesReceived, flags: DWord
+    var bytesReceived, lowFlags: DWord
     var ol = PCustomOverlapped()
     GC_ref(ol)
     ol.data = TCompletionData(sock: socket, cb:
@@ -448,12 +478,15 @@ when defined(windows) or defined(nimdoc):
     )
 
     let ret = WSASend(socket.TSocketHandle, addr dataBuf, 1, addr bytesReceived,
-                      flags, cast[POverlapped](ol), nil)
+                      lowFlags, cast[POverlapped](ol), nil)
     if ret == -1:
       let err = osLastError()
       if err.int32 != ERROR_IO_PENDING:
-        retFuture.fail(newException(EOS, osErrorMsg(err)))
         GC_unref(ol)
+        if flags.isDisconnectionError(err):
+          retFuture.complete()
+        else:
+          retFuture.fail(newException(EOS, osErrorMsg(err)))
     else:
       retFuture.complete()
       # We don't deallocate ``ol`` here because even though this completed
@@ -552,7 +585,18 @@ when defined(windows) or defined(nimdoc):
   initAll()
 else:
   import selectors
-  from posix import EINTR, EAGAIN, EINPROGRESS, EWOULDBLOCK, MSG_PEEK
+  when defined(windows):
+    import winlean
+    const
+      EINTR = WSAEINPROGRESS
+      EINPROGRESS = WSAEINPROGRESS
+      EWOULDBLOCK = WSAEWOULDBLOCK
+      EAGAIN = EINPROGRESS
+      MSG_NOSIGNAL = 0
+  else:
+    from posix import EINTR, EAGAIN, EINPROGRESS, EWOULDBLOCK, MSG_PEEK,
+                      MSG_NOSIGNAL
+  
   type
     TAsyncFD* = distinct cint
     TCallback = proc (sock: TAsyncFD): bool {.closure,gcsafe.}
@@ -686,20 +730,23 @@ else:
     return retFuture
 
   proc recv*(socket: TAsyncFD, size: int,
-             flags: int = 0): PFuture[string] =
+             flags = {TSocketFlags.SafeDisconn}): PFuture[string] =
     var retFuture = newFuture[string]()
     
     var readBuffer = newString(size)
 
     proc cb(sock: TAsyncFD): bool =
       result = true
-      let res = recv(sock.TSocketHandle, addr readBuffer[0], size,
-                     flags.cint)
+      let res = recv(sock.TSocketHandle, addr readBuffer[0], size.cint,
+                     flags.toOSFlags())
       #echo("recv cb res: ", res)
       if res < 0:
         let lastError = osLastError()
-        if lastError.int32 notin {EINTR, EWOULDBLOCK, EAGAIN}: 
-          retFuture.fail(newException(EOS, osErrorMsg(lastError)))
+        if lastError.int32 notin {EINTR, EWOULDBLOCK, EAGAIN}:
+          if flags.isDisconnectionError(lastError):
+            retFuture.complete("")
+          else:
+            retFuture.fail(newException(EOS, osErrorMsg(lastError)))
         else:
           result = false # We still want this callback to be called.
       elif res == 0:
@@ -708,11 +755,13 @@ else:
       else:
         readBuffer.setLen(res)
         retFuture.complete(readBuffer)
-  
+    # TODO: The following causes a massive slowdown.
+    #if not cb(socket):
     addRead(socket, cb)
     return retFuture
 
-  proc send*(socket: TAsyncFD, data: string): PFuture[void] =
+  proc send*(socket: TAsyncFD, data: string,
+             flags = {TSocketFlags.SafeDisconn}): PFuture[void] =
     var retFuture = newFuture[void]()
     
     var written = 0
@@ -721,11 +770,15 @@ else:
       result = true
       let netSize = data.len-written
       var d = data.cstring
-      let res = send(sock.TSocketHandle, addr d[written], netSize, 0.cint)
+      let res = send(sock.TSocketHandle, addr d[written], netSize.cint,
+                     MSG_NOSIGNAL)
       if res < 0:
         let lastError = osLastError()
         if lastError.int32 notin {EINTR, EWOULDBLOCK, EAGAIN}:
-          retFuture.fail(newException(EOS, osErrorMsg(lastError)))
+          if flags.isDisconnectionError(lastError):
+            retFuture.complete()
+          else:
+            retFuture.fail(newException(EOS, osErrorMsg(lastError)))
         else:
           result = false # We still want this callback to be called.
       else:
@@ -734,6 +787,8 @@ else:
           result = false # We still have data to send.
         else:
           retFuture.complete()
+    # TODO: The following causes crashes.
+    #if not cb(socket):
     addWrite(socket, cb)
     return retFuture
 
@@ -779,6 +834,7 @@ proc accept*(socket: TAsyncFD): PFuture[TAsyncFD] =
 template createCb*(retFutureSym, iteratorNameSym,
                    name: expr): stmt {.immediate.} =
   var nameIterVar = iteratorNameSym
+  #{.push stackTrace: off.}
   proc cb {.closure,gcsafe.} =
     try:
       if not nameIterVar.finished:
@@ -791,7 +847,7 @@ template createCb*(retFutureSym, iteratorNameSym,
     except:
       retFutureSym.fail(getCurrentException())
   cb()
-
+  #{.pop.}
 proc generateExceptionCheck(futSym,
     exceptBranch, rootReceiver: PNimrodNode): PNimrodNode {.compileTime.} =
   if exceptBranch == nil:
@@ -1005,8 +1061,6 @@ macro async*(prc: stmt): stmt {.immediate.} =
       result[4].del(i)
   if subtypeIsVoid:
     # Add discardable pragma.
-    if prc.kind == nnkProcDef: # TODO: This is a workaround for #1287
-      result[4].add(newIdentNode("discardable"))
     if returnType.kind == nnkEmpty:
       # Add PFuture[void]
       result[3][0] = parseExpr("PFuture[void]")
@@ -1042,7 +1096,7 @@ proc recvLine*(socket: TAsyncFD): PFuture[string] {.async.} =
     if c.len == 0:
       return ""
     if c == "\r":
-      c = await recv(socket, 1, MSG_PEEK)
+      c = await recv(socket, 1, {TSocketFlags.SafeDisconn, TSocketFlags.Peek})
       if c.len > 0 and c == "\L":
         discard await recv(socket, 1)
       addNLIfEmpty()
diff --git a/lib/pure/asynchttpserver.nim b/lib/pure/asynchttpserver.nim
index 005c56ebc..ee6658fd1 100644
--- a/lib/pure/asynchttpserver.nim
+++ b/lib/pure/asynchttpserver.nim
@@ -20,7 +20,7 @@ type
     protocol*: tuple[orig: string, major, minor: int]
     url*: TURL
     hostname*: string ## The hostname of the client that made the request.
-    body*: string # TODO
+    body*: string
 
   PAsyncHttpServer* = ref object
     socket: PAsyncSocket
@@ -51,10 +51,15 @@ proc `==`*(protocol: tuple[orig: string, major, minor: int],
 proc newAsyncHttpServer*(): PAsyncHttpServer =
   new result
 
-proc sendHeaders*(req: TRequest, headers: PStringTable) {.async.} =
-  ## Sends the specified headers to the requesting client.
+proc addHeaders(msg: var string, headers: PStringTable) =
   for k, v in headers:
-    await req.client.send(k & ": " & v & "\c\L")
+    msg.add(k & ": " & v & "\c\L")
+
+proc sendHeaders*(req: TRequest, headers: PStringTable): PFuture[void] =
+  ## Sends the specified headers to the requesting client.
+  var msg = ""
+  addHeaders(msg, headers)
+  return req.client.send(msg)
 
 proc respond*(req: TRequest, code: THttpCode,
         content: string, headers: PStringTable = newStringTable()) {.async.} =
@@ -64,9 +69,9 @@ proc respond*(req: TRequest, code: THttpCode,
   ## This procedure will **not** close the client socket.
   var customHeaders = headers
   customHeaders["Content-Length"] = $content.len
-  await req.client.send("HTTP/1.1 " & $code & "\c\L")
-  await sendHeaders(req, headers)
-  await req.client.send("\c\L" & content)
+  var msg = "HTTP/1.1 " & $code & "\c\L"
+  msg.addHeaders(customHeaders)
+  await req.client.send(msg & "\c\L" & content)
 
 proc newRequest(): TRequest =
   result.headers = newStringTable(modeCaseInsensitive)
@@ -78,7 +83,7 @@ proc parseHeader(line: string): tuple[key, value: string] =
   i += line.skipWhiteSpace(i)
   i += line.parseUntil(result.value, {'\c', '\L'}, i)
 
-proc parseProtocol(protocol: string):  tuple[orig: string, major, minor: int] =
+proc parseProtocol(protocol: string): tuple[orig: string, major, minor: int] =
   var i = protocol.skipIgnoreCase("HTTP/")
   if i != 5:
     raise newException(EInvalidValue, "Invalid request protocol. Got: " &
@@ -88,70 +93,95 @@ proc parseProtocol(protocol: string):  tuple[orig: string, major, minor: int] =
   i.inc # Skip .
   i.inc protocol.parseInt(result.minor, i)
 
+proc sendStatus(client: PAsyncSocket, status: string): PFuture[void] =
+  client.send("HTTP/1.1 " & status & "\c\L")
+
 proc processClient(client: PAsyncSocket, address: string,
                  callback: proc (request: TRequest): PFuture[void]) {.async.} =
-  # GET /path HTTP/1.1
-  # Header: val
-  # \n
-  var request = newRequest()
-  request.hostname = address
-  assert client != nil
-  request.client = client
-
-  # First line - GET /path HTTP/1.1
-  let line = await client.recvLine() # TODO: Timeouts.
-  if line == "":
-    client.close()
-    return
-  let lineParts = line.split(' ')
-  if lineParts.len != 3:
-    request.respond(Http400, "Invalid request. Got: " & line)
-    client.close()
-    return
-
-  let reqMethod = lineParts[0]
-  let path = lineParts[1]
-  let protocol = lineParts[2]
-
-  # Headers
-  var i = 0
   while true:
-    i = 0
-    let headerLine = await client.recvLine()
-    if headerLine == "":
-      client.close(); return
-    if headerLine == "\c\L": break
-    # TODO: Compiler crash
-    #let (key, value) = parseHeader(headerLine)
-    let kv = parseHeader(headerLine)
-    request.headers[kv.key] = kv.value
-
-  request.reqMethod = reqMethod
-  request.url = parseUrl(path)
-  try:
-    request.protocol = protocol.parseProtocol()
-  except EInvalidValue:
-    request.respond(Http400, "Invalid request protocol. Got: " & protocol)
-    return
-  
-  case reqMethod.normalize
-  of "get", "post", "head", "put", "delete", "trace", "options", "connect", "patch":
-    await callback(request)
-  else:
-    request.respond(Http400, "Invalid request method. Got: " & reqMethod)
-
-  # Persistent connections
-  if (request.protocol == HttpVer11 and
-      request.headers["connection"].normalize != "close") or
-     (request.protocol == HttpVer10 and
-      request.headers["connection"].normalize == "keep-alive"):
-    # In HTTP 1.1 we assume that connection is persistent. Unless connection
-    # header states otherwise.
-    # In HTTP 1.0 we assume that the connection should not be persistent.
-    # Unless the connection header states otherwise.
-    await processClient(client, address, callback)
-  else:
-    request.client.close()
+    # GET /path HTTP/1.1
+    # Header: val
+    # \n
+    var request = newRequest()
+    request.hostname = address
+    assert client != nil
+    request.client = client
+
+    # First line - GET /path HTTP/1.1
+    let line = await client.recvLine() # TODO: Timeouts.
+    if line == "":
+      client.close()
+      return
+    let lineParts = line.split(' ')
+    if lineParts.len != 3:
+      await request.respond(Http400, "Invalid request. Got: " & line)
+      continue
+
+    let reqMethod = lineParts[0]
+    let path = lineParts[1]
+    let protocol = lineParts[2]
+
+    # Headers
+    var i = 0
+    while true:
+      i = 0
+      let headerLine = await client.recvLine()
+      if headerLine == "":
+        client.close(); return
+      if headerLine == "\c\L": break
+      # TODO: Compiler crash
+      #let (key, value) = parseHeader(headerLine)
+      let kv = parseHeader(headerLine)
+      request.headers[kv.key] = kv.value
+
+    request.reqMethod = reqMethod
+    request.url = parseUrl(path)
+    try:
+      request.protocol = protocol.parseProtocol()
+    except EInvalidValue:
+      asyncCheck request.respond(Http400, "Invalid request protocol. Got: " &
+          protocol)
+      continue
+
+    if reqMethod.normalize == "post":
+      # Check for Expect header
+      if request.headers.hasKey("Expect"):
+        if request.headers["Expect"].toLower == "100-continue":
+          await client.sendStatus("100 Continue")
+        else:
+          await client.sendStatus("417 Expectation Failed")
+    
+      # Read the body
+      # - Check for Content-length header
+      if request.headers.hasKey("Content-Length"):
+        var contentLength = 0
+        if parseInt(request.headers["Content-Length"], contentLength) == 0:
+          await request.respond(Http400, "Bad Request. Invalid Content-Length.")
+        else:
+          request.body = await client.recv(contentLength)
+          assert request.body.len == contentLength
+      else:
+        await request.respond(Http400, "Bad Request. No Content-Length.")
+        continue
+
+    case reqMethod.normalize
+    of "get", "post", "head", "put", "delete", "trace", "options", "connect", "patch":
+      await callback(request)
+    else:
+      await request.respond(Http400, "Invalid request method. Got: " & reqMethod)
+
+    # Persistent connections
+    if (request.protocol == HttpVer11 and
+        request.headers["connection"].normalize != "close") or
+       (request.protocol == HttpVer10 and
+        request.headers["connection"].normalize == "keep-alive"):
+      # In HTTP 1.1 we assume that connection is persistent. Unless connection
+      # header states otherwise.
+      # In HTTP 1.0 we assume that the connection should not be persistent.
+      # Unless the connection header states otherwise.
+    else:
+      request.client.close()
+      break
 
 proc serve*(server: PAsyncHttpServer, port: TPort,
             callback: proc (request: TRequest): PFuture[void],
@@ -168,7 +198,7 @@ proc serve*(server: PAsyncHttpServer, port: TPort,
     # TODO: Causes compiler crash.
     #var (address, client) = await server.socket.acceptAddr()
     var fut = await server.socket.acceptAddr()
-    processClient(fut.client, fut.address, callback)
+    asyncCheck processClient(fut.client, fut.address, callback)
 
 proc close*(server: PAsyncHttpServer) =
   ## Terminates the async http server instance.
@@ -183,5 +213,5 @@ when isMainModule:
         "Content-type": "text/plain; charset=utf-8"}
     await req.respond(Http200, "Hello World", headers.newStringTable())
 
-  server.serve(TPort(5555), cb)
+  asyncCheck server.serve(TPort(5555), cb)
   runForever()
diff --git a/lib/pure/asyncnet.nim b/lib/pure/asyncnet.nim
index d16c85c58..374ac77e3 100644
--- a/lib/pure/asyncnet.nim
+++ b/lib/pure/asyncnet.nim
@@ -80,7 +80,8 @@ proc connect*(socket: PAsyncSocket, address: string, port: TPort,
   ## or an error occurs.
   result = connect(socket.fd.TAsyncFD, address, port, af)
 
-proc readIntoBuf(socket: PAsyncSocket, flags: int): PFuture[int] {.async.} =
+proc readIntoBuf(socket: PAsyncSocket,
+    flags: set[TSocketFlags]): PFuture[int] {.async.} =
   var data = await recv(socket.fd.TAsyncFD, BufferSize, flags)
   if data.len != 0:
     copyMem(addr socket.buffer[0], addr data[0], data.len)
@@ -89,7 +90,7 @@ proc readIntoBuf(socket: PAsyncSocket, flags: int): PFuture[int] {.async.} =
   result = data.len
 
 proc recv*(socket: PAsyncSocket, size: int,
-           flags: int = 0): PFuture[string] {.async.} =
+           flags = {TSocketFlags.SafeDisconn}): PFuture[string] {.async.} =
   ## Reads ``size`` bytes from ``socket``. Returned future will complete once
   ## all of the requested data is read. If socket is disconnected during the
   ## recv operation then the future may complete with only a part of the
@@ -100,7 +101,7 @@ proc recv*(socket: PAsyncSocket, size: int,
     let originalBufPos = socket.currPos
 
     if socket.bufLen == 0:
-      let res = await socket.readIntoBuf(flags and (not MSG_PEEK))
+      let res = await socket.readIntoBuf(flags - {TSocketFlags.Peek})
       if res == 0:
         result.setLen(0)
         return
@@ -108,32 +109,31 @@ proc recv*(socket: PAsyncSocket, size: int,
     var read = 0
     while read < size:
       if socket.currPos >= socket.bufLen:
-        if (flags and MSG_PEEK) == MSG_PEEK:
+        if TSocketFlags.Peek in flags:
           # We don't want to get another buffer if we're peeking.
-          result.setLen(read)
-          return
-        let res = await socket.readIntoBuf(flags and (not MSG_PEEK))
+          break
+        let res = await socket.readIntoBuf(flags - {TSocketFlags.Peek})
         if res == 0:
-          result.setLen(read)
-          return
+          break
 
       let chunk = min(socket.bufLen-socket.currPos, size-read)
       copyMem(addr(result[read]), addr(socket.buffer[socket.currPos]), chunk)
       read.inc(chunk)
       socket.currPos.inc(chunk)
 
-    if (flags and MSG_PEEK) == MSG_PEEK:
+    if TSocketFlags.Peek in flags:
       # Restore old buffer cursor position.
       socket.currPos = originalBufPos
     result.setLen(read)
   else:
     result = await recv(socket.fd.TAsyncFD, size, flags)
 
-proc send*(socket: PAsyncSocket, data: string): PFuture[void] =
+proc send*(socket: PAsyncSocket, data: string,
+           flags = {TSocketFlags.SafeDisconn}): PFuture[void] =
   ## Sends ``data`` to ``socket``. The returned future will complete once all
   ## data has been sent.
   assert socket != nil
-  result = send(socket.fd.TAsyncFD, data)
+  result = send(socket.fd.TAsyncFD, data, flags)
 
 proc acceptAddr*(socket: PAsyncSocket): 
       PFuture[tuple[address: string, client: PAsyncSocket]] =
@@ -168,7 +168,8 @@ proc accept*(socket: PAsyncSocket): PFuture[PAsyncSocket] =
         retFut.complete(future.read.client)
   return retFut
 
-proc recvLine*(socket: PAsyncSocket): PFuture[string] {.async.} =
+proc recvLine*(socket: PAsyncSocket,
+    flags = {TSocketFlags.SafeDisconn}): PFuture[string] {.async.} =
   ## Reads a line of data from ``socket``. Returned future will complete once
   ## a full line is read or an error occurs.
   ##
@@ -181,28 +182,60 @@ proc recvLine*(socket: PAsyncSocket): PFuture[string] {.async.} =
   ## If the socket is disconnected in the middle of a line (before ``\r\L``
   ## is read) then line will be set to ``""``.
   ## The partial line **will be lost**.
-  
+  ##
+  ## **Warning**: The ``Peek`` flag is not yet implemented.
   template addNLIfEmpty(): stmt =
     if result.len == 0:
       result.add("\c\L")
+  assert TSocketFlags.Peek notin flags ## TODO:
+  if socket.isBuffered:
+    result = ""
+    if socket.bufLen == 0:
+      let res = await socket.readIntoBuf(flags)
+      if res == 0:
+        return
+
+    var lastR = false
+    while true:
+      if socket.currPos >= socket.bufLen:
+        let res = await socket.readIntoBuf(flags)
+        if res == 0:
+          result = ""
+          break
 
-  result = ""
-  var c = ""
-  while true:
-    c = await recv(socket, 1)
-    if c.len == 0:
-      return ""
-    if c == "\r":
-      c = await recv(socket, 1, MSG_PEEK)
-      if c.len > 0 and c == "\L":
-        let dummy = await recv(socket, 1)
-        assert dummy == "\L"
-      addNLIfEmpty()
-      return
-    elif c == "\L":
-      addNLIfEmpty()
-      return
-    add(result.string, c)
+      case socket.buffer[socket.currPos]
+      of '\r':
+        lastR = true
+        addNLIfEmpty()
+      of '\L':
+        addNLIfEmpty()
+        socket.currPos.inc()
+        return
+      else:
+        if lastR:
+          socket.currPos.inc()
+          return
+        else:
+          result.add socket.buffer[socket.currPos]
+      socket.currPos.inc()
+  else:
+    result = ""
+    var c = ""
+    while true:
+      c = await recv(socket, 1, flags)
+      if c.len == 0:
+        return ""
+      if c == "\r":
+        c = await recv(socket, 1, flags + {TSocketFlags.Peek})
+        if c.len > 0 and c == "\L":
+          let dummy = await recv(socket, 1, flags)
+          assert dummy == "\L"
+        addNLIfEmpty()
+        return
+      elif c == "\L":
+        addNLIfEmpty()
+        return
+      add(result.string, c)
 
 proc bindAddr*(socket: PAsyncSocket, port = TPort(0), address = "") =
   ## Binds ``address``:``port`` to the socket.
@@ -241,7 +274,7 @@ when isMainModule:
           break
         else:
           echo("Got line: ", line)
-    main()
+    asyncCheck main()
   elif test == LowClient:
     var sock = newAsyncSocket()
     var f = connect(sock, "irc.freenode.net", TPort(6667))
diff --git a/lib/pure/collections/sequtils.nim b/lib/pure/collections/sequtils.nim
index f5db9d3fa..e760c5e02 100644
--- a/lib/pure/collections/sequtils.nim
+++ b/lib/pure/collections/sequtils.nim
@@ -47,19 +47,15 @@ proc concat*[T](seqs: varargs[seq[T]]): seq[T] =
       result[i] = itm
       inc(i)
 
-proc distnct*[T](seq1: seq[T]): seq[T] =
+proc deduplicate*[T](seq1: seq[T]): seq[T] =
   ## Returns a new sequence without duplicates.
   ##
-  ## This proc is `misspelled` on purpose to avoid a clash with the keyword
-  ## ``distinct`` used to `define a derived type incompatible with its base
-  ## type <manual.html#distinct-type>`_. Example:
-  ##
   ## .. code-block:: nimrod
   ##   let
   ##     dup1 = @[1, 1, 3, 4, 2, 2, 8, 1, 4]
   ##     dup2 = @["a", "a", "c", "d", "d"]
-  ##     unique1 = distnct(dup1)
-  ##     unique2 = distnct(dup2)
+  ##     unique1 = deduplicate(dup1)
+  ##     unique2 = deduplicate(dup2)
   ##   assert unique1 == @[1, 3, 4, 2, 8]
   ##   assert unique2 == @["a", "c", "d"]
   result = @[]
@@ -182,6 +178,24 @@ proc filter*[T](seq1: seq[T], pred: proc(item: T): bool {.closure.}): seq[T] =
   ##   assert f2 == @["yellow"]
   accumulateResult(filter(seq1, pred))
 
+proc keepIf*[T](seq1: var seq[T], pred: proc(item: T): bool {.closure.}) =
+  ## Keeps the items in the passed sequence if they fulfilled the predicate.
+  ## Same as the ``filter`` proc, but modifies the sequence directly.
+  ##
+  ## Example:
+  ##
+  ## .. code-block:: nimrod
+  ##   var floats = @[13.0, 12.5, 5.8, 2.0, 6.1, 9.9, 10.1]
+  ##   filter(floats, proc(x: float): bool = x > 10)
+  ##   assert floats == @[13.0, 12.5, 10.1]
+  var pos = 0
+  for i in 0 .. <len(seq1):
+    if pred(seq1[i]):
+      if pos != i:
+        seq1[pos] = seq1[i]
+      inc(pos)
+  setLen(seq1, pos)
+
 proc delete*[T](s: var seq[T], first=0, last=0) =
   ## Deletes in `s` the items at position `first` .. `last`. This modifies
   ## `s` itself, it does not return a copy.
@@ -252,6 +266,27 @@ template filterIt*(seq1, pred: expr): expr {.immediate.} =
     if pred: result.add(it)
   result
 
+template keepItIf*(varSeq, pred: expr) =
+  ## Convenience template around the ``keepIf`` proc to reduce typing.
+  ##
+  ## Unlike the `proc` version, the predicate needs to be an expression using
+  ## the ``it`` variable for testing, like: ``keepItIf("abcxyz", it == 'x')``.
+  ## Example:
+  ##
+  ## .. code-block:: nimrod
+  ##   var candidates = @["foo", "bar", "baz", "foobar"]
+  ##   keepItIf(candidates, it.len == 3 and it[0] == 'b')
+  ##   assert candidates == @["bar", "baz"]
+  var pos = 0
+  for i in 0 .. <len(varSeq):
+    let it {.inject.} = varSeq[i]
+    if pred:
+      if pos != i:
+        varSeq[pos] = varSeq[i]
+      inc(pos)
+  setLen(varSeq, pos)
+
+
 template toSeq*(iter: expr): expr {.immediate.} =
   ## Transforms any iterator into a sequence.
   ##
@@ -387,8 +422,8 @@ when isMainModule:
     let
       dup1 = @[1, 1, 3, 4, 2, 2, 8, 1, 4]
       dup2 = @["a", "a", "c", "d", "d"]
-      unique1 = distnct(dup1)
-      unique2 = distnct(dup2)
+      unique1 = deduplicate(dup1)
+      unique2 = deduplicate(dup2)
     assert unique1 == @[1, 3, 4, 2, 8]
     assert unique2 == @["a", "c", "d"]
 
@@ -418,6 +453,11 @@ when isMainModule:
       echo($n)
     # echoes 4, 8, 4 in separate lines
 
+  block: # keepIf test
+    var floats = @[13.0, 12.5, 5.8, 2.0, 6.1, 9.9, 10.1]
+    keepIf(floats, proc(x: float): bool = x > 10)
+    assert floats == @[13.0, 12.5, 10.1]
+
   block: # filterIt test
     let
       temperatures = @[-272.15, -2.0, 24.5, 44.31, 99.9, -113.44]
@@ -426,6 +466,11 @@ when isMainModule:
     assert acceptable == @[-2.0, 24.5, 44.31]
     assert notAcceptable == @[-272.15, 99.9, -113.44]
 
+  block: # keepItIf test
+    var candidates = @["foo", "bar", "baz", "foobar"]
+    keepItIf(candidates, it.len == 3 and it[0] == 'b')
+    assert candidates == @["bar", "baz"]
+
   block: # toSeq test
     let
       numeric = @[1, 2, 3, 4, 5, 6, 7, 8, 9]
diff --git a/lib/pure/httpclient.nim b/lib/pure/httpclient.nim
index be06a7b8e..9bacc80d6 100644
--- a/lib/pure/httpclient.nim
+++ b/lib/pure/httpclient.nim
@@ -654,7 +654,7 @@ when isMainModule:
       resp = await client.request("http://nimrod-lang.org/download.html")
       echo("Got response: ", resp.status)
 
-    main()
+    asyncCheck main()
     runForever()
 
   else:
diff --git a/lib/pure/math.nim b/lib/pure/math.nim
index 78ea02cbf..2f7a696b9 100644
--- a/lib/pure/math.nim
+++ b/lib/pure/math.nim
@@ -10,7 +10,8 @@
 ##   Constructive mathematics is naturally typed. -- Simon Thompson
 ## 
 ## Basic math routines for Nimrod.
-## This module is available for the JavaScript target.
+## This module is available for the `JavaScript target
+## <backends.html#the-javascript-target>`_.
 
 include "system/inclrtl"
 
diff --git a/lib/pure/net.nim b/lib/pure/net.nim
index e34c88327..ddc2bbe2d 100644
--- a/lib/pure/net.nim
+++ b/lib/pure/net.nim
@@ -350,6 +350,30 @@ type
 
   ETimeout* = object of ESynch
 
+  TSocketFlags* {.pure.} = enum
+    Peek,
+    SafeDisconn ## Ensures disconnection exceptions (ECONNRESET, EPIPE etc) are not thrown.
+
+proc isDisconnectionError*(flags: set[TSocketFlags],
+    lastError: TOSErrorCode): bool =
+  ## Determines whether ``lastError`` is a disconnection error. Only does this
+  ## if flags contains ``SafeDisconn``.
+  when useWinVersion:
+    TSocketFlags.SafeDisconn in flags and
+      lastError.int32 in {WSAECONNRESET, WSAECONNABORTED, WSAENETRESET,
+                          WSAEDISCON}
+  else:
+    TSocketFlags.SafeDisconn in flags and
+      lastError.int32 in {ECONNRESET, EPIPE, ENETRESET} 
+
+proc toOSFlags*(socketFlags: set[TSocketFlags]): cint =
+  ## Converts the flags into the underlying OS representation.
+  for f in socketFlags:
+    case f
+    of TSocketFlags.Peek:
+      result = result or MSG_PEEK
+    of TSocketFlags.SafeDisconn: continue
+
 proc createSocket(fd: TSocketHandle, isBuff: bool): PSocket =
   assert fd != osInvalidSocket
   new(result)
@@ -470,7 +494,8 @@ when defined(ssl):
     if SSLSetFd(socket.sslHandle, socket.fd) != 1:
       SSLError()
 
-proc socketError*(socket: PSocket, err: int = -1, async = false) =
+proc socketError*(socket: PSocket, err: int = -1, async = false,
+                  lastError = (-1).TOSErrorCode) =
   ## Raises an EOS error based on the error code returned by ``SSLGetError``
   ## (for SSL sockets) and ``osLastError`` otherwise.
   ##
@@ -500,17 +525,17 @@ proc socketError*(socket: PSocket, err: int = -1, async = false) =
         else: SSLError("Unknown Error")
   
   if err == -1 and not (when defined(ssl): socket.isSSL else: false):
-    let lastError = osLastError()
+    let lastE = if lastError.int == -1: osLastError() else: lastError
     if async:
       when useWinVersion:
-        if lastError.int32 == WSAEWOULDBLOCK:
+        if lastE.int32 == WSAEWOULDBLOCK:
           return
-        else: osError(lastError)
+        else: osError(lastE)
       else:
-        if lastError.int32 == EAGAIN or lastError.int32 == EWOULDBLOCK:
+        if lastE.int32 == EAGAIN or lastE.int32 == EWOULDBLOCK:
           return
-        else: osError(lastError)
-    else: osError(lastError)
+        else: osError(lastE)
+    else: osError(lastE)
 
 proc listen*(socket: PSocket, backlog = SOMAXCONN) {.tags: [FReadIO].} =
   ## Marks ``socket`` as accepting connections. 
@@ -881,7 +906,8 @@ proc recv*(socket: PSocket, data: pointer, size: int, timeout: int): int {.
   
   result = read
 
-proc recv*(socket: PSocket, data: var string, size: int, timeout = -1): int =
+proc recv*(socket: PSocket, data: var string, size: int, timeout = -1,
+           flags = {TSocketFlags.SafeDisconn}): int =
   ## Higher-level version of ``recv``.
   ##
   ## When 0 is returned the socket's connection has been closed.
@@ -893,11 +919,15 @@ proc recv*(socket: PSocket, data: var string, size: int, timeout = -1): int =
   ## within the time specified an ETimeout exception will be raised.
   ##
   ## **Note**: ``data`` must be initialised.
+  ##
+  ## **Warning**: Only the ``SafeDisconn`` flag is currently supported.
   data.setLen(size)
   result = recv(socket, cstring(data), size, timeout)
   if result < 0:
     data.setLen(0)
-    socket.socketError(result)
+    let lastError = osLastError()
+    if flags.isDisconnectionError(lastError): return
+    socket.socketError(result, lastError = lastError)
   data.setLen(result)
 
 proc peekChar(socket: PSocket, c: var char): int {.tags: [FReadIO].} =
@@ -920,7 +950,8 @@ proc peekChar(socket: PSocket, c: var char): int {.tags: [FReadIO].} =
         return
     result = recv(socket.fd, addr(c), 1, MSG_PEEK)
 
-proc readLine*(socket: PSocket, line: var TaintedString, timeout = -1) {.
+proc readLine*(socket: PSocket, line: var TaintedString, timeout = -1,
+               flags = {TSocketFlags.SafeDisconn}) {.
   tags: [FReadIO, FTime].} =
   ## Reads a line of data from ``socket``.
   ##
@@ -934,11 +965,18 @@ proc readLine*(socket: PSocket, line: var TaintedString, timeout = -1) {.
   ##
   ## A timeout can be specified in miliseconds, if data is not received within
   ## the specified time an ETimeout exception will be raised.
+  ##
+  ## **Warning**: Only the ``SafeDisconn`` flag is currently supported.
   
   template addNLIfEmpty(): stmt =
     if line.len == 0:
       line.add("\c\L")
 
+  template raiseSockError(): stmt {.dirty, immediate.} =
+    let lastError = osLastError()
+    if flags.isDisconnectionError(lastError): setLen(line.string, 0); return
+    socket.socketError(n, lastError = lastError)
+
   var waited = 0.0
 
   setLen(line.string, 0)
@@ -946,14 +984,14 @@ proc readLine*(socket: PSocket, 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: socket.socketError()
-    elif n == 0: return
+    if n < 0: raiseSockError()
+    elif n == 0: setLen(line.string, 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: socket.socketError()
+      elif n <= 0: raiseSockError()
       addNLIfEmpty()
       return
     elif c == '\L': 
@@ -1021,11 +1059,14 @@ proc send*(socket: PSocket, data: pointer, size: int): int {.
       const MSG_NOSIGNAL = 0
     result = send(socket.fd, data, size, int32(MSG_NOSIGNAL))
 
-proc send*(socket: PSocket, data: string) {.tags: [FWriteIO].} =
+proc send*(socket: PSocket, data: string,
+           flags = {TSocketFlags.SafeDisconn}) {.tags: [FWriteIO].} =
   ## sends data to a socket.
   let sent = send(socket, cstring(data), data.len)
   if sent < 0:
-    socketError(socket)
+    let lastError = osLastError()
+    if flags.isDisconnectionError(lastError): return
+    socketError(socket, lastError = lastError)
 
   if sent != data.len:
     raise newException(EOS, "Could not send all data.")
diff --git a/lib/pure/os.nim b/lib/pure/os.nim
index e2fc62d77..0b4538abc 100644
--- a/lib/pure/os.nim
+++ b/lib/pure/os.nim
@@ -1769,16 +1769,16 @@ else:
     FileId = TIno
 
 type
-  FileInfo = object
+  FileInfo* = object
     ## Contains information associated with a file object.
-    id: tuple[device: DeviceId, file: FileId] # Device and file id.
-    kind: TPathComponent # Kind of file object - directory, symlink, etc.
-    size: BiggestInt # Size of file.
-    permissions: set[TFilePermission] # File permissions
-    linkCount: BiggestInt # Number of hard links the file object has.
-    lastAccessTime: TTime # Time file was last accessed.
-    lastWriteTime: TTime # Time file was last modified/written to.
-    creationTime: TTime # Time file was created. Not supported on all systems!
+    id*: tuple[device: DeviceId, file: FileId] # Device and file id.
+    kind*: TPathComponent # Kind of file object - directory, symlink, etc.
+    size*: BiggestInt # Size of file.
+    permissions*: set[TFilePermission] # File permissions
+    linkCount*: BiggestInt # Number of hard links the file object has.
+    lastAccessTime*: TTime # Time file was last accessed.
+    lastWriteTime*: TTime # Time file was last modified/written to.
+    creationTime*: TTime # Time file was created. Not supported on all systems!
 
 template rawToFormalFileInfo(rawInfo, formalInfo): expr =
   ## Transforms the native file info structure into the one nimrod uses.
diff --git a/lib/pure/rawsockets.nim b/lib/pure/rawsockets.nim
index 94189fd89..d96741846 100644
--- a/lib/pure/rawsockets.nim
+++ b/lib/pure/rawsockets.nim
@@ -21,11 +21,12 @@ const useWinVersion = defined(Windows) or defined(nimdoc)
 
 when useWinVersion:
   import winlean
-  export WSAEWOULDBLOCK
+  export WSAEWOULDBLOCK, WSAECONNRESET, WSAECONNABORTED, WSAENETRESET,
+         WSAEDISCON
 else:
   import posix
   export fcntl, F_GETFL, O_NONBLOCK, F_SETFL, EAGAIN, EWOULDBLOCK, MSG_NOSIGNAL,
-    EINTR, EINPROGRESS
+    EINTR, EINPROGRESS, ECONNRESET, EPIPE, ENETRESET
 
 export TSocketHandle, TSockaddr_in, TAddrinfo, INADDR_ANY, TSockAddr, TSockLen,
   inet_ntoa, recv, `==`, connect, send, accept, recvfrom, sendto
diff --git a/lib/pure/selectors.nim b/lib/pure/selectors.nim
index 3af5f699c..bd53c2dbf 100644
--- a/lib/pure/selectors.nim
+++ b/lib/pure/selectors.nim
@@ -163,7 +163,7 @@ elif defined(linux):
   proc newSelector*(): PSelector =
     new result
     result.epollFD = epoll_create(64)
-    result.events = cast[array[64, epoll_event]](alloc0(sizeof(epoll_event)*64))
+    #result.events = cast[array[64, epoll_event]](alloc0(sizeof(epoll_event)*64))
     result.fds = initTable[TSocketHandle, PSelectorKey]()
     if result.epollFD < 0:
       OSError(OSLastError())
diff --git a/lib/pure/strutils.nim b/lib/pure/strutils.nim
index bd6814dcc..e642f6a99 100644
--- a/lib/pure/strutils.nim
+++ b/lib/pure/strutils.nim
@@ -10,6 +10,8 @@
 ## This module contains various string utility routines.
 ## See the module `re <re.html>`_ for regular expression support.
 ## See the module `pegs <pegs.html>`_ for PEG support.
+## This module is available for the `JavaScript target
+## <backends.html#the-javascript-target>`_.
 
 import parseutils
 
diff --git a/lib/pure/times.nim b/lib/pure/times.nim
index fdff06b2a..498511899 100644
--- a/lib/pure/times.nim
+++ b/lib/pure/times.nim
@@ -9,7 +9,8 @@
 
 
 ## This module contains routines and types for dealing with time.
-## This module is available for the JavaScript target.
+## This module is available for the `JavaScript target
+## <backends.html#the-javascript-target>`_.
 
 {.push debugger:off.} # the user does not want to trace a part
                       # of the standard library!
diff --git a/lib/system.nim b/lib/system.nim
index 3e5308f90..3c42385b7 100644
--- a/lib/system.nim
+++ b/lib/system.nim
@@ -46,6 +46,7 @@ const
   on* = true    ## alias for ``true``
   off* = false  ## alias for ``false``
 
+{.push warning[GcMem]: off.}
 {.push hints: off.}
 
 type
@@ -431,12 +432,12 @@ proc pred*[T](x: Ordinal[T], y = 1): T {.magic: "Pred", noSideEffect.}
   ## an ordinal type. If such a value does not exist, ``EOutOfRange`` is raised
   ## or a compile time error occurs.
 
-proc inc*[T](x: var Ordinal[T], y = 1) {.magic: "Inc", noSideEffect.}
+proc inc*[T: Ordinal|uint|uint64](x: var T, y = 1) {.magic: "Inc", noSideEffect.}
   ## increments the ordinal ``x`` by ``y``. If such a value does not
   ## exist, ``EOutOfRange`` is raised or a compile time error occurs. This is a
   ## short notation for: ``x = succ(x, y)``.
 
-proc dec*[T](x: var Ordinal[T], y = 1) {.magic: "Dec", noSideEffect.}
+proc dec*[T: Ordinal|uint|uint64](x: var T, y = 1) {.magic: "Dec", noSideEffect.}
   ## decrements the ordinal ``x`` by ``y``. If such a value does not
   ## exist, ``EOutOfRange`` is raised or a compile time error occurs. This is a
   ## short notation for: ``x = pred(x, y)``.
@@ -2663,6 +2664,8 @@ when hostOS != "standalone":
 proc `[]`*[Idx, T](a: array[Idx, T], x: TSlice[int]): seq[T] =
   ## slice operation for arrays. Negative indexes are **not** supported
   ## because the array might have negative bounds.
+  when low(a) < 0:
+    {.error: "Slicing for arrays with negative indices is unsupported.".}
   var L = x.b - x.a + 1
   newSeq(result, L)
   for i in 0.. <L: result[i] = a[i + x.a]
@@ -2670,6 +2673,8 @@ proc `[]`*[Idx, T](a: array[Idx, T], x: TSlice[int]): seq[T] =
 proc `[]=`*[Idx, T](a: var array[Idx, T], x: TSlice[int], b: openArray[T]) =
   ## slice assignment for arrays. Negative indexes are **not** supported
   ## because the array might have negative bounds.
+  when low(a) < 0:
+    {.error: "Slicing for arrays with negative indices is unsupported.".}
   var L = x.b - x.a + 1
   if L == b.len:
     for i in 0 .. <L: a[i+x.a] = b[i]
@@ -2745,13 +2750,13 @@ proc staticExec*(command: string, input = ""): string {.
   ## inside a pragma like `passC <nimrodc.html#passc-pragma>`_ or `passL
   ## <nimrodc.html#passl-pragma>`_.
 
-proc `+=`*[T: TOrdinal](x: var T, y: T) {.magic: "Inc", noSideEffect.}
+proc `+=`*[T: TOrdinal|uint|uint64](x: var T, y: T) {.magic: "Inc", noSideEffect.}
   ## Increments an ordinal
 
-proc `-=`*[T: TOrdinal](x: var T, y: T) {.magic: "Dec", noSideEffect.}
+proc `-=`*[T: TOrdinal|uint|uint64](x: var T, y: T) {.magic: "Dec", noSideEffect.}
   ## Decrements an ordinal
 
-proc `*=`*[T: TOrdinal](x: var T, y: T) {.inline, noSideEffect.} =
+proc `*=`*[T: TOrdinal|uint|uint64](x: var T, y: T) {.inline, noSideEffect.} =
   ## Binary `*=` operator for ordinals
   x = x * y
 
@@ -2990,6 +2995,8 @@ proc deepCopy*[T](x: T): T {.magic: "DeepCopy", noSideEffect.} =
   ## for the implementation of ``spawn``.
   discard
 
+{.pop.} #{.push warning[GcMem]: off.}
+
 when not defined(booting):
   type
     semistatic*[T] = static[T] | T
diff --git a/tests/async/tasyncawait.nim b/tests/async/tasyncawait.nim
index da4952677..2d65db4bd 100644
--- a/tests/async/tasyncawait.nim
+++ b/tests/async/tasyncawait.nim
@@ -61,11 +61,11 @@ proc createServer(port: TPort) {.async.} =
   discard server.TSocketHandle.listen()
   while true:
     var client = await accept(server)
-    readMessages(client)
+    asyncCheck readMessages(client)
     # TODO: Test: readMessages(disp, await disp.accept(server))
 
-createServer(TPort(10335))
-launchSwarm(TPort(10335))
+asyncCheck createServer(TPort(10335))
+asyncCheck launchSwarm(TPort(10335))
 while true:
   poll()
   if clientCount == swarmSize: break
diff --git a/tests/async/tasyncdiscard.nim b/tests/async/tasyncdiscard.nim
index 48d8a8c4d..966851acc 100644
--- a/tests/async/tasyncdiscard.nim
+++ b/tests/async/tasyncdiscard.nim
@@ -36,4 +36,4 @@ proc main {.async.} =
   discard await g()
   echo 6
 
-main()
+asyncCheck main()
diff --git a/tests/async/tnestedpfuturetypeparam.nim b/tests/async/tnestedpfuturetypeparam.nim
index d0d87e567..1db442170 100644
--- a/tests/async/tnestedpfuturetypeparam.nim
+++ b/tests/async/tnestedpfuturetypeparam.nim
@@ -5,4 +5,4 @@ proc main {.async.} =
     await newAsyncSocket().connect("www.google.com", TPort(80))
   let x = await f()
 
-main()
+asyncCheck main()
diff --git a/tests/casestmt/tcase_arrayconstr.nim b/tests/casestmt/tcase_arrayconstr.nim
new file mode 100644
index 000000000..cd7156600
--- /dev/null
+++ b/tests/casestmt/tcase_arrayconstr.nim
@@ -0,0 +1,19 @@
+discard """
+  output: '''Not found!
+Found!'''
+"""
+
+const
+  md_extension = [".md", ".markdown"]
+
+proc test(ext: string) =
+  case ext
+  of ".txt", md_extension:
+    echo "Found!"
+  else:
+    echo "Not found!"
+
+test(".something")
+# ensure it's not evaluated at compile-time:
+var foo = ".markdown"
+test(foo)
diff --git a/tests/exprs/tstmtexprs.nim b/tests/exprs/tstmtexprs.nim
index ed0066287..d6b827b6d 100644
--- a/tests/exprs/tstmtexprs.nim
+++ b/tests/exprs/tstmtexprs.nim
@@ -4,7 +4,8 @@ discard """
 1244
 6
 abcdefghijklmnopqrstuvwxyz
-145 23'''
+145 23
+3'''
 """
 
 import strutils
@@ -92,3 +93,32 @@ proc parseResponse(): PJsonNode =
 #bug #992
 var se = @[1,2]
 let b = (se[1] = 1; 1)
+
+
+# bug #1161
+
+type
+  PFooBase = ref object of PObject
+    field: int
+
+  PFoo[T] = ref object of PFooBase
+    field2: T
+
+var testIf =
+  if true:
+    2
+  else:
+    3
+
+var testCase =
+  case 8
+  of 8: 9
+  else: 10
+
+var testTry =
+  try:
+    PFoo[string](field: 3, field2: "asfasf")
+  except:
+    PFooBase(field: 5)
+
+echo(testTry.field)
diff --git a/tests/generics/mdotlookup.nim b/tests/generics/mdotlookup.nim
new file mode 100644
index 000000000..7a5e0ccbf
--- /dev/null
+++ b/tests/generics/mdotlookup.nim
@@ -0,0 +1,8 @@
+proc baz(o: any): int = 5 # if bar is exported, it works
+
+type MyObj = object
+  x: int
+
+proc foo*(b: any) =
+  var o: MyObj
+  echo b.baz, " ", o.x.baz, " ", b.baz()
diff --git a/tests/generics/tdotlookup.nim b/tests/generics/tdotlookup.nim
new file mode 100644
index 000000000..b886cd8c9
--- /dev/null
+++ b/tests/generics/tdotlookup.nim
@@ -0,0 +1,7 @@
+discard """
+  output: '''5 5 5'''
+"""
+
+import mdotlookup
+
+foo(7)
diff --git a/tests/macros/tbindsym.nim b/tests/macros/tbindsym.nim
new file mode 100644
index 000000000..e1e3b5112
--- /dev/null
+++ b/tests/macros/tbindsym.nim
@@ -0,0 +1,25 @@
+discard """
+  output: '''TFoo
+TBar'''
+"""
+
+# bug #1319
+
+import macros
+
+type
+  TTextKind = enum
+    TFoo, TBar
+
+macro test: stmt =
+  var x = @[TFoo, TBar]
+  result = newStmtList()
+  for i in x:
+    result.add newCall(newIdentNode("echo"),
+      case i
+      of TFoo:
+        bindSym("TFoo")
+      of TBar:
+        bindSym("TBar"))
+
+test()
diff --git a/tests/macros/tbug1149.nim b/tests/macros/tbug1149.nim
deleted file mode 100644
index 5c4cb8530..000000000
--- a/tests/macros/tbug1149.nim
+++ /dev/null
@@ -1,20 +0,0 @@
-discard """
-msg: '''a
-s
-d
-f'''
-"""
-
-type
-  Foo = object
-    s: char
-
-iterator test2(f: string): Foo =
-  for i in f:
-    yield Foo(s: i)
-
-macro test(): stmt =
-  for i in test2("asdf"):
-    echo i.s
-
-test()
diff --git a/tests/macros/tbugs.nim b/tests/macros/tbugs.nim
new file mode 100644
index 000000000..3db851dd1
--- /dev/null
+++ b/tests/macros/tbugs.nim
@@ -0,0 +1,90 @@
+discard """
+msg: '''a
+s
+d
+f
+TTaa
+TTaa
+TTaa
+TTaa
+true
+true
+nil'''
+
+output: '''test
+2'''
+"""
+
+type
+  Foo = object
+    s: char
+
+iterator test2(f: string): Foo =
+  for i in f:
+    yield Foo(s: i)
+
+macro test(): stmt =
+  for i in test2("asdf"):
+    echo i.s
+
+test()
+
+
+# bug 1297
+
+import macros
+
+type TType = tuple[s: string]
+
+macro echotest(): stmt =
+  var t: TType
+  t.s = ""
+  t.s.add("test")
+  result = newCall(newIdentNode("echo"), newStrLitNode(t.s))
+
+echotest()
+
+# bug #1103
+
+type 
+    Td = tuple
+        a:string
+        b:int
+
+proc get_data(d: Td) : string {.compileTime.} =
+    result = d.a # Works if a literal string is used here. 
+    # Bugs if line A or B is active. Works with C
+    result &= "aa"          # A
+    #result.add("aa")       # B
+    #result = result & "aa" # C
+
+macro m(s:static[Td]) : stmt =
+    echo get_data(s)
+    echo get_data(s)
+    result = newEmptyNode()
+
+const s=("TT", 3)
+m(s)
+m(s)
+
+# bug #933
+
+proc nilcheck(): PNimrodNode {.compileTime.} =
+  echo(result == nil) # true
+  echo(result.isNil) # true
+  echo(repr(result)) # nil
+
+macro testnilcheck(): stmt =
+  result = newNimNode(nnkStmtList)
+  discard nilcheck()
+
+testnilcheck()
+
+# bug #1323
+
+proc calc(): array[1, int] =
+  result[0].inc()
+  result[0].inc()
+
+const c = calc()
+echo c[0]
diff --git a/tests/metatype/tautoproc.nim b/tests/metatype/tautoproc.nim
new file mode 100644
index 000000000..9e8ff0bcb
--- /dev/null
+++ b/tests/metatype/tautoproc.nim
@@ -0,0 +1,16 @@
+# bug #898
+
+proc measureTime(e: auto) =
+  discard
+
+proc generate(a: int): void =
+  discard
+
+proc runExample =
+  var builder: int = 0
+
+  measureTime:
+    builder.generate()
+
+measureTime:
+  discard
diff --git a/tests/objects/tobjconstr2.nim b/tests/objects/tobjconstr2.nim
index cb47e146d..8ef7004e4 100644
--- a/tests/objects/tobjconstr2.nim
+++ b/tests/objects/tobjconstr2.nim
@@ -20,3 +20,15 @@ type
 
 var a = Bar(y: 100, x: 200) # works
 var b = Bar(x: 100, y: 200) # used to fail
+
+# bug 1275
+
+type
+  Graphic = object of TObject
+    case kind: range[0..1]
+    of 0:
+      radius: float
+    of 1:
+      size: tuple[w, h: float]
+
+var d = Graphic(kind: 1, size: (12.9, 6.9))
diff --git a/tests/seq/tsequtils.nim b/tests/seq/tsequtils.nim
index 7bc15ef9c..3a7eeeffa 100644
--- a/tests/seq/tsequtils.nim
+++ b/tests/seq/tsequtils.nim
@@ -50,6 +50,6 @@ var concatseq = concat(seq1,seq2)
 echo "Concat: ", $$(concatseq)
 
 var seq3 = @[1,2,3,4,5,5,5,7]
-var discntseq = distnct(seq3)
-echo "Distnct: ", $$(discntseq)
+var dedupseq = deduplicate(seq3)
+echo "Deduplicate: ", $$(dedupseq)
 
diff --git a/tests/vm/tarrayboundeval.nim b/tests/vm/tarrayboundeval.nim
index 9b33a2415..07aac4c4e 100644
--- a/tests/vm/tarrayboundeval.nim
+++ b/tests/vm/tarrayboundeval.nim
@@ -1,6 +1,7 @@
 discard """
   output: '''7
-8 8'''
+8 8
+-2'''
 """
 
 #bug 1063
@@ -21,3 +22,10 @@ type
     internal: array[int((KeyMax + 31)/32), cuint]
     
 echo myconst, " ", int((KeyMax + 31) / 32)
+
+#bug 1304 or something:
+
+const constArray: array [-3..2, int] = [-3, -2, -1, 0, 1, 2]
+
+echo constArray[-2]
+
diff --git a/tests/vm/teval1.nim b/tests/vm/teval1.nim
index a02f26592..cdb4ad8e2 100644
--- a/tests/vm/teval1.nim
+++ b/tests/vm/teval1.nim
@@ -16,4 +16,9 @@ const
   
 echo "##", x, "##"
 
+# bug #1310
+static:
+    var i, j: set[int8] = {}
+    var k = i + j
+
 
diff --git a/todo.txt b/todo.txt
index d9d91b1ec..16c05186a 100644
--- a/todo.txt
+++ b/todo.txt
@@ -1,19 +1,21 @@
 version 0.9.6
 =============
 
+- scopes are still broken for generic instantiation!
+- integrate the new LL into the devel branch
+- start experimental branch
 - overloading of '='; general lift mechanism
 
-
 Concurrency
 -----------
 
+- 'gcsafe' inferrence needs to be fixed
 - the disjoint checker needs to deal with 'a = spawn f(); g = spawn f()'
 - implement 'deepCopy' builtin
 - implement 'foo[1..4] = spawn(f[4..7])'
 - support for exception propagation
 - Minor: The copying of the 'ref Promise' into the thead local storage only
   happens to work due to the write barrier's implementation
-- 'gcsafe' inferrence needs to be fixed
 - implement lock levels --> first without the more complex race avoidance
 - document the new 'spawn' and 'parallel' statements
 
@@ -32,6 +34,7 @@ Misc
 - type API for macros; make 'spawn' a macro
 - markAndSweepGC should expose an API for fibers
 - prevent 'alloc(TypeWithGCedMemory)'
+- some table related tests are wrong (memory usage checks)
 
 
 Bugs
diff --git a/web/babelpkglist.nim b/web/babelpkglist.nim
index 378d4ce30..8745c9f99 100644
--- a/web/babelpkglist.nim
+++ b/web/babelpkglist.nim
@@ -28,13 +28,19 @@ proc processContent(content: string) =
     officialCount = 0
     unofficialList = ""
     unofficialCount = 0
+  let
+    endings = {'.', '!'}
 
   for pkg in jsonArr:
     assert pkg.kind == JObject
     let pkgWeb =
       if pkg.hasKey("web"): pkg["web"].str
       else: pkg["url"].str
-    let listItem = li(a(href=pkgWeb, pkg["name"].str), " ", pkg["description"].str)
+    let
+      desc = pkg["description"].str
+      # Review array index access when #1291 is solved.
+      dot = if desc.high > 0 and desc[<desc.high] in endings: "" else: "."
+      listItem = li(a(href=pkgWeb, pkg["name"].str), " ", desc & dot)
     if pkg["url"].str.startsWith("git://github.com/nimrod-code") or
        "official" in pkg["tags"].elems:
       officialCount.inc
diff --git a/web/news.txt b/web/news.txt
index 74a48493a..aa91a83c4 100644
--- a/web/news.txt
+++ b/web/news.txt
@@ -12,6 +12,8 @@ News
   - ``spawn`` now uses an elaborate self-adapting thread pool and as such
     has been moved into its own module. So to use it, you now have to import
     ``threadpool``.
+  - The symbol binding rules in generics changed: ``bar`` in ``foo.bar`` is
+    now considered for implicit early binding.
   - ``c2nim`` moved into its own repository and is now a Babel package.
   - ``pas2nim`` moved into its own repository and is now a Babel package.
 
@@ -21,6 +23,7 @@ News
 
   - Added module ``cpuinfo``.
   - Added module ``threadpool``.
+  - ``sequtils.distnct`` has been renamed to ``sequtils.deduplicate``.
 
 
 2014-04-21 Version 0.9.4 released
diff --git a/web/nimrod.ini b/web/nimrod.ini
index eb9ffa6b4..7b0a91c19 100644
--- a/web/nimrod.ini
+++ b/web/nimrod.ini
@@ -36,8 +36,8 @@ UNIX. We don't believe this to be a coincidence. - Jeremy S. Anderson."""
 
 
 [Documentation]
-doc: "endb;intern;apis;lib;manual;tut1;tut2;nimrodc;overview;filters;trmacros"
-doc: "tools;niminst;nimgrep;gc;estp;idetools;docgen;koch"
+doc: "endb;intern;apis;lib;manual;tut1;tut2;nimrodc;overview;filters"
+doc: "tools;c2nim;niminst;nimgrep;gc;estp;idetools;docgen;koch;backends.txt"
 pdf: "manual;lib;tut1;tut2;nimrodc;niminst;gc"
 srcdoc2: "system.nim;impure/graphics;wrappers/sdl"
 srcdoc2: "core/macros;pure/marshal;core/typeinfo;core/unsigned"