summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rwxr-xr-xcompiler/ast.nim5
-rwxr-xr-xcompiler/astalgo.nim8
-rwxr-xr-xcompiler/ccgexprs.nim8
-rwxr-xr-xcompiler/ccgstmts.nim9
-rw-r--r--compiler/ccgtrav.nim7
-rwxr-xr-xcompiler/ccgtypes.nim4
-rwxr-xr-xcompiler/cgen.nim8
-rw-r--r--compiler/cgendata.nim2
-rw-r--r--compiler/lambdalifting.nim3
-rwxr-xr-xcompiler/platform.nim14
-rwxr-xr-xcompiler/rodread.nim26
-rw-r--r--compiler/semmagic.nim2
-rwxr-xr-xcompiler/semthreads.nim4
-rwxr-xr-xcompiler/semtypes.nim37
-rwxr-xr-xcompiler/transf.nim8
-rwxr-xr-xcompiler/types.nim4
-rwxr-xr-xdoc/lib.txt4
-rwxr-xr-xkoch.nim2
-rw-r--r--lib/pure/irc.nim6
-rwxr-xr-xlib/pure/sockets.nim87
-rwxr-xr-xlib/system.nim54
-rwxr-xr-xlib/system/ansi_c.nim1
-rw-r--r--lib/system/embedded.nim106
-rwxr-xr-xlib/system/excpt.nim2
-rwxr-xr-xlib/system/mmdisp.nim72
-rwxr-xr-xlib/system/repr.nim3
-rw-r--r--tests/benchmark.nim47
-rw-r--r--tests/benchmarks/fannkuch.nim69
-rw-r--r--tests/benchmarks/quicksort.nim54
-rw-r--r--tests/compile/tglobalforvar.nim7
-rw-r--r--tests/compile/tircbot.nim447
-rwxr-xr-xtests/reject/t99bott.nim2
-rw-r--r--tests/reject/tenumitems.nim2
-rwxr-xr-xtodo.txt5
-rwxr-xr-xweb/index.txt6
-rwxr-xr-xweb/news.txt1
36 files changed, 1017 insertions, 109 deletions
diff --git a/compiler/ast.nim b/compiler/ast.nim
index a9407c91e..897501ee5 100755
--- a/compiler/ast.nim
+++ b/compiler/ast.nim
@@ -227,9 +227,6 @@ type
     sfInnerProc,      # proc is an inner proc
     sfThread,         # proc will run as a thread
                       # variable is a thread variable
-    sfInline          # forced-inline procs
-    sfImmediate,      # macro or template is immediately expanded without
-                      # considering any possible overloads
     sfCompileTime,    # proc can be evaluated at compile time
     sfMerge,          # proc can be merged with itself
     sfDeadCodeElim,   # dead code elimination for the module is turned on
@@ -246,6 +243,8 @@ const
   sfFakeConst* = sfDeadCodeElim  # const cannot be put into a data section
   sfDispatcher* = sfDeadCodeElim # copied method symbol is the dispatcher
   sfNoInit* = sfMainModule       # don't generate code to init the variable
+  sfImmediate* = sfDeadCodeElim  # macro or template is immediately expanded
+                                 # without considering any possible overloads
 
 type
   TTypeKind* = enum  # order is important!
diff --git a/compiler/astalgo.nim b/compiler/astalgo.nim
index 9da0d3a20..861642594 100755
--- a/compiler/astalgo.nim
+++ b/compiler/astalgo.nim
@@ -146,6 +146,14 @@ proc IITablePut*(t: var TIITable, key, val: int)
 
 # implementation
 
+proc skipConv*(n: PNode): PNode = 
+  case n.kind
+  of nkObjUpConv, nkObjDownConv, nkChckRange, nkChckRangeF, nkChckRange64:
+    result = n.sons[0]
+  of nkHiddenStdConv, nkHiddenSubConv, nkConv:
+    result = n.sons[1]
+  else: result = n
+
 proc SameValue*(a, b: PNode): bool = 
   result = false
   case a.kind
diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim
index 81d122859..d03142208 100755
--- a/compiler/ccgexprs.nim
+++ b/compiler/ccgexprs.nim
@@ -139,9 +139,9 @@ proc getStorageLoc(n: PNode): TStorageLoc =
   case n.kind
   of nkSym:
     case n.sym.kind
-    of skParam, skForVar, skTemp:
+    of skParam, skTemp:
       result = OnStack
-    of skVar, skResult, skLet:
+    of skVar, skForVar, skResult, skLet:
       if sfGlobal in n.sym.flags: result = OnHeap
       else: result = OnStack
     of skConst: 
@@ -1652,7 +1652,7 @@ proc expr(p: BProc, e: PNode, d: var TLoc) =
         genComplexConst(p, sym, d)
     of skEnumField:
       putIntoDest(p, d, e.typ, toRope(sym.position))
-    of skVar, skResult, skLet:
+    of skVar, skForVar, skResult, skLet:
       if sfGlobal in sym.flags: genVarPrototype(p.module, sym)
       if sym.loc.r == nil or sym.loc.t == nil:
         InternalError(e.info, "expr: var not init " & sym.name.s)
@@ -1664,7 +1664,7 @@ proc expr(p: BProc, e: PNode, d: var TLoc) =
           putLocIntoDest(p, d, sym.loc)
       else:
         putLocIntoDest(p, d, sym.loc)
-    of skForVar, skTemp:
+    of skTemp:
       if sym.loc.r == nil or sym.loc.t == nil:
         InternalError(e.info, "expr: temp not init " & sym.name.s)
       putLocIntoDest(p, d, sym.loc)
diff --git a/compiler/ccgstmts.nim b/compiler/ccgstmts.nim
index d0112f9d7..9c0d52221 100755
--- a/compiler/ccgstmts.nim
+++ b/compiler/ccgstmts.nim
@@ -23,7 +23,7 @@ proc genVarTuple(p: BProc, n: PNode) =
   for i in countup(0, L-3): 
     var v = n.sons[i].sym
     if sfCompileTime in v.flags: continue
-    if sfGlobal in v.flags and v.kind != skForVar: 
+    if sfGlobal in v.flags:
       assignGlobalVar(p, v)
       genObjectInit(p, cpsInit, v.typ, v.loc, true)
     else:
@@ -49,7 +49,7 @@ proc genSingleVar(p: BProc, a: PNode) =
   var v = a.sons[0].sym
   if sfCompileTime in v.flags: return
   var immediateAsgn = a.sons[2].kind != nkEmpty
-  if sfGlobal in v.flags and v.kind != skForVar: 
+  if sfGlobal in v.flags:
     assignGlobalVar(p, v)
     genObjectInit(p, cpsInit, v.typ, v.loc, true)
   else:
@@ -725,7 +725,10 @@ proc genStmts(p: BProc, t: PNode) =
     genLineDir(p, t)
     initLocExpr(p, t, a)
   of nkAsgn: genAsgn(p, t, fastAsgn=false)
-  of nkFastAsgn: genAsgn(p, t, fastAsgn=true)
+  of nkFastAsgn: 
+    # transf is overly aggressive with 'nkFastAsgn', so we work around here.
+    # See tests/run/tcnstseq3 for an example that would fail otherwise.
+    genAsgn(p, t, fastAsgn=p.prc != nil)
   of nkDiscardStmt: 
     genLineDir(p, t)
     initLocExpr(p, t.sons[0], a)
diff --git a/compiler/ccgtrav.nim b/compiler/ccgtrav.nim
index 995ed2973..8aaf5370f 100644
--- a/compiler/ccgtrav.nim
+++ b/compiler/ccgtrav.nim
@@ -70,6 +70,7 @@ proc genTraverseProc(c: var TTraversalClosure, accessor: PRope, typ: PType) =
       genTraverseProc(c, accessor.parentObj, typ.sons[i])
     if typ.n != nil: genTraverseProc(c, accessor, typ.n)
   of tyTuple:
+    let typ = GetUniqueType(typ)
     if typ.n != nil:
       genTraverseProc(c, accessor, typ.n)
     else:
@@ -110,7 +111,11 @@ proc genTraverseProc(m: BModule, typ: PType, reason: TTypeInfoReason): PRope =
   if typ.kind == tySequence:
     genTraverseProcSeq(c, "a".toRope, typ)
   else:
-    genTraverseProc(c, "(*a)".toRope, typ.sons[0])
+    if skipTypes(typ.sons[0], abstractInst).kind in {tyArrayConstr, tyArray}:
+      # C's arrays are broken beyond repair:
+      genTraverseProc(c, "a".toRope, typ.sons[0])
+    else:
+      genTraverseProc(c, "(*a)".toRope, typ.sons[0])
   
   let generatedProc = ropef("$1 {$n$2$3$4}$n",
         [header, p.s[cpsLocals], p.s[cpsInit], p.s[cpsStmts]])
diff --git a/compiler/ccgtypes.nim b/compiler/ccgtypes.nim
index 78b02c691..6195ff2f4 100755
--- a/compiler/ccgtypes.nim
+++ b/compiler/ccgtypes.nim
@@ -39,10 +39,10 @@ proc mangleName(s: PSym): PRope =
       case s.kind
       of skProc, skMethod, skConverter, skConst: 
         result = toRope("@")
-      of skVar, skResult, skLet: 
+      of skVar, skForVar, skResult, skLet: 
         if sfGlobal in s.flags: result = toRope("@")
         else: result = toRope("%")
-      of skForVar, skTemp, skParam, skType, skEnumField, skModule: 
+      of skTemp, skParam, skType, skEnumField, skModule: 
         result = toRope("%")
       else: InternalError(s.info, "mangleName")
     app(result, toRope(mangle(s.name.s)))
diff --git a/compiler/cgen.nim b/compiler/cgen.nim
index 0c1d721c0..a56053f79 100755
--- a/compiler/cgen.nim
+++ b/compiler/cgen.nim
@@ -779,6 +779,9 @@ proc genMainProc(m: BModule) =
     PosixCMain = "int main(int argc, char** args, char** env) {$n" &
         "  cmdLine = args;$n" & "  cmdCount = argc;$n" & "  gEnv = env;$n" &
         "  NimMain();$n" & "  return nim_program_result;$n" & "}$n"
+    StandaloneCMain = "int main(void) {$n" &
+        "  NimMain();$n" & 
+        "  return 0;$n" & "}$n"
     WinNimMain = "N_CDECL(void, NimMain)(void) {$n" &
         CommonMainBody & "}$n"
     WinCMain = "N_STDCALL(int, WinMain)(HINSTANCE hCurInstance, $n" &
@@ -808,7 +811,10 @@ proc genMainProc(m: BModule) =
   elif optGenDynLib in gGlobalOptions:
     nimMain = posixNimDllMain
     otherMain = posixCDllMain
-  else: 
+  elif platform.targetOS == osStandalone:
+    nimMain = PosixNimMain
+    otherMain = StandaloneCMain
+  else:
     nimMain = PosixNimMain
     otherMain = PosixCMain
   if gBreakpoints != nil: discard cgsym(m, "dbgRegisterBreakpoint")
diff --git a/compiler/cgendata.nim b/compiler/cgendata.nim
index d93c107ac..c58c64250 100644
--- a/compiler/cgendata.nim
+++ b/compiler/cgendata.nim
@@ -36,7 +36,7 @@ type
     cfsDynLibInit,            # section for init of dynamic library binding
     cfsDynLibDeinit           # section for deinitialization of dynamic
                               # libraries
-  TCTypeKind* = enum           # describes the type kind of a C type
+  TCTypeKind* = enum          # describes the type kind of a C type
     ctVoid, ctChar, ctBool, ctUInt, ctUInt8, ctUInt16, ctUInt32, ctUInt64, 
     ctInt, ctInt8, ctInt16, ctInt32, ctInt64, ctFloat, ctFloat32, ctFloat64, 
     ctFloat128, ctArray, ctStruct, ctPtr, ctNimStr, ctNimSeq, ctProc, ctCString
diff --git a/compiler/lambdalifting.nim b/compiler/lambdalifting.nim
index a22252a30..dc6469563 100644
--- a/compiler/lambdalifting.nim
+++ b/compiler/lambdalifting.nim
@@ -11,8 +11,7 @@
 # included from transf.nim
 
 const
-  declarativeDefs = {nkProcDef, nkMethodDef, nkIteratorDef,
-     nkConverterDef}
+  declarativeDefs = {nkProcDef, nkMethodDef, nkIteratorDef, nkConverterDef}
   procDefs = nkLambdaKinds + declarativeDefs
 
 proc indirectAccess(a, b: PSym, info: TLineInfo): PNode = 
diff --git a/compiler/platform.nim b/compiler/platform.nim
index 01190c9c9..f4cf3b882 100755
--- a/compiler/platform.nim
+++ b/compiler/platform.nim
@@ -21,7 +21,8 @@ type
                     # conditionals to condsyms (end of module).
     osNone, osDos, osWindows, osOs2, osLinux, osMorphos, osSkyos, osSolaris, 
     osIrix, osNetbsd, osFreebsd, osOpenbsd, osAix, osPalmos, osQnx, osAmiga, 
-    osAtari, osNetware, osMacos, osMacosx, osEcmaScript, osNimrodVM
+    osAtari, osNetware, osMacos, osMacosx, osEcmaScript, osNimrodVM, 
+    osStandalone
 
 type 
   TInfoOSProp* = enum 
@@ -139,14 +140,18 @@ const
       exeExt: "", extSep: ".", props: {}), 
      (name: "NimrodVM", parDir: "..", dllFrmt: "lib$1.so", altDirSep: "/", 
       objExt: ".o", newLine: "\x0A", pathSep: ":", dirSep: "/", 
-      scriptExt: ".sh", curDir: ".", exeExt: "", extSep: ".", props: {})]
+      scriptExt: ".sh", curDir: ".", exeExt: "", extSep: ".", props: {}),
+     (name: "Standalone", parDir: "..", dllFrmt: "lib$1.so", altDirSep: "/",
+      objExt: ".o", newLine: "\x0A", pathSep: ":", dirSep: "/",
+      scriptExt: ".sh", curDir: ".", exeExt: ".elf", extSep: ".", 
+      props: {})]
 
 type 
   TSystemCPU* = enum # Also add CPU for in initialization section and 
                      # alias conditionals to condsyms (end of module).
     cpuNone, cpuI386, cpuM68k, cpuAlpha, cpuPowerpc, cpuPowerpc64,
     cpuSparc, cpuVm, cpuIa64, cpuAmd64, cpuMips, cpuArm, 
-    cpuEcmaScript, cpuNimrodVM
+    cpuEcmaScript, cpuNimrodVM, cpuAVR
 
 type 
   TEndian* = enum 
@@ -169,7 +174,8 @@ const
     (name: "mips", intSize: 32, endian: bigEndian, floatSize: 64, bit: 32), 
     (name: "arm", intSize: 32, endian: littleEndian, floatSize: 64, bit: 32), 
     (name: "ecmascript", intSize: 32, endian: bigEndian,floatSize: 64,bit: 32), 
-    (name: "nimrodvm", intSize: 32, endian: bigEndian, floatSize: 64, bit: 32)]
+    (name: "nimrodvm", intSize: 32, endian: bigEndian, floatSize: 64, bit: 32),
+    (name: "avr", intSize: 16, endian: littleEndian, floatSize: 32, bit: 16)]
 
 var 
   targetCPU*, hostCPU*: TSystemCPU
diff --git a/compiler/rodread.nim b/compiler/rodread.nim
index 3385ce942..c3123161b 100755
--- a/compiler/rodread.nim
+++ b/compiler/rodread.nim
@@ -535,7 +535,7 @@ proc cmdChangeTriggersRecompilation(old, new: TCommands): bool =
 proc processRodFile(r: PRodReader, crc: TCrc32) = 
   var 
     w: string
-    d, L, inclCrc: int
+    d, inclCrc: int
   while r.s[r.pos] != '\0': 
     var section = rdWord(r)
     if r.reason != rrNone: 
@@ -573,20 +573,17 @@ proc processRodFile(r: PRodReader, crc: TCrc32) =
     of "FILES": 
       inc(r.pos, 2)           # skip "(\10"
       inc(r.line)
-      L = 0
-      while r.s[r.pos] > '\x0A' and r.s[r.pos] != ')': 
-        setlen(r.files, L + 1)
+      while r.s[r.pos] != ')':
         var relativePath = decodeStr(r.s, r.pos)
         var resolvedPath = relativePath.findModule
-        r.files[L] = if resolvedPath.len > 0: resolvedPath else: relativePath
+        r.files.add(if resolvedPath.len > 0: resolvedPath else: relativePath)
         inc(r.pos)            # skip #10
         inc(r.line)
-        inc(L)
       if r.s[r.pos] == ')': inc(r.pos)
     of "INCLUDES": 
       inc(r.pos, 2)           # skip "(\10"
       inc(r.line)
-      while r.s[r.pos] > '\x0A' and r.s[r.pos] != ')': 
+      while r.s[r.pos] != ')': 
         w = r.files[decodeVInt(r.s, r.pos)]
         inc(r.pos)            # skip ' '
         inclCrc = decodeVInt(r.s, r.pos)
@@ -597,13 +594,10 @@ proc processRodFile(r: PRodReader, crc: TCrc32) =
           inc(r.pos)
           inc(r.line)
       if r.s[r.pos] == ')': inc(r.pos)
-    of "DEPS": 
+    of "DEPS":
       inc(r.pos)              # skip ':'
-      L = 0
       while r.s[r.pos] > '\x0A': 
-        setlen(r.modDeps, L + 1)
-        r.modDeps[L] = r.files[decodeVInt(r.s, r.pos)]
-        inc(L)
+        r.modDeps.add r.files[decodeVInt(r.s, r.pos)]
         if r.s[r.pos] == ' ': inc(r.pos)
     of "INTERF": 
       r.interfIdx = r.pos + 2
@@ -629,9 +623,11 @@ proc processRodFile(r: PRodReader, crc: TCrc32) =
     of "INIT": 
       r.initIdx = r.pos + 2   # "(\10"
       skipSection(r)
-    else: 
-      MsgWriteln("skipping section: " & section &
-                 " at " & $r.pos & " in " & r.filename)
+    else:
+      InternalError("invalid section: '" & section &
+                    "' at " & $r.line & " in " & r.filename)
+      #MsgWriteln("skipping section: " & section &
+      #           " at " & $r.line & " in " & r.filename)
       skipSection(r)
     if r.s[r.pos] == '\x0A': 
       inc(r.pos)
diff --git a/compiler/semmagic.nim b/compiler/semmagic.nim
index 932f36c2f..4f120e2ab 100644
--- a/compiler/semmagic.nim
+++ b/compiler/semmagic.nim
@@ -22,7 +22,7 @@ proc semSlurp(c: PContext, n: PNode, flags: TExprFlags): PNode =
     result = newStrNode(nkStrLit, content)
     result.typ = getSysType(tyString)
     result.info = n.info
-    c.slurpedFiles.add(filename)
+    c.slurpedFiles.add(a.strVal)
   except EIO:
     GlobalError(a.info, errCannotOpenFile, a.strVal)
 
diff --git a/compiler/semthreads.nim b/compiler/semthreads.nim
index 1295723cf..09668a912 100755
--- a/compiler/semthreads.nim
+++ b/compiler/semthreads.nim
@@ -107,14 +107,14 @@ proc analyseSym(c: PProcCtx, n: PNode): TThreadOwner =
   result = c.mapping[v.id]
   if result != toUndefined: return
   case v.kind
-  of skVar, skLet, skResult:
+  of skVar, skForVar, skLet, skResult:
     result = toNil
     if sfGlobal in v.flags:
       if sfThread in v.flags: 
         result = toMine 
       elif containsGarbageCollectedRef(v.typ):
         result = toTheirs
-  of skTemp, skForVar: result = toNil
+  of skTemp: result = toNil
   of skConst: result = toMine
   of skParam: 
     result = c.mapping[v.id]
diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim
index 40176ad50..38cf19406 100755
--- a/compiler/semtypes.nim
+++ b/compiler/semtypes.nim
@@ -251,43 +251,38 @@ proc semIdentWithPragma(c: PContext, kind: TSymKind, n: PNode,
     result = semIdentVis(c, kind, n, allowed)
   
 proc checkForOverlap(c: PContext, t, ex: PNode, branchIndex: int) = 
+  let ex = ex.skipConv
   for i in countup(1, branchIndex - 1): 
     for j in countup(0, sonsLen(t.sons[i]) - 2): 
-      if overlap(t.sons[i].sons[j], ex): 
+      if overlap(t.sons[i].sons[j].skipConv, ex): 
         LocalError(ex.info, errDuplicateCaseLabel)
   
-proc semBranchExpr(c: PContext, t, e: PNode): PNode =
-  result = semConstExpr(c, e)
+proc semBranchRange(c: PContext, t, a, b: PNode, covered: var biggestInt): PNode =
   checkMinSonsLen(t, 1)
-  result = fitNode(c, t.sons[0].typ, result)
-  #if cmpTypes(t.sons[0].typ, result.typ) <= isConvertible: 
-  #  typeMismatch(result, t.sons[0].typ, result.typ)
+  let ac = semConstExpr(c, a)
+  let bc = semConstExpr(c, b)
+  let at = fitNode(c, t.sons[0].typ, ac)
+  let bt = fitNode(c, t.sons[0].typ, bc)
+  
+  result = newNodeI(nkRange, a.info)
+  result.add(at)
+  result.add(bt)
+  if emptyRange(ac, bc): GlobalError(b.info, errRangeIsEmpty)
+  covered = covered + getOrdValue(bc) - getOrdValue(ac) + 1
 
 proc SemCaseBranchRange(c: PContext, t, b: PNode, 
                         covered: var biggestInt): PNode = 
   checkSonsLen(b, 3)
-  result = newNodeI(nkRange, b.info)
-  result.add(semBranchExpr(c, t, b.sons[1]))
-  result.add(semBranchExpr(c, t, b.sons[2]))
-  if emptyRange(result[0], result[1]): GlobalError(b.info, errRangeIsEmpty)
-  covered = covered + getOrdValue(result[1]) - getOrdValue(result[0]) + 1
+  result = semBranchRange(c, t, b.sons[1], b.sons[2], covered)
 
 proc semCaseBranchSetElem(c: PContext, t, b: PNode, 
                           covered: var biggestInt): PNode = 
   if isRange(b):
     checkSonsLen(b, 3)
-    result = newNodeI(nkRange, b.info)
-    result.add(semBranchExpr(c, t, b.sons[1]))
-    result.add(semBranchExpr(c, t, b.sons[2]))
-    if emptyRange(result[0], result[1]): GlobalError(b.info, errRangeIsEmpty)
-    covered = covered + getOrdValue(result[1]) - getOrdValue(result[0]) + 1
+    result = semBranchRange(c, t, b.sons[1], b.sons[2], covered)
   elif b.kind == nkRange:
     checkSonsLen(b, 2)
-    result = newNodeI(nkRange, b.info)
-    result.add(semBranchExpr(c, t, b.sons[0]))
-    result.add(semBranchExpr(c, t, b.sons[1]))
-    if emptyRange(result[0], result[1]): GlobalError(b.info, errRangeIsEmpty)
-    covered = covered + getOrdValue(result[1]) - getOrdValue(result[0]) + 1
+    result = semBranchRange(c, t, b.sons[0], b.sons[1], covered)
   else:
     result = fitNode(c, t.sons[0].typ, b)
     inc(covered)
diff --git a/compiler/transf.nim b/compiler/transf.nim
index 3c685eeb4..ff42ff592 100755
--- a/compiler/transf.nim
+++ b/compiler/transf.nim
@@ -267,14 +267,6 @@ proc transformLoopBody(c: PTransf, n: PNode): PTransNode =
     discard c.blockSyms.pop()
   else: 
     result = transform(c, n)
-
-proc skipConv(n: PNode): PNode = 
-  case n.kind
-  of nkObjUpConv, nkObjDownConv, nkChckRange, nkChckRangeF, nkChckRange64:
-    result = n.sons[0]
-  of nkHiddenStdConv, nkHiddenSubConv, nkConv:
-    result = n.sons[1]
-  else: result = n
   
 proc newTupleAccess(tup: PNode, i: int): PNode = 
   result = newNodeIT(nkBracketExpr, tup.info, tup.typ.sons[i])
diff --git a/compiler/types.nim b/compiler/types.nim
index 6b25a388f..3f7c2c820 100755
--- a/compiler/types.nim
+++ b/compiler/types.nim
@@ -869,9 +869,11 @@ proc typeAllowedAux(marker: var TIntSet, typ: PType, kind: TSymKind): bool =
   of tyArray:
     result = t.sons[1].kind == tyEmpty or
         typeAllowedAux(marker, t.sons[1], skVar)
-  of tyPtr, tyRef:
+  of tyRef:
     if kind == skConst: return false
     result = typeAllowedAux(marker, t.sons[0], skVar)
+  of tyPtr:
+    result = typeAllowedAux(marker, t.sons[0], skVar)
   of tyArrayConstr, tyTuple, tySet, tyConst, tyMutable, tyIter, tyProxy: 
     for i in countup(0, sonsLen(t) - 1): 
       result = typeAllowedAux(marker, t.sons[i], kind)
diff --git a/doc/lib.txt b/doc/lib.txt
index acdee3447..65f5d81ed 100755
--- a/doc/lib.txt
+++ b/doc/lib.txt
@@ -255,6 +255,10 @@ XML Processing
 * `htmlparser <htmlparser.html>`_
   This module parses an HTML document and creates its XML tree representation.
 
+* `htmlgen <htmlgen.html>`_
+  This module implements a simple XML and HTML code 
+  generator. Each commonly used HTML tag has a corresponding macro
+  that generates a string with its HTML representation.
 
 Cryptography and Hashing
 ------------------------
diff --git a/koch.nim b/koch.nim
index add08625a..9eec6bd76 100755
--- a/koch.nim
+++ b/koch.nim
@@ -141,7 +141,7 @@ proc boot(args: string) =
       return
     copyExe(output, (i+1).thVersion)
   copyExe(output, finalDest)
-  echo "[Warning] executables are still not equal"
+  when not defined(windows): echo "[Warning] executables are still not equal"
 
 # -------------- clean --------------------------------------------------------
 
diff --git a/lib/pure/irc.nim b/lib/pure/irc.nim
index 8946a9d8f..81dff024e 100644
--- a/lib/pure/irc.nim
+++ b/lib/pure/irc.nim
@@ -142,6 +142,8 @@ proc parseMessage(msg: string): TIRCEvent =
     inc(i) # Skip `:`
     var nick = ""
     i.inc msg.parseUntil(nick, {'!', ' '}, i)
+    result.nick = ""
+    result.serverName = ""
     if msg[i] == '!':
       result.nick = nick
       inc(i) # Skip `!`
@@ -237,7 +239,8 @@ proc processLine(irc: var TIRC, line: string): TIRCEvent =
     result = parseMessage(line)
     # Get the origin
     result.origin = result.params[0]
-    if result.origin == irc.nick: result.origin = result.nick
+    if result.origin == irc.nick and
+       result.nick != "": result.origin = result.nick
 
     if result.cmd == MError:
       irc.close()
@@ -386,6 +389,7 @@ proc asyncIRC*(address: string, port: TPort = 6667.TPort,
   result.messageBuffer = @[]
   result.handleEvent = ircEvent
   result.userArg = userArg
+  result.lineBuffer = ""
 
 proc register*(d: PDispatcher, irc: PAsyncIRC) =
   ## Registers ``irc`` with dispatcher ``d``.
diff --git a/lib/pure/sockets.nim b/lib/pure/sockets.nim
index 5721d79fe..31973c6ce 100755
--- a/lib/pure/sockets.nim
+++ b/lib/pure/sockets.nim
@@ -8,8 +8,12 @@
 #
 
 ## This module implements a simple portable type-safe sockets layer.
+##
+## Most procedures raise EOS on error.
+
 
 import os, parseutils
+from times import epochTime
 
 when defined(Windows):
   import winlean
@@ -59,6 +63,8 @@ type
   TRecvLineResult* = enum ## result for recvLineAsync
     RecvFullLine, RecvPartialLine, RecvDisconnected, RecvFail
 
+  ETimeout* = object of ESynch
+
 const
   InvalidSocket* = TSocket(-1'i32) ## invalid socket number
 
@@ -377,12 +383,14 @@ proc connect*(socket: TSocket, name: string, port = TPort(0),
   ## host name. If ``name`` is a host name, this function will try each IP
   ## of that host name. ``htons`` is already performed on ``port`` so you must
   ## not do it.
+  
   var hints: TAddrInfo
   var aiList: ptr TAddrInfo = nil
   hints.ai_family = toInt(af)
   hints.ai_socktype = toInt(SOCK_STREAM)
   hints.ai_protocol = toInt(IPPROTO_TCP)
   gaiNim(name, port, hints, aiList)
+  
   # try all possibilities:
   var success = false
   var it = aiList
@@ -445,7 +453,6 @@ proc connectAsync*(socket: TSocket, name: string, port = TPort(0),
   freeaddrinfo(aiList)
   if not success: OSError()
 
-
 proc timeValFromMilliseconds(timeout = 500): TTimeVal =
   if timeout != -1:
     var seconds = timeout div 1000
@@ -545,7 +552,33 @@ proc select*(readfds: var seq[TSocket], timeout = 500): int =
     result = int(select(cint(m+1), addr(rd), nil, nil, nil))
   
   pruneSocketSet(readfds, (rd))
+  
+proc recv*(socket: TSocket, data: pointer, size: int): int =
+  ## receives data from a socket
+  result = recv(cint(socket), data, size, 0'i32)
 
+template waitFor(): stmt =
+  if timeout - int(waited * 1000.0) < 1:
+    raise newException(ETimeout, "Call to recv() timed out.")
+  var s = @[socket]
+  var startTime = epochTime()
+  if select(s, timeout - int(waited * 1000.0)) != 1:
+    raise newException(ETimeout, "Call to recv() timed out.")
+  waited += (epochTime() - startTime)
+
+proc recv*(socket: TSocket, data: var string, size: int, timeout: int): int =
+  ## overload with a ``timeout`` parameter in miliseconds.
+  var waited = 0.0 # number of seconds already waited  
+  
+  var read = 0
+  while read < size:
+    waitFor()
+    result = recv(cint(socket), addr(data[read]), 1, 0'i32)
+    if result < 0:
+      return
+    inc(read)
+  
+  result = read
 
 proc recvLine*(socket: TSocket, line: var TaintedString): bool =
   ## returns false if no further data is available. `Line` must be initialized
@@ -567,6 +600,29 @@ proc recvLine*(socket: TSocket, line: var TaintedString): bool =
     elif c == '\L': return true
     add(line.string, c)
 
+proc recvLine*(socket: TSocket, line: var TaintedString, timeout: int): bool =
+  ## variant with a ``timeout`` parameter, the timeout parameter specifies
+  ## how many miliseconds to wait for data.
+  
+  var waited = 0.0 # number of seconds already waited
+  
+  setLen(line.string, 0)
+  while true:
+    var c: char
+    waitFor()
+    var n = recv(cint(socket), addr(c), 1, 0'i32)
+    if n < 0: return
+    elif n == 0: return true
+    if c == '\r':
+      waitFor()
+      n = recv(cint(socket), addr(c), 1, MSG_PEEK)
+      if n > 0 and c == '\L':
+        discard recv(cint(socket), addr(c), 1, 0'i32)
+      elif n <= 0: return false
+      return true
+    elif c == '\L': return true
+    add(line.string, c)
+
 proc recvLineAsync*(socket: TSocket, line: var TaintedString): TRecvLineResult =
   ## similar to ``recvLine`` but for non-blocking sockets.
   ## The values of the returned enum should be pretty self explanatory:
@@ -592,10 +648,6 @@ proc recvLineAsync*(socket: TSocket, line: var TaintedString): TRecvLineResult =
     elif c == '\L': return RecvFullLine
     add(line.string, c)
 
-proc recv*(socket: TSocket, data: pointer, size: int): int =
-  ## receives data from a socket
-  result = recv(cint(socket), data, size, 0'i32)
-
 proc recv*(socket: TSocket): TaintedString =
   ## receives all the data from the socket.
   ## Socket errors will result in an ``EOS`` error.
@@ -625,6 +677,16 @@ proc recv*(socket: TSocket): TaintedString =
       add(result.string, buf)
       if bytesRead != bufSize-1: break
 
+proc recvTimeout*(socket: TSocket, timeout: int): TaintedString =
+  ## overloaded variant to support a ``timeout`` parameter, the ``timeout``
+  ## parameter specifies the amount of miliseconds to wait for data on the
+  ## socket.
+  var s = @[socket]
+  if s.select(timeout) != 1:
+    raise newException(ETimeout, "Call to recv() timed out.")
+  
+  return socket.recv
+
 proc recvAsync*(socket: TSocket, s: var TaintedString): bool =
   ## receives all the data from a non-blocking socket. If socket is non-blocking 
   ## and there are no messages available, `False` will be returned.
@@ -723,6 +785,21 @@ proc setBlocking*(s: TSocket, blocking: bool) =
       if fcntl(cint(s), F_SETFL, mode) == -1:
         OSError()
 
+proc connect*(socket: TSocket, timeout: int, name: string, port = TPort(0),
+             af: TDomain = AF_INET) =
+  ## Overload for ``connect`` to support timeouts. The ``timeout`` parameter 
+  ## specifies the time in miliseconds of how long to wait for a connection
+  ## to be made.
+  ##
+  ## **Warning:** If ``socket`` is non-blocking and timeout is not ``-1`` then
+  ## this function may set blocking mode on ``socket`` to true.
+  socket.setBlocking(true)
+  
+  socket.connectAsync(name, port, af)
+  var s: seq[TSocket] = @[socket]
+  if selectWrite(s, timeout) != 1:
+    raise newException(ETimeout, "Call to connect() timed out.")
+
 when defined(Windows):
   var wsa: TWSADATA
   if WSAStartup(0x0101'i16, wsa) != 0: OSError()
diff --git a/lib/system.nim b/lib/system.nim
index e1b82b6bb..78912be7e 100755
--- a/lib/system.nim
+++ b/lib/system.nim
@@ -851,7 +851,7 @@ template sysAssert(cond: bool, msg: string) =
 
 include "system/inclrtl"
 
-when not defined(ecmascript) and not defined(nimrodVm):
+when not defined(ecmascript) and not defined(nimrodVm) and not defined(avr):
   include "system/cgprocs"
 
 proc add *[T](x: var seq[T], y: T) {.magic: "AppendSeqElem", noSideEffect.}
@@ -1604,16 +1604,17 @@ when not defined(EcmaScript) and not defined(NimrodVM):
   {.push stack_trace: off.}
 
   proc initGC()
-  when not defined(boehmgc):
+  when not defined(boehmgc) and not defined(useMalloc):
     proc initAllocator() {.inline.}
 
-  proc initStackBottom() {.inline.} = 
-    # WARNING: This is very fragile! An array size of 8 does not work on my
-    # Linux 64bit system. Very strange, but we are at the will of GCC's 
-    # optimizer...
-    var locals {.volatile.}: pointer
-    locals = addr(locals)
-    setStackBottom(locals)
+  when not defined(nogc):
+    proc initStackBottom() {.inline.} = 
+      # WARNING: This is very fragile! An array size of 8 does not work on my
+      # Linux 64bit system. Very strange, but we are at the will of GCC's 
+      # optimizer...
+      var locals {.volatile.}: pointer
+      locals = addr(locals)
+      setStackBottom(locals)
 
   var
     strDesc: TNimType
@@ -1868,7 +1869,7 @@ when not defined(EcmaScript) and not defined(NimrodVM):
   when hasThreadSupport:
     include "system/syslocks"
     include "system/threads"
-  else:
+  elif not defined(nogc):
     initStackBottom()
     initGC()
 
@@ -1881,21 +1882,23 @@ when not defined(EcmaScript) and not defined(NimrodVM):
     ## for debug builds.
     
   {.push stack_trace: off.}
-  include "system/excpt"
+  when hostCPU == "avr":
+    include "system/embedded"
+  else:
+    include "system/excpt"
+    
   # we cannot compile this with stack tracing on
   # as it would recurse endlessly!
   include "system/arithm"
   {.pop.} # stack trace
   {.pop.} # stack trace
       
-  include "system/dyncalls"
+  when hostOS != "standalone": include "system/dyncalls"
   include "system/sets"
 
   const
     GenericSeqSize = (2 * sizeof(int))
     
-  proc reprAny(p: pointer, typ: PNimType): string {.compilerRtl.}
-
   proc getDiscriminant(aa: Pointer, n: ptr TNimNode): int =
     sysAssert(n.kind == nkCase, "getDiscriminant: node != nkCase")
     var d: int
@@ -1918,7 +1921,7 @@ when not defined(EcmaScript) and not defined(NimrodVM):
 
   include "system/mmdisp"
   {.push stack_trace: off.}
-  include "system/sysstr"
+  when hostCPU != "avr": include "system/sysstr"
   {.pop.}
 
   include "system/sysio"
@@ -1938,18 +1941,19 @@ when not defined(EcmaScript) and not defined(NimrodVM):
     var res = TaintedString(newStringOfCap(80))
     while f.readLine(res): yield TaintedString(res)
 
-  include "system/assign"
-  include "system/repr"
+  when hostCPU != "avr":
+    include "system/assign"
+    include "system/repr"
 
-  proc getCurrentException*(): ref E_Base {.compilerRtl, inl.} =
-    ## retrieves the current exception; if there is none, nil is returned.
-    result = currException
+    proc getCurrentException*(): ref E_Base {.compilerRtl, inl.} =
+      ## retrieves the current exception; if there is none, nil is returned.
+      result = currException
 
-  proc getCurrentExceptionMsg*(): string {.inline.} =
-    ## retrieves the error message that was attached to the current
-    ## exception; if there is none, "" is returned.
-    var e = getCurrentException()
-    return if e == nil: "" else: e.msg
+    proc getCurrentExceptionMsg*(): string {.inline.} =
+      ## retrieves the error message that was attached to the current
+      ## exception; if there is none, "" is returned.
+      var e = getCurrentException()
+      return if e == nil: "" else: e.msg
 
   {.push stack_trace: off.}
   when defined(endb):
diff --git a/lib/system/ansi_c.nim b/lib/system/ansi_c.nim
index 9722e1396..e328f7099 100755
--- a/lib/system/ansi_c.nim
+++ b/lib/system/ansi_c.nim
@@ -103,4 +103,3 @@ proc c_getenv(env: CString): CString {.importc: "getenv", noDecl.}
 proc c_putenv(env: CString): cint {.importc: "putenv", noDecl.}
 
 {.pop}
-
diff --git a/lib/system/embedded.nim b/lib/system/embedded.nim
new file mode 100644
index 000000000..f17432561
--- /dev/null
+++ b/lib/system/embedded.nim
@@ -0,0 +1,106 @@
+#
+#
+#            Nimrod's Runtime Library
+#        (c) Copyright 2012 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+
+# Bare-bones implementation of some things for embedded targets.
+
+proc writeToStdErr(msg: CString) = write(stdout, msg)
+
+proc chckIndx(i, a, b: int): int {.inline, compilerproc.}
+proc chckRange(i, a, b: int): int {.inline, compilerproc.}
+proc chckRangeF(x, a, b: float): float {.inline, compilerproc.}
+proc chckNil(p: pointer) {.inline, compilerproc.}
+
+proc pushFrame(s: PFrame) {.compilerRtl, inl.} = nil
+proc popFrame {.compilerRtl, inl.} = nil
+
+proc setFrame(s: PFrame) {.compilerRtl, inl.} = nil
+proc pushSafePoint(s: PSafePoint) {.compilerRtl, inl.} = nil
+proc popSafePoint {.compilerRtl, inl.} = nil
+proc pushCurrentException(e: ref E_Base) {.compilerRtl, inl.} = nil
+proc popCurrentException {.compilerRtl, inl.} = nil
+
+# some platforms have native support for stack traces:
+const
+  nativeStackTraceSupported = false
+  hasSomeStackTrace = false
+
+proc quitOrDebug() {.inline.} =
+  quit(1)
+
+proc raiseException(e: ref E_Base, ename: CString) {.compilerRtl.} =
+  writeToStdErr(ename)
+ 
+proc reraiseException() {.compilerRtl.} =
+  writeToStdErr("reraise not supported")
+
+proc WriteStackTrace() = nil
+
+proc setControlCHook(hook: proc () {.noconv.}) =
+  # ugly cast, but should work on all architectures:
+  type TSignalHandler = proc (sig: cint) {.noconv.}
+  c_signal(SIGINT, cast[TSignalHandler](hook))
+
+proc raiseRangeError(val: biggestInt) {.compilerproc, noreturn, noinline.} =
+  writeToStdErr("value out of range")
+
+proc raiseIndexError() {.compilerproc, noreturn, noinline.} =
+  writeToStdErr("index out of bounds")
+
+proc raiseFieldError(f: string) {.compilerproc, noreturn, noinline.} =
+  writeToStdErr("field is not accessible")
+
+proc chckIndx(i, a, b: int): int =
+  if i >= a and i <= b:
+    return i
+  else:
+    raiseIndexError()
+
+proc chckRange(i, a, b: int): int =
+  if i >= a and i <= b:
+    return i
+  else:
+    raiseRangeError(i)
+
+proc chckRange64(i, a, b: int64): int64 {.compilerproc.} =
+  if i >= a and i <= b:
+    return i
+  else:
+    raiseRangeError(i)
+
+proc chckRangeF(x, a, b: float): float =
+  if x >= a and x <= b:
+    return x
+  else:
+    raise newException(EOutOfRange, "value " & $x & " out of range")
+
+proc chckNil(p: pointer) =
+  if p == nil: c_raise(SIGSEGV)
+
+proc chckObj(obj, subclass: PNimType) {.compilerproc.} =
+  # checks if obj is of type subclass:
+  var x = obj
+  if x == subclass: return # optimized fast path
+  while x != subclass:
+    if x == nil:
+      raise newException(EInvalidObjectConversion, "invalid object conversion")
+    x = x.base
+
+proc chckObjAsgn(a, b: PNimType) {.compilerproc, inline.} =
+  if a != b:
+    raise newException(EInvalidObjectAssignment, "invalid object assignment")
+
+proc isObj(obj, subclass: PNimType): bool {.compilerproc.} =
+  # checks if obj is of type subclass:
+  var x = obj
+  if x == subclass: return true # optimized fast path
+  while x != subclass:
+    if x == nil: return false
+    x = x.base
+  return true
diff --git a/lib/system/excpt.nim b/lib/system/excpt.nim
index 8ffca90fb..2df7fe4ad 100755
--- a/lib/system/excpt.nim
+++ b/lib/system/excpt.nim
@@ -27,7 +27,7 @@ else:
   proc writeToStdErr(msg: CString) =
     discard MessageBoxA(0, msg, nil, 0)
 
-proc registerSignalHandler() {.compilerproc.}
+proc registerSignalHandler()
 
 proc chckIndx(i, a, b: int): int {.inline, compilerproc.}
 proc chckRange(i, a, b: int): int {.inline, compilerproc.}
diff --git a/lib/system/mmdisp.nim b/lib/system/mmdisp.nim
index e8ad23970..1abf3fbbf 100755
--- a/lib/system/mmdisp.nim
+++ b/lib/system/mmdisp.nim
@@ -181,6 +181,78 @@ when defined(boehmgc):
   proc deallocOsPages() {.inline.} = nil
 
   include "system/cellsets"
+elif defined(nogc) and defined(useMalloc):
+  
+  when not defined(useNimRtl):
+    proc alloc(size: int): pointer =
+      result = cmalloc(size)
+      if result == nil: raiseOutOfMem()
+    proc alloc0(size: int): pointer =
+      result = alloc(size)
+      zeroMem(result, size)
+    proc realloc(p: Pointer, newsize: int): pointer =
+      result = crealloc(p, newsize)
+      if result == nil: raiseOutOfMem()
+    proc dealloc(p: Pointer) = cfree(p)
+    
+    proc allocShared(size: int): pointer =
+      result = cmalloc(size)
+      if result == nil: raiseOutOfMem()
+    proc allocShared0(size: int): pointer =
+      result = alloc(size)
+      zeroMem(result, size)
+    proc reallocShared(p: Pointer, newsize: int): pointer =
+      result = crealloc(p, newsize)
+      if result == nil: raiseOutOfMem()
+    proc deallocShared(p: Pointer) = cfree(p)
+
+    proc GC_disable() = nil
+    proc GC_enable() = nil
+    proc GC_fullCollect() = nil
+    proc GC_setStrategy(strategy: TGC_Strategy) = nil
+    proc GC_enableMarkAndSweep() = nil
+    proc GC_disableMarkAndSweep() = nil
+    proc GC_getStatistics(): string = return ""
+    
+    proc getOccupiedMem(): int = nil
+    proc getFreeMem(): int = nil
+    proc getTotalMem(): int = nil
+    
+    proc setStackBottom(theStackBottom: pointer) = nil
+
+  proc initGC() = nil
+
+  proc newObj(typ: PNimType, size: int): pointer {.compilerproc.} =
+    result = alloc(size)
+  proc newSeq(typ: PNimType, len: int): pointer {.compilerproc.} =
+    result = newObj(typ, addInt(mulInt(len, typ.base.size), GenericSeqSize))
+    cast[PGenericSeq](result).len = len
+    cast[PGenericSeq](result).reserved = len
+
+  proc growObj(old: pointer, newsize: int): pointer =
+    result = realloc(old, newsize)
+
+  proc nimGCref(p: pointer) {.compilerproc, inline.} = nil
+  proc nimGCunref(p: pointer) {.compilerproc, inline.} = nil
+  
+  proc unsureAsgnRef(dest: ppointer, src: pointer) {.compilerproc, inline.} =
+    dest[] = src
+  proc asgnRef(dest: ppointer, src: pointer) {.compilerproc, inline.} =
+    dest[] = src
+  proc asgnRefNoCycle(dest: ppointer, src: pointer) {.compilerproc, inline.} =
+    dest[] = src
+
+  type
+    TMemRegion = object {.final, pure.}
+  
+  proc Alloc(r: var TMemRegion, size: int): pointer =
+    result = alloc(size)
+  proc Alloc0(r: var TMemRegion, size: int): pointer =
+    result = alloc0(size)
+  proc Dealloc(r: var TMemRegion, p: Pointer) = Dealloc(p)
+  proc deallocOsPages(r: var TMemRegion) {.inline.} = nil
+  proc deallocOsPages() {.inline.} = nil
+
 elif defined(nogc):
   # Even though we don't want the GC, we cannot simply use C's memory manager
   # because Nimrod's runtime wants ``realloc`` to zero out the additional
diff --git a/lib/system/repr.nim b/lib/system/repr.nim
index 2dec8136c..ec02f5e08 100755
--- a/lib/system/repr.nim
+++ b/lib/system/repr.nim
@@ -9,6 +9,9 @@
 
 # The generic ``repr`` procedure. It is an invaluable debugging tool.
 
+when not defined(useNimRtl):
+  proc reprAny(p: pointer, typ: PNimType): string {.compilerRtl.}
+
 proc reprInt(x: int64): string {.compilerproc.} = return $x
 proc reprFloat(x: float): string {.compilerproc.} = return $x
 
diff --git a/tests/benchmark.nim b/tests/benchmark.nim
new file mode 100644
index 000000000..8dd9cc2e2
--- /dev/null
+++ b/tests/benchmark.nim
@@ -0,0 +1,47 @@
+#
+#
+#            Nimrod Benchmark tool
+#        (c) Copyright 2012 Dominik Picheta
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+## This program runs benchmarks
+import osproc, os, times, json
+
+type
+  TBenchResult = tuple[file: string, success: bool, time: float]
+
+proc compileBench(file: string) =
+  ## Compiles ``file``.
+  doAssert(execCmdEx("nimrod c -d:release " & file).exitCode == QuitSuccess)
+
+proc runBench(file: string): TBenchResult =
+  ## Runs ``file`` and returns info on how long it took to run.
+  var start = epochTime()
+  if execCmdEx(file.addFileExt(ExeExt)).exitCode == QuitSuccess:
+    var t = epochTime() - start
+    result = (file, true, t)
+  else: result = (file, false, -1.0)
+
+proc genOutput(benches: seq[TBenchResult]): PJsonNode =
+  result = newJObject()
+  for i in benches:
+    if i.success:
+      result[i.file.extractFilename] = newJFloat(i.time)
+    else:
+      result[i.file.extractFilename] = newJNull()
+
+proc doBench(): seq[TBenchResult] =
+  result = @[]
+  for i in walkFiles("tests/benchmarks/*.nim"):
+    echo(i.extractFilename)
+    compileBench(i)
+    result.add(runBench(i))
+
+when isMainModule:
+  var b = doBench()
+  var output = genOutput(b)
+  writeFile("benchmarkResults.json", pretty(output))
+  
\ No newline at end of file
diff --git a/tests/benchmarks/fannkuch.nim b/tests/benchmarks/fannkuch.nim
new file mode 100644
index 000000000..15f78f50c
--- /dev/null
+++ b/tests/benchmarks/fannkuch.nim
@@ -0,0 +1,69 @@
+import os
+import strutils
+
+proc fannkuch (n: int): int =
+    var 
+        count: seq[int]
+        maxFlips = 0
+        m        = n-1
+        r        = n
+        check    = 0
+        perm1: seq[int]
+        perm:  seq[int]
+
+    newSeq (count, n+1)
+    newSeq (perm1, n)
+    newSeq (perm, n)
+    for i in 0 .. n-1:
+        count[i] = i+1
+        perm1[i] = i
+        perm[i]  = i
+    count[n] = n+1
+
+    while True:
+        if check < 30:
+            for i in items (perm1):
+                write (stdout, $(i+1))
+            echo ("")
+            inc (check)
+
+        while r != 1:
+            count[r-1] = r
+            dec (r)
+
+        if perm1[0] != 0 and perm1[m] != m:
+            # perm = perm1
+            # The above line is between 3 and 4 times slower than the loop below!
+            for i in 0 .. n-1:
+                perm[i] = perm1[i]
+            var flipsCount = 0
+            var k = perm[0]
+            while k != 0:
+                for i in 0 .. (k div 2):
+                    swap (perm[i], perm[k-i])
+                inc (flipsCount)
+                k = perm[0]
+
+            if flipsCount > maxFlips:
+                maxFlips = flipsCount
+
+        block makePerm:
+            while r != n:
+                var tmp = perm1[0]
+                # # perm1.delete (0)
+                # # perm1.insert (tmp, r)
+                # # The above is about twice as slow as the following:
+                # moveMem (addr (perm1[0]), addr (perm1[1]), r * sizeof (int))
+                # The call to moveMem is about 50% slower than the loop below!
+                for i in 0 .. r-1:
+                    perm1[i] = perm1[i+1]
+                perm1[r] = tmp
+                
+                dec (count[r])
+                if count[r] > 0:
+                    break makePerm
+                inc (r)
+            return maxFlips
+
+var n = 10
+echo ("Pfannkuchen(" & $n & ") = " & $fannkuch (n))
\ No newline at end of file
diff --git a/tests/benchmarks/quicksort.nim b/tests/benchmarks/quicksort.nim
new file mode 100644
index 000000000..599e3674c
--- /dev/null
+++ b/tests/benchmarks/quicksort.nim
@@ -0,0 +1,54 @@
+import os
+import strutils
+
+# Generate some pseudo-random data
+var seed: tuple[s1, s2, s3: int32] = (2'i32, 8'i32, 16'i32)
+
+proc random(): int32 =
+    seed = (((((((seed[0] and 0x0007_FFFF'i32) shl 13'i32) xor seed[0]) shr
+               19'i32) and 0x0000_1FFF'i32) xor
+             ((seed[0] and 0x000F_FFFE'i32) shl 12'i32)),
+
+            ((((((seed[1] and 0x3FFF_FFFF'i32) shl  2'i32) xor seed[1]) shr
+               25'i32) and 0x0000_007F'i32) xor
+             ((seed[1] and 0x0FFF_FFF8'i32) shl  4'i32)),
+
+            ((((((seed[2] and 0x1FFF_FFFF'i32) shl  3'i32) xor seed[2]) shr
+               11'i32) and 0x001F_FFFF'i32) xor
+             ((seed[2] and 0x0000_7FF0'i32) shl 17'i32)))
+    return seed[0] xor seed[1] xor seed[2]
+
+var n = 9999999
+
+var data: seq[int32]
+newSeq (data, n)
+for i in 0 .. data.high():
+    data[i] = random()
+
+
+proc `$` (d: seq[int32]): string =
+    result = "[ "
+    for i in items (d):
+        result.addSep (", ", 2)
+        result.add ($(i and 0xFFFF_FFFF'i64))
+    result.add (" ]")
+
+# Sort the data
+proc sort (start, stop: int) =
+    if stop <= start+1:
+        return
+
+    var j = start
+    for i in start..stop-2:
+        if data[i] <% data[stop-1]:
+            swap (data[i], data[j])
+            inc (j)
+    swap (data[j], data[stop-1])
+
+    sort (start, j)
+    sort (j+1, stop)
+
+sort (0, data.len)
+echo (data[n div 2 - 1] and 0xFFFF_FFFF'i64, ", ",
+      data[n div 2] and 0xFFFF_FFFF'i64, ", ",
+      data[n div 2 + 1] and 0xFFFF_FFFF'i64)
\ No newline at end of file
diff --git a/tests/compile/tglobalforvar.nim b/tests/compile/tglobalforvar.nim
new file mode 100644
index 000000000..9f61ebcab
--- /dev/null
+++ b/tests/compile/tglobalforvar.nim
@@ -0,0 +1,7 @@
+
+var funcs: seq[proc (): int] = @[]
+for i in 0..10:
+  funcs.add((proc (): int = return i * i))
+
+echo(funcs[3]())
+
diff --git a/tests/compile/tircbot.nim b/tests/compile/tircbot.nim
new file mode 100644
index 000000000..91be18092
--- /dev/null
+++ b/tests/compile/tircbot.nim
@@ -0,0 +1,447 @@
+import irc, sockets, asyncio, json, os, strutils, times, redis
+
+type
+  TDb* = object
+    r*: TRedis
+    lastPing: float
+
+  TBuildResult* = enum
+    bUnknown, bFail, bSuccess
+
+  TTestResult* = enum
+    tUnknown, tFail, tSuccess
+
+  TEntry* = tuple[c: TCommit, p: seq[TPlatform]]
+  
+  TCommit* = object
+    commitMsg*, username*, hash*: string
+    date*: TTime
+
+  TPlatform* = object
+    buildResult*: TBuildResult
+    testResult*: TTestResult
+    failReason*, platform*: string
+    total*, passed*, skipped*, failed*: biggestInt
+    csources*: bool
+
+const
+  listName = "commits"
+  failOnExisting = False
+
+proc open*(host = "localhost", port: TPort): TDb =
+  result.r = redis.open(host, port)
+  result.lastPing = epochTime()
+
+proc customHSet(database: TDb, name, field, value: string) =
+  if database.r.hSet(name, field, value).int == 0:
+    if failOnExisting:
+      assert(false)
+    else:
+      echo("[Warning:REDIS] ", field, " already exists in ", name)
+
+proc updateProperty*(database: TDb, commitHash, platform, property,
+                    value: string) =
+  var name = platform & ":" & commitHash
+  if database.r.hSet(name, property, value).int == 0:
+    echo("[INFO:REDIS] '$1' field updated in hash" % [property])
+  else:
+    echo("[INFO:REDIS] '$1' new field added to hash" % [property])
+
+proc globalProperty*(database: TDb, commitHash, property, value: string) =
+  if database.r.hSet(commitHash, property, value).int == 0:
+    echo("[INFO:REDIS] '$1' field updated in hash" % [property])
+  else:
+    echo("[INFO:REDIS] '$1' new field added to hash" % [property])
+
+proc addCommit*(database: TDb, commitHash, commitMsg, user: string) =
+  # Add the commit hash to the `commits` list.
+  discard database.r.lPush(listName, commitHash)
+  # Add the commit message, current date and username as a property
+  globalProperty(database, commitHash, "commitMsg", commitMsg)
+  globalProperty(database, commitHash, "date", $int(getTime()))
+  globalProperty(database, commitHash, "username", user)
+
+proc keepAlive*(database: var TDb) =
+  ## Keep the connection alive. Ping redis in this case. This functions does
+  ## not guarantee that redis will be pinged.
+  var t = epochTime()
+  if t - database.lastPing >= 60.0:
+    echo("PING -> redis")
+    assert(database.r.ping() == "PONG")
+    database.lastPing = t
+    
+proc getCommits*(database: TDb,
+                 plStr: var seq[string]): seq[TEntry] =
+  result = @[]
+  var commitsRaw = database.r.lrange("commits", 0, -1)
+  for c in items(commitsRaw):
+    var commit: TCommit
+    commit.hash = c
+    for key, value in database.r.hPairs(c):
+      case normalize(key)
+      of "commitmsg": commit.commitMsg = value
+      of "date": commit.date = TTime(parseInt(value))
+      of "username": commit.username = value
+      else:
+        echo(key)
+        assert(false)
+
+    var platformsRaw = database.r.lrange(c & ":platforms", 0, -1)
+    var platforms: seq[TPlatform] = @[]
+    for p in items(platformsRaw):
+      var platform: TPlatform
+      for key, value in database.r.hPairs(p & ":" & c):
+        case normalize(key)
+        of "buildresult":
+          platform.buildResult = parseInt(value).TBuildResult
+        of "testresult":
+          platform.testResult = parseInt(value).TTestResult
+        of "failreason":
+          platform.failReason = value
+        of "total":
+          platform.total = parseBiggestInt(value)
+        of "passed":
+          platform.passed = parseBiggestInt(value)
+        of "skipped":
+          platform.skipped = parseBiggestInt(value)
+        of "failed":
+          platform.failed = parseBiggestInt(value)
+        of "csources":
+          platform.csources = if value == "t": true else: false
+        else:
+          echo(normalize(key))
+          assert(false)
+      
+      platform.platform = p
+      
+      platforms.add(platform)
+      if p notin plStr:
+        plStr.add(p)
+    result.add((commit, platforms))
+
+proc commitExists*(database: TDb, commit: string, starts = false): bool =
+  # TODO: Consider making the 'commits' list a set.
+  for c in items(database.r.lrange("commits", 0, -1)):
+    if starts:
+      if c.startsWith(commit): return true
+    else:
+      if c == commit: return true
+  return false
+
+proc platformExists*(database: TDb, commit: string, platform: string): bool =
+  for p in items(database.r.lrange(commit & ":" & "platforms", 0, -1)):
+    if p == platform: return true
+
+proc expandHash*(database: TDb, commit: string): string =
+  for c in items(database.r.lrange("commits", 0, -1)):
+    if c.startsWith(commit): return c
+  assert false
+
+proc isNewest*(database: TDb, commit: string): bool =
+  return database.r.lIndex("commits", 0) == commit
+
+proc getNewest*(database: TDb): string =
+  return database.r.lIndex("commits", 0)
+
+proc addPlatform*(database: TDb, commit: string, platform: string) =
+  assert database.commitExists(commit)
+  assert (not database.platformExists(commit, platform))
+  var name = platform & ":" & commit
+  if database.r.exists(name):
+    if failOnExisting: quit("[FAIL] " & name & " already exists!", 1)
+    else: echo("[Warning] " & name & " already exists!")
+
+  discard database.r.lPush(commit & ":" & "platforms", platform)
+
+proc `[]`*(p: seq[TPlatform], name: string): TPlatform =
+  for platform in items(p):
+    if platform.platform == name:
+      return platform
+  raise newException(EInvalidValue, name & " platforms not found in commits.")
+  
+proc contains*(p: seq[TPlatform], s: string): bool =
+  for i in items(p):
+    if i.platform == s:
+      return True
+    
+
+type
+  PState = ref TState
+  TState = object of TObject
+    dispatcher: PDispatcher
+    sock: PAsyncSocket
+    ircClient: PAsyncIRC
+    hubPort: TPort
+    database: TDb
+    dbConnected: bool
+
+  TSeenType = enum
+    PSeenJoin, PSeenPart, PSeenMsg, PSeenNick, PSeenQuit
+  
+  TSeen = object
+    nick: string
+    channel: string
+    timestamp: TTime
+    case kind*: TSeenType
+    of PSeenJoin: nil
+    of PSeenPart, PSeenQuit, PSeenMsg:
+      msg: string
+    of PSeenNick:
+      newNick: string
+
+const
+  ircServer = "irc.freenode.net"
+  joinChans = @["#nimrod"]
+  botNickname = "NimBot"
+
+proc setSeen(d: TDb, s: TSeen) =
+  discard d.r.del("seen:" & s.nick)
+
+  var hashToSet = @[("type", $s.kind.int), ("channel", s.channel),
+                    ("timestamp", $s.timestamp.int)]
+  case s.kind
+  of PSeenJoin: nil
+  of PSeenPart, PSeenMsg, PSeenQuit:
+    hashToSet.add(("msg", s.msg))
+  of PSeenNick:
+    hashToSet.add(("newnick", s.newNick))
+  
+  d.r.hMSet("seen:" & s.nick, hashToSet)
+
+proc getSeen(d: TDb, nick: string, s: var TSeen): bool =
+  if d.r.exists("seen:" & nick):
+    result = true
+    s.nick = nick
+    # Get the type first
+    s.kind = d.r.hGet("seen:" & nick, "type").parseInt.TSeenType
+    
+    for key, value in d.r.hPairs("seen:" & nick):
+      case normalize(key)
+      of "type":
+        #s.kind = value.parseInt.TSeenType
+      of "channel":
+        s.channel = value
+      of "timestamp":
+        s.timestamp = TTime(value.parseInt)
+      of "msg":
+        s.msg = value
+      of "newnick":
+        s.newNick = value
+
+template createSeen(typ: TSeenType, n, c: string): stmt =
+  var seenNick: TSeen
+  seenNick.kind = typ
+  seenNick.nick = n
+  seenNick.channel = c
+  seenNick.timestamp = getTime()
+
+proc parseReply(line: string, expect: string): Bool =
+  var jsonDoc = parseJson(line)
+  return jsonDoc["reply"].str == expect
+
+proc limitCommitMsg(m: string): string =
+  ## Limits the message to 300 chars and adds ellipsis.
+  var m1 = m
+  if NewLines in m1:
+    m1 = m1.splitLines()[0]
+  
+  if m1.len >= 300:
+    m1 = m1[0..300]
+
+  if m1.len >= 300 or NewLines in m: m1.add("... ")
+
+  if NewLines in m: m1.add($m.splitLines().len & " more lines")
+
+  return m1
+
+proc handleWebMessage(state: PState, line: string) =
+  echo("Got message from hub: " & line)
+  var json = parseJson(line)
+  if json.existsKey("payload"):
+    for i in 0..min(4, json["payload"]["commits"].len-1):
+      var commit = json["payload"]["commits"][i]
+      # Create the message
+      var message = ""
+      message.add(json["payload"]["repository"]["owner"]["name"].str & "/" &
+                  json["payload"]["repository"]["name"].str & " ")
+      message.add(commit["id"].str[0..6] & " ")
+      message.add(commit["author"]["name"].str & " ")
+      message.add("[+" & $commit["added"].len & " ")
+      message.add("±" & $commit["modified"].len & " ")
+      message.add("-" & $commit["removed"].len & "]: ")
+      message.add(limitCommitMsg(commit["message"].str))
+
+      # Send message to #nimrod.
+      state.ircClient[].privmsg(joinChans[0], message)
+  elif json.existsKey("redisinfo"):
+    assert json["redisinfo"].existsKey("port")
+    let redisPort = json["redisinfo"]["port"].num
+    state.dbConnected = true
+
+proc hubConnect(state: PState)
+proc handleConnect(s: PAsyncSocket, userArg: PObject) =
+  let state = PState(userArg)
+  try:
+    # Send greeting
+    var obj = newJObject()
+    obj["name"] = newJString("irc")
+    obj["platform"] = newJString("?")
+    state.sock.send($obj & "\c\L")
+
+    # Wait for reply.
+    var line = ""
+    sleep(1500)
+    if state.sock.recvLine(line):
+      assert(line != "")
+      doAssert parseReply(line, "OK")
+      echo("The hub accepted me!")
+    else:
+      raise newException(EInvalidValue,
+                         "Hub didn't accept me. Waited 1.5 seconds.")
+    
+    # ask for the redis info
+    var riobj = newJObject()
+    riobj["do"] = newJString("redisinfo")
+    state.sock.send($riobj & "\c\L")
+    
+  except EOS:
+    echo(getCurrentExceptionMsg())
+    s.close()
+    echo("Waiting 5 seconds...")
+    sleep(5000)
+    state.hubConnect()
+
+proc handleRead(s: PAsyncSocket, userArg: PObject) =
+  let state = PState(userArg)
+  var line = ""
+  if state.sock.recvLine(line):
+    if line != "":
+      # Handle the message
+      state.handleWebMessage(line)
+    else:
+      echo("Disconnected from hub: ", OSErrorMsg())
+      s.close()
+      echo("Reconnecting...")
+      state.hubConnect()
+  else:
+    echo(OSErrorMsg())
+
+proc hubConnect(state: PState) =
+  state.sock = AsyncSocket()
+  state.sock.connect("127.0.0.1", state.hubPort)
+  state.sock.userArg = state
+  state.sock.handleConnect = handleConnect
+  state.sock.handleRead = handleRead
+
+  state.dispatcher.register(state.sock)
+
+proc handleIrc(irc: var TAsyncIRC, event: TIRCEvent, userArg: PObject) =
+  let state = PState(userArg)
+  case event.typ
+  of EvDisconnected:
+    while not state.ircClient[].isConnected:
+      try:
+        state.ircClient.connect()
+      except:
+        echo("Error reconnecting: ", getCurrentExceptionMsg())
+      
+      echo("Waiting 5 seconds...")
+      sleep(5000)
+    echo("Reconnected successfully!")
+  of EvMsg:
+    echo("< ", event.raw)
+    case event.cmd
+    of MPrivMsg:
+      let msg = event.params[event.params.len-1]
+      let words = msg.split(' ')
+      template pm(msg: string): stmt =
+        state.ircClient[].privmsg(event.origin, msg)
+      case words[0]
+      of "!ping": pm("pong")
+      of "!lag":
+        if state.ircClient[].getLag != -1.0:
+          var lag = state.ircClient[].getLag
+          lag = lag * 1000.0
+          pm($int(lag) & "ms between me and the server.")
+        else:
+          pm("Unknown.")
+      of "!seen":
+        if words.len > 1:
+          let nick = words[1]
+          if nick == botNickname:
+            pm("Yes, I see myself.")
+          echo(nick)
+          var seenInfo: TSeen
+          if state.database.getSeen(nick, seenInfo):
+            var mSend = ""
+            case seenInfo.kind
+            of PSeenMsg:
+              pm("$1 was last seen on $2 in $3 saying: $4" %
+                    [seenInfo.nick, $seenInfo.timestamp,
+                     seenInfo.channel, seenInfo.msg])
+            of PSeenJoin:
+              pm("$1 was last seen on $2 joining $3" %
+                        [seenInfo.nick, $seenInfo.timestamp, seenInfo.channel])
+            of PSeenPart:
+              pm("$1 was last seen on $2 leaving $3 with message: $4" %
+                        [seenInfo.nick, $seenInfo.timestamp, seenInfo.channel,
+                         seenInfo.msg])
+            of PSeenQuit:
+              pm("$1 was last seen on $2 quitting with message: $3" %
+                        [seenInfo.nick, $seenInfo.timestamp, seenInfo.msg])
+            of PSeenNick:
+              pm("$1 was last seen on $2 changing nick to $3" %
+                        [seenInfo.nick, $seenInfo.timestamp, seenInfo.newNick])
+            
+          else:
+            pm("I have not seen " & nick)
+        else:
+          pm("Syntax: !seen <nick>")
+
+      # TODO: ... commands
+
+      # -- Seen
+      # Log this as activity.
+      createSeen(PSeenMsg, event.nick, event.origin)
+      seenNick.msg = msg
+      state.database.setSeen(seenNick)
+    of MJoin:
+      createSeen(PSeenJoin, event.nick, event.origin)
+      state.database.setSeen(seenNick)
+    of MPart:
+      createSeen(PSeenPart, event.nick, event.origin)
+      let msg = event.params[event.params.high]
+      seenNick.msg = msg
+      state.database.setSeen(seenNick)
+    of MQuit:
+      createSeen(PSeenQuit, event.nick, event.origin)
+      let msg = event.params[event.params.high]
+      seenNick.msg = msg
+      state.database.setSeen(seenNick)
+    of MNick:
+      createSeen(PSeenNick, event.nick, "#nimrod")
+      seenNick.newNick = event.params[0]
+      state.database.setSeen(seenNick)
+    else:
+      nil # TODO: ?
+
+proc open(port: TPort = TPort(5123)): PState =
+  new(result)
+  result.dispatcher = newDispatcher()
+  
+  result.hubPort = port
+  result.hubConnect()
+
+  # Connect to the irc server.
+  result.ircClient = AsyncIrc(ircServer, nick = botNickname, user = botNickname,
+                 joinChans = joinChans, ircEvent = handleIrc, userArg = result)
+  result.ircClient.connect()
+  result.dispatcher.register(result.ircClient)
+
+  result.dbConnected = false
+
+var state = tircbot.open() # Connect to the website and the IRC server.
+
+while state.dispatcher.poll():
+  if state.dbConnected:
+    state.database.keepAlive()
diff --git a/tests/reject/t99bott.nim b/tests/reject/t99bott.nim
index 7d11ba4b0..7ebfd61e9 100755
--- a/tests/reject/t99bott.nim
+++ b/tests/reject/t99bott.nim
@@ -1,7 +1,7 @@
 discard """
   file: "t99bott.nim"
   line: 26
-  errormsg: "cannot evaluate 'GetBottleNumber(bn)'"
+  errormsg: "constant expression expected"
   disabled: false
 """
 ## 99 Bottles of Beer
diff --git a/tests/reject/tenumitems.nim b/tests/reject/tenumitems.nim
index a0497fd59..b6eee5ba8 100644
--- a/tests/reject/tenumitems.nim
+++ b/tests/reject/tenumitems.nim
@@ -1,6 +1,6 @@
 discard """
   line: 7
-  errormsg: "a type has no value"
+  errormsg: "type mismatch"
 """
 
 type a = enum b,c,d
diff --git a/todo.txt b/todo.txt
index 9921e06d7..9772f4001 100755
--- a/todo.txt
+++ b/todo.txt
@@ -1,7 +1,7 @@
 version 0.9.0
 =============
 
-- bootstrapping fails with --symbolFiles:on again!
+- make GC realtime capable: GC_step(ms: int)
 - ``=`` should be overloadable; requires specialization for ``=``
 - fix remaining generics bugs
 - fix remaining closure bugs:
@@ -49,6 +49,8 @@ Bugs
   without ``-d:release`` leaks memory?
 - bug: object {.pure, final.} does not work again!
 - bug: tsortdev does not run with native GC?
+- bug: pragma statements in combination with symbol files are evaluated twice
+  but this can lead to compilation errors
 
 
 version 0.9.XX
@@ -98,6 +100,7 @@ version 0.9.XX
 Library
 -------
 
+- provide more up to date OpenGL headers
 - wrappers for mongodb; poppler; libharu
 - suffix trees
 - locale support; i18n module
diff --git a/web/index.txt b/web/index.txt
index fcdccee49..3e939f492 100755
--- a/web/index.txt
+++ b/web/index.txt
@@ -42,11 +42,11 @@ priority).
 Nimrod is efficient
 ===================
 
-* Native code generation (currently via compilation to C), not dependant on a
+* Native code generation (currently via compilation to C), not dependent on a
   virtual machine: **Nimrod produces small executables without dependencies
   for easy redistribution.**
-* A fast non-recursive incremental and generational garbage collector that 
-  should be well suited for soft real-time systems (like games).
+* A fast **non-tracing** garbage collector that should be well suited for soft 
+  real-time systems (like games).
 * System programming features: Ability to manage your own memory and access the
   hardware directly. Pointers to garbage collected memory are distinguished
   from pointers to manually managed memory.
diff --git a/web/news.txt b/web/news.txt
index 633ad3d08..897961c25 100755
--- a/web/news.txt
+++ b/web/news.txt
@@ -17,6 +17,7 @@ Bugfixes
 Library Additions
 -----------------
 
+- Added the (already existing) module ``htmlgen`` to the documentation.
 - Added ``system.shallow`` that can be used to speed up string and sequence
   assignments.
 - Added ``system.eval`` that can execute an anonymous block of code at