summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorMichał Zieliński <michal@zielinscy.org.pl>2014-01-26 17:06:21 +0100
committerMichał Zieliński <michal@zielinscy.org.pl>2014-01-26 17:06:21 +0100
commite0e0b409e49b53e9c95de6fcb0372707b3869de6 (patch)
treef4128f64551d3de5fd2e21ab53686bf370ee21a8
parentad1a0c51e265eaaa977dd35654f9a3136983e2fa (diff)
parent5d712e0d3f9f5b8e486720c8bedd749656b527d8 (diff)
downloadNim-e0e0b409e49b53e9c95de6fcb0372707b3869de6.tar.gz
Merge branch 'devel' of https://github.com/Araq/Nimrod into devel
Conflicts:
	lib/pure/osproc.nim
-rw-r--r--compiler/ast.nim59
-rw-r--r--compiler/ccgcalls.nim8
-rw-r--r--compiler/ccgutils.nim2
-rw-r--r--compiler/cgen.nim124
-rw-r--r--compiler/jsgen.nim2
-rw-r--r--compiler/lambdalifting.nim444
-rw-r--r--compiler/lexer.nim2
-rw-r--r--compiler/parser.nim138
-rw-r--r--compiler/renderer.nim28
-rw-r--r--compiler/semdestruct.nim5
-rw-r--r--compiler/semexprs.nim39
-rw-r--r--compiler/semfold.nim3
-rw-r--r--compiler/semstmts.nim21
-rw-r--r--compiler/semtypes.nim11
-rw-r--r--compiler/semtypinst.nim9
-rw-r--r--compiler/sigmatch.nim150
-rw-r--r--compiler/transf.nim13
-rw-r--r--compiler/types.nim55
-rw-r--r--compiler/vm.nim4
-rw-r--r--doc/docgen.txt192
-rw-r--r--doc/docgen_sample.nim12
-rw-r--r--doc/grammar.txt34
-rw-r--r--doc/manual.txt39
-rw-r--r--doc/nimrodc.txt7
-rw-r--r--koch.nim9
-rw-r--r--lib/core/macros.nim22
-rw-r--r--lib/pure/asyncio.nim18
-rw-r--r--lib/pure/ftpclient.nim20
-rw-r--r--lib/pure/os.nim2
-rw-r--r--lib/pure/osproc.nim5
-rw-r--r--lib/pure/pegs.nim8
-rw-r--r--lib/pure/sockets.nim6
-rw-r--r--lib/system.nim66
-rw-r--r--lib/system/excpt.nim6
-rw-r--r--lib/system/jssys.nim6
-rw-r--r--tests/assert/tfailedassert.nim2
-rw-r--r--tests/closure/tnamedparamanonproc.nim4
-rw-r--r--tests/controlflow/tblock1.nim (renamed from tests/block/tblock1.nim)0
-rw-r--r--tests/controlflow/tnestif.nim (renamed from tests/ifstmt/tnestif.nim)0
-rw-r--r--tests/iter/tanoniter1.nim32
-rw-r--r--tests/iter/titer2.nim2
-rw-r--r--tests/macros/tmemit.nim7
-rw-r--r--tests/metatype/tstaticparams.nim (renamed from tests/static/tstaticparams.nim)0
-rw-r--r--tests/objects/tobjconstr.nim (renamed from tests/object/tobjconstr.nim)0
-rw-r--r--tests/objects/tobjconstr2.nim (renamed from tests/object/tobjconstr2.nim)0
-rw-r--r--tests/objects/tobjcov.nim (renamed from tests/object/tobjcov.nim)0
-rw-r--r--tests/objects/tobject.nim (renamed from tests/object/tobject.nim)0
-rw-r--r--tests/objects/tobject2.nim (renamed from tests/object/tobject2.nim)0
-rw-r--r--tests/objects/tobject3.nim (renamed from tests/object/tobject3.nim)0
-rw-r--r--tests/objects/tofopr.nim (renamed from tests/operator/tofopr.nim)0
-rw-r--r--tests/objects/toop.nim (renamed from tests/object/toop.nim)0
-rw-r--r--tests/objects/toop1.nim (renamed from tests/object/toop1.nim)0
-rw-r--r--tests/parser/tcommand_as_expr.nim12
-rw-r--r--tests/parser/tdomulttest.nim17
-rw-r--r--tests/parser/tinvwhen.nim15
-rw-r--r--tests/parser/toprprec.nim (renamed from tests/operator/toprprec.nim)0
-rw-r--r--tests/parser/tprecedence.nim (renamed from tests/operator/tprecedence.nim)0
-rw-r--r--tests/patterns/tpatterns.nim (renamed from tests/pattern/tpatterns.nim)0
-rw-r--r--tests/pragmas/tuserpragma.nim (renamed from tests/pragma/tuserpragma.nim)0
-rw-r--r--tests/showoff/tdrdobbs_examples.nim (renamed from tests/important/tdrdobbs_examples.nim)0
-rw-r--r--todo.txt36
-rw-r--r--tools/nimweb.nim14
-rw-r--r--web/news.txt9
-rw-r--r--web/nimrod.ini2
64 files changed, 1144 insertions, 577 deletions
diff --git a/compiler/ast.nim b/compiler/ast.nim
index 0e351a31a..7138b5f52 100644
--- a/compiler/ast.nim
+++ b/compiler/ast.nim
@@ -336,26 +336,52 @@ type
     tyConst, tyMutable, tyVarargs, 
     tyIter, # unused
     tyProxy # used as errornous type (for idetools)
-    tyTypeClass
-    tyParametricTypeClass # structured similarly to tyGenericInst
-                          # lastSon is the body of the type class
     
-    tyBuiltInTypeClass # Type such as the catch-all object, tuple, seq, etc
+    tyBuiltInTypeClass #\
+      # Type such as the catch-all object, tuple, seq, etc
     
-    tyCompositeTypeClass # 
+    tyUserTypeClass #\
+      # the body of a user-defined type class
+
+    tyUserTypeClassInst #\
+      # Instance of a parametric user-defined type class.
+      # Structured similarly to tyGenericInst.
+      # tyGenericInst represents concrete types, while
+      # this is still a "generic param" that will bind types
+      # and resolves them during sigmatch and instantiation.
     
-    tyAnd, tyOr, tyNot # boolean type classes such as `string|int`,`not seq`,
-                       # `Sortable and Enumable`, etc
+    tyCompositeTypeClass #\
+      # Type such as seq[Number]
+      # The notes for tyUserTypeClassInst apply here as well 
+      # sons[0]: the original expression used by the user.
+      # sons[1]: fully expanded and instantiated meta type
+      # (potentially following aliases)
     
-    tyAnything # a type class matching any type
+    tyAnd, tyOr, tyNot #\
+      # boolean type classes such as `string|int`,`not seq`,
+      # `Sortable and Enumable`, etc
     
-    tyStatic   # a value known at compile type (the underlying type is .base)
+    tyAnything #\
+      # a type class matching any type
     
-    tyFromExpr # This is a type representing an expression that depends
-               # on generic parameters (the exprsesion is stored in t.n)
-               # It will be converted to a real type only during generic
-               # instantiation and prior to this it has the potential to
-               # be any type.
+    tyStatic #\
+      # a value known at compile type (the underlying type is .base)
+    
+    tyFromExpr #\
+      # This is a type representing an expression that depends
+      # on generic parameters (the exprsesion is stored in t.n)
+      # It will be converted to a real type only during generic
+      # instantiation and prior to this it has the potential to
+      # be any type.
+
+    tyFieldAccessor #\
+      # Expressions such as Type.field (valid in contexts such
+      # as the `is` operator and magics like `high` and `low`).
+      # Could be lifted to a single argument proc returning the
+      # field value.
+      # sons[0]: type of containing object or tuple
+      # sons[1]: field type
+      # .n: nkDotExpr storing the field name
 
 const
   tyPureObject* = tyTuple
@@ -364,8 +390,9 @@ const
 
   tyUnknownTypes* = {tyError, tyFromExpr}
 
-  tyTypeClasses* = {tyTypeClass, tyBuiltInTypeClass, tyCompositeTypeClass,
-                    tyParametricTypeClass, tyAnd, tyOr, tyNot, tyAnything}
+  tyTypeClasses* = {tyBuiltInTypeClass, tyCompositeTypeClass,
+                    tyUserTypeClass, tyUserTypeClassInst,
+                    tyAnd, tyOr, tyNot, tyAnything}
 
   tyMetaTypes* = {tyGenericParam, tyTypeDesc, tyStatic, tyExpr} + tyTypeClasses
  
diff --git a/compiler/ccgcalls.nim b/compiler/ccgcalls.nim
index 1c6eea621..84c5bf419 100644
--- a/compiler/ccgcalls.nim
+++ b/compiler/ccgcalls.nim
@@ -146,7 +146,8 @@ proc genClosureCall(p: BProc, le, ri: PNode, d: var TLoc) =
   proc addComma(r: PRope): PRope =
     result = if r == nil: r else: con(r, ~", ")
 
-  const CallPattern = "$1.ClEnv? $1.ClPrc($3$1.ClEnv) : (($4)($1.ClPrc))($2)"
+  const PatProc = "$1.ClEnv? $1.ClPrc($3$1.ClEnv):(($4)($1.ClPrc))($2)"
+  const PatIter = "$1.ClPrc($3$1.ClEnv)" # we know the env exists
   var op: TLoc
   initLocExpr(p, ri.sons[0], op)
   var pl: PRope
@@ -164,9 +165,10 @@ proc genClosureCall(p: BProc, le, ri: PNode, d: var TLoc) =
     if i < length - 1: app(pl, ~", ")
   
   template genCallPattern {.dirty.} =
-    lineF(p, cpsStmts, CallPattern & ";$n", op.r, pl, pl.addComma, rawProc)
+    lineF(p, cpsStmts, callPattern & ";$n", op.r, pl, pl.addComma, rawProc)
 
   let rawProc = getRawProcType(p, typ)
+  let callPattern = if tfIterator in typ.flags: PatIter else: PatProc
   if typ.sons[0] != nil:
     if isInvalidReturnType(typ.sons[0]):
       if sonsLen(ri) > 1: app(pl, ~", ")
@@ -190,7 +192,7 @@ proc genClosureCall(p: BProc, le, ri: PNode, d: var TLoc) =
       assert(d.t != nil)        # generate an assignment to d:
       var list: TLoc
       initLoc(list, locCall, d.t, OnUnknown)
-      list.r = ropef(CallPattern, op.r, pl, pl.addComma, rawProc)
+      list.r = ropef(callPattern, op.r, pl, pl.addComma, rawProc)
       genAssignment(p, d, list, {}) # no need for deep copying
   else:
     genCallPattern()
diff --git a/compiler/ccgutils.nim b/compiler/ccgutils.nim
index fe349174f..1129ecbef 100644
--- a/compiler/ccgutils.nim
+++ b/compiler/ccgutils.nim
@@ -87,7 +87,7 @@ proc getUniqueType*(key: PType): PType =
       gCanonicalTypes[k] = key
       result = key
   of tyTypeDesc, tyTypeClasses, tyGenericParam,
-     tyFromExpr, tyStatic:
+     tyFromExpr, tyStatic, tyFieldAccessor:
     internalError("GetUniqueType")
   of tyGenericInst, tyDistinct, tyOrdinal, tyMutable, tyConst, tyIter:
     result = getUniqueType(lastSon(key))
diff --git a/compiler/cgen.nim b/compiler/cgen.nim
index 0e6e48399..5057ae558 100644
--- a/compiler/cgen.nim
+++ b/compiler/cgen.nim
@@ -911,29 +911,29 @@ proc addIntTypes(result: var PRope) {.inline.} =
   appf(result, "#define NIM_INTBITS $1", [
     platform.CPU[targetCPU].intSize.toRope])
 
-proc getCopyright(cfilenoext: string): PRope = 
-  if optCompileOnly in gGlobalOptions: 
-    result = ropeff("/* Generated by Nimrod Compiler v$1 */$n" &
-        "/*   (c) 2014 Andreas Rumpf */$n" &
-        "/* The generated code is subject to the original license. */$n",
-        "; Generated by Nimrod Compiler v$1$n" &
-        ";   (c) 2012 Andreas Rumpf$n", [toRope(VersionAsString)])
-  else: 
-    result = ropeff("/* Generated by Nimrod Compiler v$1 */$n" &
-        "/*   (c) 2014 Andreas Rumpf */$n" & 
-        "/* The generated code is subject to the original license. */$n" &
-        "/* Compiled for: $2, $3, $4 */$n" &
-        "/* Command for C compiler:$n   $5 */$n", 
-        "; Generated by Nimrod Compiler v$1$n" &
-        ";   (c) 2014 Andreas Rumpf$n" & 
-        "; Compiled for: $2, $3, $4$n" &
-        "; Command for LLVM compiler:$n   $5$n", [toRope(VersionAsString), 
-        toRope(platform.OS[targetOS].name), 
-        toRope(platform.CPU[targetCPU].name), 
-        toRope(extccomp.CC[extccomp.cCompiler].name), 
+proc getCopyright(cfilenoext: string): PRope =
+  if optCompileOnly in gGlobalOptions:
+    result = ropeff("/* Generated by Nimrod Compiler v$1 */$N" &
+        "/*   (c) 2014 Andreas Rumpf */$N" &
+        "/* The generated code is subject to the original license. */$N",
+        "; Generated by Nimrod Compiler v$1$N" &
+        ";   (c) 2012 Andreas Rumpf$N", [toRope(VersionAsString)])
+  else:
+    result = ropeff("/* Generated by Nimrod Compiler v$1 */$N" &
+        "/*   (c) 2014 Andreas Rumpf */$N" &
+        "/* The generated code is subject to the original license. */$N" &
+        "/* Compiled for: $2, $3, $4 */$N" &
+        "/* Command for C compiler:$n   $5 */$N",
+        "; Generated by Nimrod Compiler v$1$N" &
+        ";   (c) 2014 Andreas Rumpf$N" &
+        "; Compiled for: $2, $3, $4$N" &
+        "; Command for LLVM compiler:$N   $5$N", [toRope(VersionAsString),
+        toRope(platform.OS[targetOS].name),
+        toRope(platform.CPU[targetCPU].name),
+        toRope(extccomp.CC[extccomp.cCompiler].name),
         toRope(getCompileCFileCmd(cfilenoext))])
 
-proc getFileHeader(cfilenoext: string): PRope = 
+proc getFileHeader(cfilenoext: string): PRope =
   result = getCopyright(cfilenoext)
   addIntTypes(result)
 
@@ -941,61 +941,71 @@ proc genFilenames(m: BModule): PRope =
   discard cgsym(m, "dbgRegisterFilename")
   result = nil
   for i in 0.. <fileInfos.len:
-    result.appf("dbgRegisterFilename($1);$n", fileInfos[i].projPath.makeCString)
+    result.appf("dbgRegisterFilename($1);$N", fileInfos[i].projPath.makeCString)
 
 proc genMainProc(m: BModule) =
   const 
     PreMainBody =
-      "\tsystemDatInit();$n" &
-      "\tsystemInit();$n" &
+      "\tsystemDatInit();$N" &
+      "\tsystemInit();$N" &
       "$1" &
       "$2" &
       "$3" &
       "$4"
 
     MainProcs =
-      "\tPreMain();$n" &
-      "\tNimMain();$n"
+      "\tNimMain();$N"
     
     MainProcsWithResult =
-      MainProcs & "\treturn nim_program_result;$n"
+      MainProcs & "\treturn nim_program_result;$N"
+
+    NimMainBody =
+      "N_CDECL(void, NimMain)(void) {$N" &
+        "\tPreMain();$N" &
+        "$1$N" &
+      "}$N"
 
     PosixNimMain =
-      "int cmdCount;$n" &
-      "char** cmdLine;$n" &
-      "char** gEnv;$n" &
-      "N_CDECL(void, NimMain)(void) {$n$1}$n"
+      "int cmdCount;$N" &
+      "char** cmdLine;$N" &
+      "char** gEnv;$N" &
+      NimMainBody
   
-    PosixCMain = "int main(int argc, char** args, char** env) {$n" &
-      "\tcmdLine = args;$n" & "\tcmdCount = argc;$n" & "\tgEnv = env;$n" &
-      MainProcsWithResult &
-      "}$n"
+    PosixCMain =
+      "int main(int argc, char** args, char** env) {$N" &
+        "\tcmdLine = args;$N" &
+        "\tcmdCount = argc;$N" &
+        "\tgEnv = env;$N" &
+        MainProcsWithResult &
+      "}$N"
   
-    StandaloneCMain = "int main(void) {$n" &
-      MainProcs &
-      "\treturn 0;$n" & "}$n"
+    StandaloneCMain =
+      "int main(void) {$N" &
+        MainProcs &
+        "\treturn 0;$N" &
+      "}$N"
     
-    WinNimMain = "N_CDECL(void, NimMain)(void) {$n$1}$n"
+    WinNimMain = NimMainBody
     
-    WinCMain = "N_STDCALL(int, WinMain)(HINSTANCE hCurInstance, $n" &
-      "                        HINSTANCE hPrevInstance, $n" &
-      "                        LPSTR lpCmdLine, int nCmdShow) {$n" &
-      MainProcsWithResult & "}$n"
+    WinCMain = "N_STDCALL(int, WinMain)(HINSTANCE hCurInstance, $N" &
+      "                        HINSTANCE hPrevInstance, $N" &
+      "                        LPSTR lpCmdLine, int nCmdShow) {$N" &
+      MainProcsWithResult & "}$N"
   
-    WinNimDllMain = "N_LIB_EXPORT N_CDECL(void, NimMain)(void) {$n$1}$n"
+    WinNimDllMain = "N_LIB_EXPORT " & NimMainBody
 
     WinCDllMain =
-      "BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fwdreason, $n" &
-      "                    LPVOID lpvReserved) {$n" &
-      "\tif(fwdreason == DLL_PROCESS_ATTACH) {" & MainProcs & "}$n" &
-      "\treturn 1;$n}$n"
+      "BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fwdreason, $N" &
+      "                    LPVOID lpvReserved) {$N" &
+      "\tif(fwdreason == DLL_PROCESS_ATTACH) {$N" & MainProcs & "}$N" &
+      "\treturn 1;$N}$N"
 
     PosixNimDllMain = WinNimDllMain
     
     PosixCDllMain =
-      "void NIM_POSIX_INIT NimMainInit(void) {$n" &
-      MainProcs &
-      "}$n"
+      "void NIM_POSIX_INIT NimMainInit(void) {$N" &
+        MainProcs &
+      "}$N"
 
   var nimMain, otherMain: TFormatStr
   if platform.targetOS == osWindows and
@@ -1022,9 +1032,9 @@ proc genMainProc(m: BModule) =
   
   let initStackBottomCall = if emulatedThreadVars() or
                               platform.targetOS == osStandalone: "".toRope
-                            else: ropecg(m, "\t#initStackBottom();$n")
+                            else: ropecg(m, "\t#initStackBottom();$N")
   inc(m.labels)
-  appcg(m, m.s[cfsProcs], "void PreMain() {$n" & PreMainBody & "}$n", [
+  appcg(m, m.s[cfsProcs], "void PreMain() {$N" & PreMainBody & "}$N", [
     mainDatInit, initStackBottomCall, gBreakpoints, otherModsInit])
 
   appcg(m, m.s[cfsProcs], nimMain, [mainModInit, toRope(m.labels)])
@@ -1049,8 +1059,8 @@ proc registerModuleToMain(m: PSym) =
   appff(mainModProcs, "N_NOINLINE(void, $1)(void);$N",
                       "declare void $1() noinline$N", [datInit])
   if sfSystemModule notin m.flags:
-    appff(mainDatInit, "\t$1();$n", "call void ()* $1$n", [datInit])
-    let initCall = ropeff("\t$1();$n", "call void ()* $1$n", [init])
+    appff(mainDatInit, "\t$1();$N", "call void ()* $1$n", [datInit])
+    let initCall = ropeff("\t$1();$N", "call void ()* $1$n", [init])
     if sfMainModule in m.flags:
       app(mainModInit, initCall)
     else:
@@ -1058,7 +1068,7 @@ proc registerModuleToMain(m: PSym) =
     
 proc genInitCode(m: BModule) = 
   var initname = getInitName(m.module)
-  var prc = ropeff("N_NOINLINE(void, $1)(void) {$n", 
+  var prc = ropeff("N_NOINLINE(void, $1)(void) {$N", 
                    "define void $1() noinline {$n", [initname])
   if m.typeNodes > 0: 
     appcg(m, m.s[cfsTypeInit1], "static #TNimNode $1[$2];$n", 
@@ -1101,7 +1111,7 @@ proc genInitCode(m: BModule) =
   app(prc, deinitGCFrame(m.initProc))
   appf(prc, "}$N$N")
 
-  prc.appff("N_NOINLINE(void, $1)(void) {$n",
+  prc.appff("N_NOINLINE(void, $1)(void) {$N",
             "define void $1() noinline {$n", [getDatInitName(m.module)])
 
   for i in cfsTypeInit1..cfsDynLibInit:
diff --git a/compiler/jsgen.nim b/compiler/jsgen.nim
index 82c45059c..c0fc4131a 100644
--- a/compiler/jsgen.nim
+++ b/compiler/jsgen.nim
@@ -130,7 +130,7 @@ proc mapType(typ: PType): TJSTypeKind =
     result = etyObject
   of tyNil: result = etyNull
   of tyGenericInst, tyGenericParam, tyGenericBody, tyGenericInvokation,
-     tyNone, tyFromExpr, tyForward, tyEmpty,
+     tyNone, tyFromExpr, tyForward, tyEmpty, tyFieldAccessor,
      tyExpr, tyStmt, tyStatic, tyTypeDesc, tyTypeClasses:
     result = etyNone
   of tyProc: result = etyProc
diff --git a/compiler/lambdalifting.nim b/compiler/lambdalifting.nim
index ed92fefb4..00fa04556 100644
--- a/compiler/lambdalifting.nim
+++ b/compiler/lambdalifting.nim
@@ -116,9 +116,9 @@ type
   TDep = tuple[e: PEnv, field: PSym]
   TEnv {.final.} = object of TObject
     attachedNode: PNode
-    closure: PSym   # if != nil it is a used environment
+    createdVar: PSym         # if != nil it is a used environment
     capturedVars: seq[PSym] # captured variables in this environment
-    deps: seq[TDep] # dependencies
+    deps: seq[TDep]         # dependencies
     up: PEnv
     tup: PType
   
@@ -130,12 +130,99 @@ type
   TOuterContext {.final.} = object
     fn: PSym # may also be a module!
     currentEnv: PEnv
+    isIter: bool   # first class iterator?
     capturedVars, processed: TIntSet
     localsToEnv: TIdTable # PSym->PEnv mapping
     localsToAccess: TIdNodeTable
     lambdasToEnv: TIdTable # PSym->PEnv mapping
     up: POuterContext
 
+    closureParam, state, resultSym: PSym # only if isIter
+    tup: PType # only if isIter
+
+
+proc getStateType(iter: PSym): PType =
+  var n = newNodeI(nkRange, iter.info)
+  addSon(n, newIntNode(nkIntLit, -1))
+  addSon(n, newIntNode(nkIntLit, 0))
+  result = newType(tyRange, iter)
+  result.n = n
+  rawAddSon(result, getSysType(tyInt))
+
+proc createStateField(iter: PSym): PSym =
+  result = newSym(skField, getIdent(":state"), iter, iter.info)
+  result.typ = getStateType(iter)
+
+proc newIterResult(iter: PSym): PSym =
+  if resultPos < iter.ast.len:
+    result = iter.ast.sons[resultPos].sym
+  else:
+    # XXX a bit hacky:
+    result = newSym(skResult, getIdent":result", iter, iter.info)
+    result.typ = iter.typ.sons[0]
+    incl(result.flags, sfUsed)
+    iter.ast.add newSymNode(result)
+
+proc addHiddenParam(routine: PSym, param: PSym) =
+  var params = routine.ast.sons[paramsPos]
+  # -1 is correct here as param.position is 0 based but we have at position 0
+  # some nkEffect node:
+  param.position = params.len-1
+  addSon(params, newSymNode(param))
+  incl(routine.typ.flags, tfCapturesEnv)
+  #echo "produced environment: ", param.id, " for ", routine.name.s
+
+proc getHiddenParam(routine: PSym): PSym =
+  let params = routine.ast.sons[paramsPos]
+  let hidden = lastSon(params)
+  assert hidden.kind == nkSym
+  result = hidden.sym
+
+proc getEnvParam(routine: PSym): PSym =
+  let params = routine.ast.sons[paramsPos]
+  let hidden = lastSon(params)
+  if hidden.kind == nkSym and hidden.sym.name.s == paramName:
+    result = hidden.sym
+    
+proc addField(tup: PType, s: PSym) =
+  var field = newSym(skField, s.name, s.owner, s.info)
+  let t = skipIntLit(s.typ)
+  field.typ = t
+  field.position = sonsLen(tup)
+  addSon(tup.n, newSymNode(field))
+  rawAddSon(tup, t)
+
+proc initIterContext(c: POuterContext, iter: PSym) =
+  c.fn = iter
+  c.capturedVars = initIntSet()
+
+  var cp = getEnvParam(iter)
+  if cp == nil:
+    c.tup = newType(tyTuple, iter)
+    c.tup.n = newNodeI(nkRecList, iter.info)
+
+    cp = newSym(skParam, getIdent(paramName), iter, iter.info)
+    incl(cp.flags, sfFromGeneric)
+    cp.typ = newType(tyRef, iter)
+    rawAddSon(cp.typ, c.tup)
+    addHiddenParam(iter, cp)
+
+    c.state = createStateField(iter)
+    addField(c.tup, c.state)
+  else:
+    c.tup = cp.typ.sons[0]
+    assert c.tup.kind == tyTuple
+    if c.tup.len > 0:
+      c.state = c.tup.n[0].sym
+    else:
+      c.state = createStateField(iter)
+      addField(c.tup, c.state)
+
+  c.closureParam = cp
+  if iter.typ.sons[0] != nil:
+    c.resultSym = newIterResult(iter)
+    #iter.ast.add(newSymNode(c.resultSym))
+
 proc newOuterContext(fn: PSym, up: POuterContext = nil): POuterContext =
   new(result)
   result.fn = fn
@@ -144,12 +231,14 @@ proc newOuterContext(fn: PSym, up: POuterContext = nil): POuterContext =
   initIdNodeTable(result.localsToAccess)
   initIdTable(result.localsToEnv)
   initIdTable(result.lambdasToEnv)
+  result.isIter = fn.kind == skIterator and fn.typ.callConv == ccClosure
+  if result.isIter: initIterContext(result, fn)
   
 proc newInnerContext(fn: PSym): PInnerContext =
   new(result)
   result.fn = fn
   initIdNodeTable(result.localsToAccess)
-  
+
 proc newEnv(outerProc: PSym, up: PEnv, n: PNode): PEnv =
   new(result)
   result.deps = @[]
@@ -159,17 +248,12 @@ proc newEnv(outerProc: PSym, up: PEnv, n: PNode): PEnv =
   result.up = up
   result.attachedNode = n
 
-proc addField(tup: PType, s: PSym) =
-  var field = newSym(skField, s.name, s.owner, s.info)
-  let t = skipIntLit(s.typ)
-  field.typ = t
-  field.position = sonsLen(tup)
-  addSon(tup.n, newSymNode(field))
-  rawAddSon(tup, t)
-  
 proc addCapturedVar(e: PEnv, v: PSym) =
   for x in e.capturedVars:
     if x == v: return
+  # XXX meh, just add the state field for every closure for now, it's too
+  # hard to figure out if it comes from a closure iterator:
+  if e.tup.len == 0: addField(e.tup, createStateField(v.owner))
   e.capturedVars.add(v)
   addField(e.tup, v)
   
@@ -189,6 +273,7 @@ proc indirectAccess(a: PNode, b: PSym, info: TLineInfo): PNode =
   # returns a[].b as a node
   var deref = newNodeI(nkHiddenDeref, info)
   deref.typ = a.typ.sons[0]
+  assert deref.typ.kind == tyTuple
   let field = getSymFromList(deref.typ.n, b.name)
   assert field != nil, b.name.s
   addSon(deref, a)
@@ -205,33 +290,24 @@ proc newCall(a, b: PSym): PNode =
   result.add newSymNode(a)
   result.add newSymNode(b)
 
-proc addHiddenParam(routine: PSym, param: PSym) =
-  var params = routine.ast.sons[paramsPos]
-  # -1 is correct here as param.position is 0 based but we have at position 0
-  # some nkEffect node:
-  param.position = params.len-1
-  addSon(params, newSymNode(param))
-  incl(routine.typ.flags, tfCapturesEnv)
-  #echo "produced environment: ", param.id, " for ", routine.name.s
-
-proc getHiddenParam(routine: PSym): PSym =
-  let params = routine.ast.sons[paramsPos]
-  let hidden = lastSon(params)
-  assert hidden.kind == nkSym
-  result = hidden.sym
-
 proc isInnerProc(s, outerProc: PSym): bool {.inline.} =
-  result = s.kind in {skProc, skMethod, skConverter} and 
+  result = (s.kind in {skProc, skMethod, skConverter} or
+            s.kind == skIterator and s.typ.callConv == ccClosure) and
            s.skipGenericOwner == outerProc
   #s.typ.callConv == ccClosure
 
 proc addClosureParam(i: PInnerContext, e: PEnv) =
-  var cp = newSym(skParam, getIdent(paramName), i.fn, i.fn.info)
-  incl(cp.flags, sfFromGeneric)
-  cp.typ = newType(tyRef, i.fn)
-  rawAddSon(cp.typ, e.tup)
+  var cp = getEnvParam(i.fn)
+  if cp == nil:
+    cp = newSym(skParam, getIdent(paramName), i.fn, i.fn.info)
+    incl(cp.flags, sfFromGeneric)
+    cp.typ = newType(tyRef, i.fn)
+    rawAddSon(cp.typ, e.tup)
+    addHiddenParam(i.fn, cp)
+  else:
+    e.tup = cp.typ.sons[0]
+    assert e.tup.kind == tyTuple
   i.closureParam = cp
-  addHiddenParam(i.fn, i.closureParam)
   #echo "closure param added for ", i.fn.name.s, " ", i.fn.id
 
 proc dummyClosureParam(o: POuterContext, i: PInnerContext) =
@@ -306,7 +382,9 @@ proc gatherVars(o: POuterContext, i: PInnerContext, n: PNode) =
     var s = n.sym
     if interestingVar(s) and i.fn.id != s.owner.id:
       captureVar(o, i, s, n.info)
-    elif isInnerProc(s, o.fn) and tfCapturesEnv in s.typ.flags and s != i.fn:
+    elif s.kind in {skProc, skMethod, skConverter} and
+            s.skipGenericOwner == o.fn and 
+            tfCapturesEnv in s.typ.flags and s != i.fn:
       # call to some other inner proc; we need to track the dependencies for
       # this:
       let env = PEnv(idTableGet(o.lambdasToEnv, i.fn))
@@ -314,7 +392,7 @@ proc gatherVars(o: POuterContext, i: PInnerContext, n: PNode) =
       if o.currentEnv != env:
         discard addDep(o.currentEnv, env, i.fn)
         internalError(n.info, "too complex environment handling required")
-  of nkEmpty..pred(nkSym), succ(nkSym)..nkNilLit: discard
+  of nkEmpty..pred(nkSym), succ(nkSym)..nkNilLit, nkClosure: discard
   else:
     for k in countup(0, sonsLen(n) - 1): 
       gatherVars(o, i, n.sons[k])
@@ -366,10 +444,11 @@ proc transformInnerProc(o: POuterContext, i: PInnerContext, n: PNode): PNode =
     else:
       # captured symbol?
       result = idNodeTableGet(i.localsToAccess, n.sym)
-  of nkLambdaKinds:
-    result = transformInnerProc(o, i, n.sons[namePos])
+  of nkLambdaKinds, nkIteratorDef:
+    if n.typ != nil:
+      result = transformInnerProc(o, i, n.sons[namePos])
   of nkProcDef, nkMethodDef, nkConverterDef, nkMacroDef, nkTemplateDef,
-     nkIteratorDef:
+      nkClosure:
     # don't recurse here:
     discard
   else:
@@ -400,8 +479,9 @@ proc searchForInnerProcs(o: POuterContext, n: PNode) =
       if inner.closureParam != nil:
         let ti = transformInnerProc(o, inner, body)
         if ti != nil: n.sym.ast.sons[bodyPos] = ti
-  of nkLambdaKinds:
-    searchForInnerProcs(o, n.sons[namePos])
+  of nkLambdaKinds, nkIteratorDef:
+    if n.typ != nil:
+      searchForInnerProcs(o, n.sons[namePos])
   of nkWhileStmt, nkForStmt, nkParForStmt, nkBlockStmt:
     # some nodes open a new scope, so they are candidates for the insertion
     # of closure creation; however for simplicity we merge closures between
@@ -438,7 +518,7 @@ proc searchForInnerProcs(o: POuterContext, n: PNode) =
       else:
         internalError(it.info, "transformOuter")
   of nkProcDef, nkMethodDef, nkConverterDef, nkMacroDef, nkTemplateDef, 
-     nkIteratorDef:
+     nkClosure:
     # don't recurse here:
     # XXX recurse here and setup 'up' pointers
     discard
@@ -463,19 +543,20 @@ proc addVar*(father, v: PNode) =
   addSon(vpart, ast.emptyNode)
   addSon(father, vpart)
 
-proc getClosureVar(o: POuterContext, e: PEnv): PSym =
-  if e.closure == nil:
-    result = newSym(skVar, getIdent(envName), o.fn, e.attachedNode.info)
-    incl(result.flags, sfShadowed)
-    result.typ = newType(tyRef, o.fn)
-    result.typ.rawAddSon(e.tup)
-    e.closure = result
-  else:
-    result = e.closure
+proc newClosureCreationVar(o: POuterContext; e: PEnv): PSym =
+  result = newSym(skVar, getIdent(envName), o.fn, e.attachedNode.info)
+  incl(result.flags, sfShadowed)
+  result.typ = newType(tyRef, o.fn)
+  result.typ.rawAddSon(e.tup)
 
-proc generateClosureCreation(o: POuterContext, scope: PEnv): PNode =
-  var env = getClosureVar(o, scope)
+proc getClosureVar(o: POuterContext; e: PEnv): PSym =
+  if e.createdVar == nil:
+    result = newClosureCreationVar(o, e)
+    e.createdVar = result
+  else:
+    result = e.createdVar
 
+proc rawClosureCreation(o: POuterContext, scope: PEnv; env: PSym): PNode =
   result = newNodeI(nkStmtList, env.info)
   var v = newNodeI(nkVarSection, env.info)
   addVar(v, newSymNode(env))
@@ -496,6 +577,65 @@ proc generateClosureCreation(o: POuterContext, scope: PEnv): PNode =
     # add ``env.up = env2``
     result.add(newAsgnStmt(indirectAccess(env, field, env.info),
                newSymNode(getClosureVar(o, e)), env.info))
+  
+proc generateClosureCreation(o: POuterContext, scope: PEnv): PNode =
+  var env = getClosureVar(o, scope)
+  result = rawClosureCreation(o, scope, env)
+
+proc generateIterClosureCreation(o: POuterContext; env: PEnv;
+                                 scope: PNode): PSym =
+  result = newClosureCreationVar(o, env)
+  let cc = rawClosureCreation(o, env, result)
+  var insertPoint = scope.sons[0]
+  if insertPoint.kind == nkEmpty: scope.sons[0] = cc
+  else:
+    assert cc.kind == nkStmtList and insertPoint.kind == nkStmtList
+    for x in cc: insertPoint.add(x)
+  if env.createdVar == nil: env.createdVar = result
+
+proc interestingIterVar(s: PSym): bool {.inline.} =
+  result = s.kind in {skVar, skLet, skTemp, skForVar} and sfGlobal notin s.flags
+
+proc transformOuterProc(o: POuterContext, n: PNode): PNode
+
+proc transformYield(c: POuterContext, n: PNode): PNode =
+  inc c.state.typ.n.sons[1].intVal
+  let stateNo = c.state.typ.n.sons[1].intVal
+
+  var stateAsgnStmt = newNodeI(nkAsgn, n.info)
+  stateAsgnStmt.add(indirectAccess(newSymNode(c.closureParam),c.state,n.info))
+  stateAsgnStmt.add(newIntTypeNode(nkIntLit, stateNo, getSysType(tyInt)))
+
+  var retStmt = newNodeI(nkReturnStmt, n.info)
+  if n.sons[0].kind != nkEmpty:
+    var a = newNodeI(nkAsgn, n.sons[0].info)
+    var retVal = transformOuterProc(c, n.sons[0])
+    addSon(a, newSymNode(c.resultSym))
+    addSon(a, if retVal.isNil: n.sons[0] else: retVal)
+    retStmt.add(a)
+  else:
+    retStmt.add(emptyNode)
+  
+  var stateLabelStmt = newNodeI(nkState, n.info)
+  stateLabelStmt.add(newIntTypeNode(nkIntLit, stateNo, getSysType(tyInt)))
+  
+  result = newNodeI(nkStmtList, n.info)
+  result.add(stateAsgnStmt)
+  result.add(retStmt)
+  result.add(stateLabelStmt)
+
+proc transformReturn(c: POuterContext, n: PNode): PNode =
+  result = newNodeI(nkStmtList, n.info)
+  var stateAsgnStmt = newNodeI(nkAsgn, n.info)
+  stateAsgnStmt.add(indirectAccess(newSymNode(c.closureParam),c.state,n.info))
+  stateAsgnStmt.add(newIntTypeNode(nkIntLit, -1, getSysType(tyInt)))
+  result.add(stateAsgnStmt)
+  result.add(n)
+
+proc outerProcSons(o: POuterContext, n: PNode) =
+  for i in countup(0, sonsLen(n) - 1):
+    let x = transformOuterProc(o, n.sons[i])
+    if x != nil: n.sons[i] = x
 
 proc transformOuterProc(o: POuterContext, n: PNode): PNode =
   if n == nil: return nil
@@ -503,10 +643,25 @@ proc transformOuterProc(o: POuterContext, n: PNode): PNode =
   of nkEmpty..pred(nkSym), succ(nkSym)..nkNilLit: discard
   of nkSym:
     var local = n.sym
+
+    if o.isIter and interestingIterVar(local) and o.fn.id == local.owner.id:
+      if not containsOrIncl(o.capturedVars, local.id): addField(o.tup, local)
+      return indirectAccess(newSymNode(o.closureParam), local, n.info)
+
     var closure = PEnv(idTableGet(o.lambdasToEnv, local))
     if closure != nil:
-      # we need to replace the lambda with '(lambda, env)': 
-      let a = closure.closure
+      # we need to replace the lambda with '(lambda, env)':
+      if local.kind == skIterator and local.typ.callConv == ccClosure:
+        # consider: [i1, i2, i1]  Since we merged the iterator's closure
+        # with the captured owning variables, we need to generate the
+        # closure generation code again:
+        #if local == o.fn: message(n.info, errRecursiveDependencyX, local.name.s)
+        # XXX why doesn't this work?
+        let createdVar = generateIterClosureCreation(o, closure,
+                                                     closure.attachedNode)
+        return makeClosure(local, createdVar, n.info)
+      
+      let a = closure.createdVar
       if a != nil:
         return makeClosure(local, a, n.info)
       else:
@@ -516,7 +671,7 @@ proc transformOuterProc(o: POuterContext, n: PNode): PNode =
         if scope.sons[0].kind == nkEmpty:
           # change the empty node to contain the closure construction:
           scope.sons[0] = generateClosureCreation(o, closure)
-        let x = closure.closure
+        let x = closure.createdVar
         assert x != nil
         return makeClosure(local, x, n.info)
     
@@ -535,20 +690,47 @@ proc transformOuterProc(o: POuterContext, n: PNode): PNode =
     assert result != nil, "cannot find: " & local.name.s
     # else it is captured by copy and this means that 'outer' should continue
     # to access the local as a local.
-  of nkLambdaKinds:
-    result = transformOuterProc(o, n.sons[namePos])
-  of nkProcDef, nkMethodDef, nkConverterDef, nkMacroDef, nkTemplateDef, 
-     nkIteratorDef: 
+  of nkLambdaKinds, nkIteratorDef:
+    if n.typ != nil:
+      result = transformOuterProc(o, n.sons[namePos])
+  of nkProcDef, nkMethodDef, nkConverterDef, nkMacroDef, nkTemplateDef,
+      nkClosure:
     # don't recurse here:
     discard
   of nkHiddenStdConv, nkHiddenSubConv, nkConv:
     let x = transformOuterProc(o, n.sons[1])
     if x != nil: n.sons[1] = x
     result = transformOuterConv(n)
+  of nkYieldStmt:
+    if o.isIter: result = transformYield(o, n)
+    else: outerProcSons(o, n)
+  of nkReturnStmt:
+    if o.isIter: result = transformReturn(o, n)
+    else: outerProcSons(o, n)
   else:
-    for i in countup(0, sonsLen(n) - 1):
-      let x = transformOuterProc(o, n.sons[i])
-      if x != nil: n.sons[i] = x
+    outerProcSons(o, n)
+
+proc liftIterator(c: POuterContext, body: PNode): PNode =
+  let iter = c.fn
+  result = newNodeI(nkStmtList, iter.info)
+  var gs = newNodeI(nkGotoState, iter.info)
+  gs.add(indirectAccess(newSymNode(c.closureParam), c.state, iter.info))
+  result.add(gs)
+  var state0 = newNodeI(nkState, iter.info)
+  state0.add(newIntNode(nkIntLit, 0))
+  result.add(state0)
+  
+  let newBody = transformOuterProc(c, body)
+  if newBody != nil:
+    result.add(newBody)
+  else:
+    result.add(body)
+
+  var stateAsgnStmt = newNodeI(nkAsgn, iter.info)
+  stateAsgnStmt.add(indirectAccess(newSymNode(c.closureParam),
+                    c.state,iter.info))
+  stateAsgnStmt.add(newIntTypeNode(nkIntLit, -1, getSysType(tyInt)))
+  result.add(stateAsgnStmt)
 
 proc liftLambdas*(fn: PSym, body: PNode): PNode =
   # XXX gCmd == cmdCompileToJS does not suffice! The compiletime stuff needs
@@ -572,8 +754,11 @@ proc liftLambdas*(fn: PSym, body: PNode): PNode =
     if resultPos < sonsLen(ast) and ast.sons[resultPos].kind == nkSym:
       idTablePut(o.localsToEnv, ast.sons[resultPos].sym, o.currentEnv)
     searchForInnerProcs(o, body)
-    discard transformOuterProc(o, body)
-    result = ex
+    if o.isIter:
+      result = liftIterator(o, ex)
+    else:
+      discard transformOuterProc(o, body)
+      result = ex
 
 proc liftLambdasForTopLevel*(module: PSym, body: PNode): PNode =
   if body.kind == nkEmpty or gCmd == cmdCompileToJS:
@@ -588,140 +773,15 @@ proc liftLambdasForTopLevel*(module: PSym, body: PNode): PNode =
 
 # ------------------- iterator transformation --------------------------------
 
-discard """
-  iterator chain[S, T](a, b: *S->T, args: *S): T =
-    for x in a(args): yield x
-    for x in b(args): yield x
-
-  let c = chain(f, g)
-  for x in c: echo x
-  
-  # translated to:
-  let c = chain( (f, newClosure(f)), (g, newClosure(g)), newClosure(chain))
-"""
-
-type
-  TIterContext {.final, pure.} = object
-    iter, closureParam, state, resultSym: PSym
-    capturedVars: TIntSet
-    tup: PType
-
-proc newIterResult(iter: PSym): PSym =
-  result = iter.ast.sons[resultPos].sym
-  when false:
-    result = newSym(skResult, getIdent":result", iter, iter.info)
-    result.typ = iter.typ.sons[0]
-    incl(result.flags, sfUsed)
-
-proc interestingIterVar(s: PSym): bool {.inline.} =
-  result = s.kind in {skVar, skLet, skTemp, skForVar} and sfGlobal notin s.flags
-
-proc transfIterBody(c: var TIterContext, n: PNode): PNode =
-  # gather used vars for closure generation
-  if n == nil: return nil
-  case n.kind
-  of nkSym:
-    var s = n.sym
-    if interestingIterVar(s) and c.iter.id == s.owner.id:
-      if not containsOrIncl(c.capturedVars, s.id): addField(c.tup, s)
-      result = indirectAccess(newSymNode(c.closureParam), s, n.info)
-  of nkEmpty..pred(nkSym), succ(nkSym)..nkNilLit: discard
-  of nkYieldStmt:
-    inc c.state.typ.n.sons[1].intVal
-    let stateNo = c.state.typ.n.sons[1].intVal
-
-    var stateAsgnStmt = newNodeI(nkAsgn, n.info)
-    stateAsgnStmt.add(indirectAccess(newSymNode(c.closureParam),c.state,n.info))
-    stateAsgnStmt.add(newIntTypeNode(nkIntLit, stateNo, getSysType(tyInt)))
-
-    var retStmt = newNodeI(nkReturnStmt, n.info)
-    if n.sons[0].kind != nkEmpty:
-      var a = newNodeI(nkAsgn, n.sons[0].info)
-      var retVal = transfIterBody(c, n.sons[0])
-      addSon(a, newSymNode(c.resultSym))
-      addSon(a, if retVal.isNil: n.sons[0] else: retVal)
-      retStmt.add(a)
-    else:
-      retStmt.add(emptyNode)
-    
-    var stateLabelStmt = newNodeI(nkState, n.info)
-    stateLabelStmt.add(newIntTypeNode(nkIntLit, stateNo, getSysType(tyInt)))
-    
-    result = newNodeI(nkStmtList, n.info)
-    result.add(stateAsgnStmt)
-    result.add(retStmt)
-    result.add(stateLabelStmt)
-  of nkReturnStmt:
-    result = newNodeI(nkStmtList, n.info)
-    var stateAsgnStmt = newNodeI(nkAsgn, n.info)
-    stateAsgnStmt.add(indirectAccess(newSymNode(c.closureParam),c.state,n.info))
-    stateAsgnStmt.add(newIntTypeNode(nkIntLit, -1, getSysType(tyInt)))
-    result.add(stateAsgnStmt)
-    result.add(n)
-  else:
-    for i in countup(0, sonsLen(n)-1):
-      let x = transfIterBody(c, n.sons[i])
-      if x != nil: n.sons[i] = x
-
-proc getStateType(iter: PSym): PType =
-  var n = newNodeI(nkRange, iter.info)
-  addSon(n, newIntNode(nkIntLit, -1))
-  addSon(n, newIntNode(nkIntLit, 0))
-  result = newType(tyRange, iter)
-  result.n = n
-  rawAddSon(result, getSysType(tyInt))
-
-proc liftIterator*(iter: PSym, body: PNode): PNode =
-  var c: TIterContext
-  c.iter = iter
-  c.capturedVars = initIntSet()
-
-  c.tup = newType(tyTuple, iter)
-  c.tup.n = newNodeI(nkRecList, iter.info)
-
-  var cp = newSym(skParam, getIdent(paramName), iter, iter.info)
-  incl(cp.flags, sfFromGeneric)
-  cp.typ = newType(tyRef, iter)
-  rawAddSon(cp.typ, c.tup)
-  c.closureParam = cp
-  addHiddenParam(iter, cp)
-
-  c.state = newSym(skField, getIdent(":state"), iter, iter.info)
-  c.state.typ = getStateType(iter)
-  addField(c.tup, c.state)
-
-  if iter.typ.sons[0] != nil:
-    c.resultSym = newIterResult(iter)
-    iter.ast.add(newSymNode(c.resultSym))
-
-  result = newNodeI(nkStmtList, iter.info)
-  var gs = newNodeI(nkGotoState, iter.info)
-  gs.add(indirectAccess(newSymNode(c.closureParam), c.state, iter.info))
-  result.add(gs)
-  var state0 = newNodeI(nkState, iter.info)
-  state0.add(newIntNode(nkIntLit, 0))
-  result.add(state0)
-  
-  let newBody = transfIterBody(c, body)
-  if newBody != nil:
-    result.add(newBody)
-  else:
-    result.add(body)
-
-  var stateAsgnStmt = newNodeI(nkAsgn, iter.info)
-  stateAsgnStmt.add(indirectAccess(newSymNode(c.closureParam),
-                    c.state,iter.info))
-  stateAsgnStmt.add(newIntTypeNode(nkIntLit, -1, getSysType(tyInt)))
-  result.add(stateAsgnStmt)
-
 proc liftIterSym*(n: PNode): PNode =
   # transforms  (iter)  to  (let env = newClosure[iter](); (iter, env)) 
-  result = newNodeIT(nkStmtListExpr, n.info, n.typ)
   let iter = n.sym
   assert iter.kind == skIterator
+
+  result = newNodeIT(nkStmtListExpr, n.info, n.typ)
+  
   var env = copySym(getHiddenParam(iter))
   env.kind = skLet
-
   var v = newNodeI(nkVarSection, n.info)
   addVar(v, newSymNode(env))
   result.add(v)
@@ -766,7 +826,7 @@ proc liftForLoop*(body: PNode): PNode =
   # static binding?
   var env: PSym
   if call[0].kind == nkSym and call[0].sym.kind == skIterator:
-    # createClose()
+    # createClosure()
     let iter = call[0].sym
     assert iter.kind == skIterator
     env = copySym(getHiddenParam(iter))
diff --git a/compiler/lexer.nim b/compiler/lexer.nim
index 97414ddb7..0e7df13cd 100644
--- a/compiler/lexer.nim
+++ b/compiler/lexer.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.
diff --git a/compiler/parser.nim b/compiler/parser.nim
index c44036c5f..3765557b9 100644
--- a/compiler/parser.nim
+++ b/compiler/parser.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.
@@ -18,10 +18,10 @@
 # In fact the grammar is generated from this file:
 when isMainModule:
   import pegs
-  var outp = open("compiler/grammar.txt", fmWrite)
+  var outp = open("doc/grammar.txt", fmWrite)
   for line in lines("compiler/parser.nim"):
     if line =~ peg" \s* '#| ' {.*}":
-      outp.writeln matches[0]
+      outp.write matches[0], "\L"
   outp.close
 
 import
@@ -31,9 +31,10 @@ type
   TParser*{.final.} = object  # a TParser object represents a module that
                               # is being parsed
     currInd: int              # current indentation
-    firstTok: bool
+    firstTok, strongSpaces: bool
     lex*: TLexer              # the lexer that is used for parsing
     tok*: TToken              # the current token
+    inPragma: int
 
 proc parseAll*(p: var TParser): PNode
 proc openParser*(p: var TParser, filename: string, inputstream: PLLStream)
@@ -518,14 +519,14 @@ proc parsePar(p: var TParser): PNode =
   eat(p, tkParRi)
 
 proc identOrLiteral(p: var TParser, mode: TPrimaryMode): PNode = 
+  #| literal = | INT_LIT | INT8_LIT | INT16_LIT | INT32_LIT | INT64_LIT
+  #|           | UINT_LIT | UINT8_LIT | UINT16_LIT | UINT32_LIT | UINT64_LIT
+  #|           | FLOAT_LIT | FLOAT32_LIT | FLOAT64_LIT
+  #|           | STR_LIT | RSTR_LIT | TRIPLESTR_LIT
+  #|           | CHAR_LIT
+  #|           | NIL
   #| generalizedLit = GENERALIZED_STR_LIT | GENERALIZED_TRIPLESTR_LIT
-  #| identOrLiteral = generalizedLit | symbol 
-  #|                | INT_LIT | INT8_LIT | INT16_LIT | INT32_LIT | INT64_LIT
-  #|                | UINT_LIT | UINT8_LIT | UINT16_LIT | UINT32_LIT | UINT64_LIT
-  #|                | FLOAT_LIT | FLOAT32_LIT | FLOAT64_LIT
-  #|                | STR_LIT | RSTR_LIT | TRIPLESTR_LIT
-  #|                | CHAR_LIT
-  #|                | NIL
+  #| identOrLiteral = generalizedLit | symbol | literal
   #|                | par | arrayConstr | setOrTableConstr
   #|                | castExpr
   #| tupleConstr = '(' optInd (exprColonEqExpr comma?)* optPar ')'
@@ -634,12 +635,15 @@ proc namedParams(p: var TParser, callee: PNode,
   addSon(result, a)
   exprColonEqExprListAux(p, endTok, result)
 
+proc parseMacroColon(p: var TParser, x: PNode): PNode
 proc primarySuffix(p: var TParser, r: PNode): PNode =
   #| primarySuffix = '(' (exprColonEqExpr comma?)* ')' doBlocks?
   #|               | doBlocks
   #|               | '.' optInd ('type' | 'addr' | symbol) generalizedLit?
   #|               | '[' optInd indexExprList optPar ']'
   #|               | '{' optInd indexExprList optPar '}'
+  #|               | &( '`'|IDENT|literal|'cast') expr ^+ ',' # command syntax
+  #|                      (doBlock | macroColon)?
   result = r
   while p.tok.indent < 0:
     case p.tok.tokType
@@ -661,8 +665,27 @@ proc primarySuffix(p: var TParser, r: PNode): PNode =
       result = namedParams(p, result, nkBracketExpr, tkBracketRi)
     of tkCurlyLe:
       result = namedParams(p, result, nkCurlyExpr, tkCurlyRi)
-    else: break
-
+    of tkSymbol, tkAccent, tkIntLit..tkCharLit, tkNil, tkCast:
+      if p.inPragma == 0:
+        # actually parsing {.push hints:off.} as {.push(hints:off).} is a sweet
+        # solution, but pragmas.nim can't handle that
+        let a = result
+        result = newNodeP(nkCommand, p)
+        addSon(result, a)
+        while p.tok.tokType != tkEof:
+          let a = parseExpr(p)
+          addSon(result, a)
+          if p.tok.tokType != tkComma: break
+          getTok(p)
+          optInd(p, a)
+        if p.tok.tokType == tkDo:
+          parseDoBlocks(p, result)
+        else:
+          result = parseMacroColon(p, result)
+      break
+    else:
+      break
+    
 proc primary(p: var TParser, mode: TPrimaryMode): PNode
 
 proc simpleExprAux(p: var TParser, limit: int, mode: TPrimaryMode): PNode =
@@ -713,6 +736,7 @@ proc parseIfExpr(p: var TParser, kind: TNodeKind): PNode =
 proc parsePragma(p: var TParser): PNode =
   #| pragma = '{.' optInd (exprColonExpr comma?)* optPar ('.}' | '}')
   result = newNodeP(nkPragma, p)
+  inc p.inPragma
   getTok(p)
   optInd(p, result)
   while p.tok.tokType notin {tkCurlyDotRi, tkCurlyRi, tkEof}:
@@ -724,6 +748,7 @@ proc parsePragma(p: var TParser): PNode =
   optPar(p)
   if p.tok.tokType in {tkCurlyDotRi, tkCurlyRi}: getTok(p)
   else: parMessage(p, errTokenExpected, ".}")
+  dec p.inPragma
   
 proc identVis(p: var TParser): PNode = 
   #| identVis = symbol opr?  # postfix position
@@ -965,7 +990,7 @@ proc primary(p: var TParser, mode: TPrimaryMode): PNode =
   of tkTuple: result = parseTuple(p, mode == pmTypeDef)
   of tkProc: result = parseProcExpr(p, mode notin {pmTypeDesc, pmTypeDef})
   of tkIterator:
-    when true:
+    when false:
       if mode in {pmTypeDesc, pmTypeDef}:
         result = parseProcExpr(p, false)
         result.kind = nkIteratorTy
@@ -976,7 +1001,8 @@ proc primary(p: var TParser, mode: TPrimaryMode): PNode =
         result = ast.emptyNode
     else:
       result = parseProcExpr(p, mode notin {pmTypeDesc, pmTypeDef})
-      result.kind = nkIteratorTy
+      if result.kind == nkLambda: result.kind = nkIteratorDef
+      else: result.kind = nkIteratorTy
   of tkEnum:
     if mode == pmTypeDef:
       result = parseEnum(p)
@@ -1022,6 +1048,7 @@ proc parseTypeDesc(p: var TParser): PNode =
 
 proc parseTypeDefAux(p: var TParser): PNode = 
   #| typeDefAux = simpleExpr
+  #|            | 'generic' typeClass
   result = simpleExpr(p, pmTypeDef)
 
 proc makeCall(n: PNode): PNode =
@@ -1031,15 +1058,50 @@ proc makeCall(n: PNode): PNode =
     result = newNodeI(nkCall, n.info)
     result.add n
 
+proc parseMacroColon(p: var TParser, x: PNode): PNode =
+  #| macroColon = ':' stmt? ( IND{=} 'of' exprList ':' stmt 
+  #|                        | IND{=} 'elif' expr ':' stmt
+  #|                        | IND{=} 'except' exprList ':' stmt
+  #|                        | IND{=} 'else' ':' stmt )*
+  result = x
+  if p.tok.tokType == tkColon and p.tok.indent < 0:
+    result = makeCall(result)
+    getTok(p)
+    skipComment(p, result)
+    if p.tok.tokType notin {tkOf, tkElif, tkElse, tkExcept}:
+      let body = parseStmt(p)
+      addSon(result, newProcNode(nkDo, body.info, body))
+    while sameInd(p):
+      var b: PNode
+      case p.tok.tokType
+      of tkOf:
+        b = newNodeP(nkOfBranch, p)
+        exprList(p, tkColon, b)
+      of tkElif: 
+        b = newNodeP(nkElifBranch, p)
+        getTok(p)
+        optInd(p, b)
+        addSon(b, parseExpr(p))
+        eat(p, tkColon)
+      of tkExcept: 
+        b = newNodeP(nkExceptBranch, p)
+        exprList(p, tkColon, b)
+        skipComment(p, b)
+      of tkElse: 
+        b = newNodeP(nkElse, p)
+        getTok(p)
+        eat(p, tkColon)
+      else: break 
+      addSon(b, parseStmt(p))
+      addSon(result, b)
+      if b.kind == nkElse: break
+
 proc parseExprStmt(p: var TParser): PNode = 
   #| exprStmt = simpleExpr
   #|          (( '=' optInd expr )
   #|          / ( expr ^+ comma
   #|              doBlocks
-  #|               / ':' stmt? ( IND{=} 'of' exprList ':' stmt 
-  #|                           | IND{=} 'elif' expr ':' stmt
-  #|                           | IND{=} 'except' exprList ':' stmt
-  #|                           | IND{=} 'else' ':' stmt )*
+  #|               / macroColon
   #|            ))?
   var a = simpleExpr(p)
   if p.tok.tokType == tkEquals: 
@@ -1064,37 +1126,7 @@ proc parseExprStmt(p: var TParser): PNode =
       result = makeCall(result)
       parseDoBlocks(p, result)
       return result
-    if p.tok.tokType == tkColon and p.tok.indent < 0:
-      result = makeCall(result)
-      getTok(p)
-      skipComment(p, result)
-      if p.tok.tokType notin {tkOf, tkElif, tkElse, tkExcept}:
-        let body = parseStmt(p)
-        addSon(result, newProcNode(nkDo, body.info, body))
-      while sameInd(p):
-        var b: PNode
-        case p.tok.tokType
-        of tkOf:
-          b = newNodeP(nkOfBranch, p)
-          exprList(p, tkColon, b)
-        of tkElif: 
-          b = newNodeP(nkElifBranch, p)
-          getTok(p)
-          optInd(p, b)
-          addSon(b, parseExpr(p))
-          eat(p, tkColon)
-        of tkExcept: 
-          b = newNodeP(nkExceptBranch, p)
-          exprList(p, tkColon, b)
-          skipComment(p, b)
-        of tkElse: 
-          b = newNodeP(nkElse, p)
-          getTok(p)
-          eat(p, tkColon)
-        else: break 
-        addSon(b, parseStmt(p))
-        addSon(result, b)
-        if b.kind == nkElse: break
+    result = parseMacroColon(p, result)
 
 proc parseModuleName(p: var TParser, kind: TNodeKind): PNode =
   result = parseExpr(p)
@@ -1177,8 +1209,7 @@ proc parseReturnOrRaise(p: var TParser, kind: TNodeKind): PNode =
   if p.tok.tokType == tkComment:
     skipComment(p, result)
     addSon(result, ast.emptyNode)
-  elif p.tok.indent >= 0 and p.tok.indent <= p.currInd or
-      p.tok.tokType == tkEof:
+  elif p.tok.indent >= 0 and p.tok.indent <= p.currInd or not isExprStart(p):
     # NL terminates:
     addSon(result, ast.emptyNode)
   else:
@@ -1641,6 +1672,9 @@ proc parseTypeClassParam(p: var TParser): PNode =
     result = p.parseSymbol
 
 proc parseTypeClass(p: var TParser): PNode =
+  #| typeClassParam = ('var')? symbol
+  #| typeClass = typeClassParam ^* ',' (pragma)? ('of' typeDesc ^* ',')?
+  #|               &IND{>} stmt
   result = newNodeP(nkTypeClassTy, p)
   getTok(p)
   var args = newNode(nkArgList)
diff --git a/compiler/renderer.nim b/compiler/renderer.nim
index b5e3c0e74..1afb5961e 100644
--- a/compiler/renderer.nim
+++ b/compiler/renderer.nim
@@ -426,6 +426,8 @@ proc lsub(n: PNode): int =
   of nkVarTy: result = (if n.len > 0: lsub(n.sons[0])+1 else: 0) + len("var")
   of nkDistinctTy: result = (if n.len > 0: lsub(n.sons[0])+1 else: 0) +
                                                          len("Distinct")
+  of nkStaticTy: result = (if n.len > 0: lsub(n.sons[0]) else: 0) +
+                                                         len("static[]")
   of nkTypeDef: result = lsons(n) + 3
   of nkOfInherit: result = lsub(n.sons[0]) + len("of_")
   of nkProcTy: result = lsons(n) + len("proc_")
@@ -701,6 +703,19 @@ proc gproc(g: var TSrcGen, n: PNode) =
       gcoms(g)
       dedent(g)
 
+proc gTypeClassTy(g: var TSrcGen, n: PNode) =
+  var c: TContext
+  initContext(c)
+  putWithSpace(g, tkGeneric, "generic")
+  gsons(g, n[0], c) # arglist
+  gsub(g, n[1]) # pragmas
+  gsub(g, n[2]) # of
+  gcoms(g)
+  indentNL(g)
+  gcoms(g)
+  gstmts(g, n[3], c)
+  dedent(g)
+
 proc gblock(g: var TSrcGen, n: PNode) = 
   var c: TContext
   initContext(c)
@@ -1054,6 +1069,12 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
       gsub(g, n.sons[0])
     else:
       put(g, tkShared, "shared")
+  of nkStaticTy:
+    put(g, tkStatic, "static")
+    put(g, tkBracketLe, "[")
+    if n.len > 0:
+      gsub(g, n.sons[0])
+    put(g, tkBracketRi, "]")    
   of nkEnumTy:
     if sonsLen(n) > 0:
       putWithSpace(g, tkEnum, "enum")
@@ -1251,6 +1272,13 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
     put(g, tkParLe, "(META|")
     gsub(g, n.sons[0])
     put(g, tkParRi, ")")
+  of nkGotoState, nkState:
+    var c: TContext
+    initContext c
+    putWithSpace g, tkSymbol, if n.kind == nkState: "state" else: "goto"
+    gsons(g, n, c)
+  of nkTypeClassTy:
+    gTypeClassTy(g, n)
   else: 
     #nkNone, nkExplicitTypeListCall: 
     internalError(n.info, "rnimsyn.gsub(" & $n.kind & ')')
diff --git a/compiler/semdestruct.nim b/compiler/semdestruct.nim
index 9dbbf2940..fb05826cb 100644
--- a/compiler/semdestruct.nim
+++ b/compiler/semdestruct.nim
@@ -116,7 +116,10 @@ proc generateDestructor(c: PContext, t: PType): PNode =
       let stmt = destroyField(c, t.n.sons[s].sym, destructedObj)
       if stmt != nil: addLine(stmt)
     else:
-      internalAssert false
+      # XXX just skip it for now so that the compiler doesn't crash, but
+      # please zahary fix it! arbitrary nesting of nkRecList/nkRecCase is
+      # possible. Any thread example seems to trigger this. 
+      discard
   # base classes' destructors will be automatically called by
   # semProcAux for both auto-generated and user-defined destructors
 
diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim
index 6e2d777fb..84303b6cd 100644
--- a/compiler/semexprs.nim
+++ b/compiler/semexprs.nim
@@ -239,7 +239,8 @@ proc semLowHigh(c: PContext, n: PNode, m: TMagic): PNode =
     localError(n.info, errXExpectsTypeOrValue, opToStr[m])
   else: 
     n.sons[1] = semExprWithType(c, n.sons[1], {efDetermineType})
-    var typ = skipTypes(n.sons[1].typ, abstractVarRange+{tyTypeDesc})
+    var typ = skipTypes(n.sons[1].typ, abstractVarRange +
+                                       {tyTypeDesc, tyFieldAccessor})
     case typ.kind
     of tySequence, tyString, tyOpenArray, tyVarargs: 
       n.typ = getSysType(tyInt)
@@ -247,7 +248,7 @@ proc semLowHigh(c: PContext, n: PNode, m: TMagic): PNode =
       n.typ = typ.sons[0] # indextype
     of tyInt..tyInt64, tyChar, tyBool, tyEnum, tyUInt8, tyUInt16, tyUInt32: 
       # do not skip the range!
-      n.typ = n.sons[1].typ.skipTypes(abstractVar)
+      n.typ = n.sons[1].typ.skipTypes(abstractVar + {tyFieldAccessor})
     of tyGenericParam:
       # prepare this for resolving in semtypinst:
       # we must use copyTree here in order to avoid creating a cycle
@@ -306,7 +307,7 @@ proc isOpImpl(c: PContext, n: PNode): PNode =
     n[1].typ != nil and n[1].typ.kind == tyTypeDesc and
     n[2].kind in {nkStrLit..nkTripleStrLit, nkType}
   
-  let t1 = n[1].typ.skipTypes({tyTypeDesc})
+  let t1 = n[1].typ.skipTypes({tyTypeDesc, tyFieldAccessor})
 
   if n[2].kind in {nkStrLit..nkTripleStrLit}:
     case n[2].strVal.normalize
@@ -321,24 +322,13 @@ proc isOpImpl(c: PContext, n: PNode): PNode =
                                         t.callConv == ccClosure and 
                                         tfIterator in t.flags))
   else:
-    var match: bool
-    let t2 = n[2].typ
-    case t2.kind
-    of tyTypeClasses:
-      var m: TCandidate
-      initCandidate(c, m, t2)
-      match = matchUserTypeClass(c, m, emptyNode, t2, t1) != nil
-    of tyOrdinal:
-      var m: TCandidate
-      initCandidate(c, m, t2)
-      match = isOrdinalType(t1)
-    of tySequence, tyArray, tySet:
-      var m: TCandidate
-      initCandidate(c, m, t2)
-      match = typeRel(m, t2, t1) != isNone
-    else:
-      match = sameType(t1, t2)
- 
+    var t2 = n[2].typ.skipTypes({tyTypeDesc})
+    let lifted = liftParamType(c, skType, newNodeI(nkArgList, n.info),
+                               t2, ":anon", n.info)
+    if lifted != nil: t2 = lifted
+    var m: TCandidate
+    initCandidate(c, m, t2)
+    let match = typeRel(m, t2, t1) != isNone
     result = newIntNode(nkIntLit, ord(match))
 
   result.typ = n.typ
@@ -948,6 +938,13 @@ proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode =
             let foundTyp = makeTypeDesc(c, rawTyp)
             return newSymNode(copySym(tParam.sym).linkTo(foundTyp), n.info)
       return
+    of tyObject, tyTuple:
+      if ty.n.kind == nkRecList:
+        for field in ty.n.sons:
+          if field.sym.name == i:
+            n.typ = newTypeWithSons(c, tyFieldAccessor, @[ty, field.sym.typ])
+            n.typ.n = copyTree(n)
+            return n
     else:
       # echo "TYPE FIELD ACCESS"
       # debug ty
diff --git a/compiler/semfold.nim b/compiler/semfold.nim
index 78e5cdd5e..4740ddcb3 100644
--- a/compiler/semfold.nim
+++ b/compiler/semfold.nim
@@ -252,8 +252,7 @@ proc evalIs(n, a: PNode): PNode =
   else:
     # XXX semexprs.isOpImpl is slightly different and requires a context. yay.
     let t2 = n[2].typ
-    var match = if t2.kind == tyTypeClass: true
-                else: sameType(t1, t2)
+    var match = sameType(t1, t2)
     result = newIntNode(nkIntLit, ord(match))
   result.typ = n.typ
 
diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim
index 1aa6a793c..caa719c7e 100644
--- a/compiler/semstmts.nim
+++ b/compiler/semstmts.nim
@@ -868,6 +868,8 @@ proc semProcAnnotation(c: PContext, prc: PNode): PNode =
     return semStmt(c, x)
 
 proc semLambda(c: PContext, n: PNode, flags: TExprFlags): PNode =
+  # XXX semProcAux should be good enough for this now, we will eventually
+  # remove semLambda
   result = semProcAnnotation(c, n)
   if result != nil: return result
   result = n
@@ -922,7 +924,7 @@ proc activate(c: PContext, n: PNode) =
     of nkCallKinds:
       for i in 1 .. <n.len: activate(c, n[i])
     else:
-      nil
+      discard
 
 proc maybeAddResult(c: PContext, s: PSym, n: PNode) =
   if s.typ.sons[0] != nil and
@@ -949,9 +951,15 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
   checkSonsLen(n, bodyPos + 1)
   var s: PSym
   var typeIsDetermined = false
+  var isAnon = false
   if n[namePos].kind != nkSym:
     assert phase == stepRegisterSymbol
-    s = semIdentDef(c, n.sons[0], kind)
+
+    if n[namePos].kind == nkEmpty:
+      s = newSym(kind, idAnon, getCurrOwner(), n.info)
+      isAnon = true
+    else:
+      s = semIdentDef(c, n.sons[0], kind)
     n.sons[namePos] = newSymNode(s)
     s.ast = n
     s.scope = c.currentScope
@@ -992,11 +1000,13 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
     rawAddSon(s.typ, nil)
   if n.sons[patternPos].kind != nkEmpty:
     n.sons[patternPos] = semPattern(c, n.sons[patternPos])
-  if s.kind == skIterator: s.typ.flags.incl(tfIterator)
+  if s.kind == skIterator: 
+    s.typ.flags.incl(tfIterator)
   
   var proto = searchForProc(c, s.scope, s)
   if proto == nil: 
-    s.typ.callConv = lastOptionEntry(c).defaultCC
+    if s.kind == skIterator and isAnon: s.typ.callConv = ccClosure
+    else: s.typ.callConv = lastOptionEntry(c).defaultCC
     # add it here, so that recursive procs are possible:
     if sfGenSym in s.flags: discard
     elif kind in OverloadableSyms:
@@ -1074,6 +1084,7 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
   popOwner()
   if n.sons[patternPos].kind != nkEmpty:
     c.patterns.add(s)
+  if isAnon: result.typ = s.typ
 
 proc determineType(c: PContext, s: PSym) =
   if s.typ != nil: return
@@ -1236,7 +1247,7 @@ proc semStmtList(c: PContext, n: PNode): PNode =
       if n.sons[i].typ == enforceVoidContext or usesResult(n.sons[i]):
         voidContext = true
         n.typ = enforceVoidContext
-      if i != last or voidContext:
+      if i != last or voidContext or c.inTypeClass > 0:
         discardCheck(c, n.sons[i])
       else:
         n.typ = n.sons[i].typ
diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim
index d5a938a12..408b1b62e 100644
--- a/compiler/semtypes.nim
+++ b/compiler/semtypes.nim
@@ -710,6 +710,11 @@ proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode,
     result = addImplicitGeneric(result)
   
   of tyGenericInst:
+    if paramType.lastSon.kind == tyUserTypeClass:
+      var cp = copyType(paramType, getCurrOwner(), false)
+      cp.kind = tyUserTypeClassInst
+      return addImplicitGeneric(cp)
+
     for i in 1 .. (paramType.sons.len - 2):
       var lifted = liftingWalk(paramType.sons[i])
       if lifted != nil:
@@ -731,7 +736,7 @@ proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode,
                                         allowMetaTypes = true)
     result = liftingWalk(expanded)
 
-  of tyTypeClass, tyBuiltInTypeClass, tyAnd, tyOr, tyNot:
+  of tyUserTypeClass, tyBuiltInTypeClass, tyAnd, tyOr, tyNot:
     result = addImplicitGeneric(copyType(paramType, getCurrOwner(), true))
   
   of tyExpr:
@@ -866,7 +871,7 @@ proc semGenericParamInInvokation(c: PContext, n: PNode): PType =
 proc semGeneric(c: PContext, n: PNode, s: PSym, prev: PType): PType = 
   result = newOrPrevType(tyGenericInvokation, prev, c)
   addSonSkipIntLit(result, s.typ)
- 
+
   template addToResult(typ) =
     if typ.isNil:
       internalAssert false
@@ -923,7 +928,7 @@ proc freshType(res, prev: PType): PType {.inline.} =
 
 proc semTypeClass(c: PContext, n: PNode, prev: PType): PType =
   # if n.sonsLen == 0: return newConstraint(c, tyTypeClass)
-  result = newOrPrevType(tyTypeClass, prev, c)
+  result = newOrPrevType(tyUserTypeClass, prev, c)
   result.n = n
 
   let
diff --git a/compiler/semtypinst.nim b/compiler/semtypinst.nim
index ac14179cd..1158335a8 100644
--- a/compiler/semtypinst.nim
+++ b/compiler/semtypinst.nim
@@ -116,8 +116,8 @@ proc hasGenericArguments*(n: PNode): bool =
            (n.sym.kind == skType and
             n.sym.typ.flags * {tfGenericTypeParam, tfImplicitTypeParam} != {})
   else:
-    for s in n.sons:
-      if hasGenericArguments(s): return true
+    for i in 0.. <n.safeLen:
+      if hasGenericArguments(n.sons[i]): return true
     return false
 
 proc reResolveCallsWithTypedescParams(cl: var TReplTypeVars, n: PNode): PNode =
@@ -360,7 +360,10 @@ proc replaceTypeVarsTAux(cl: var TReplTypeVars, t: PType): PType =
       if tfUnresolved in t.flags: result = result.base
     elif t.sonsLen > 0:
       result = makeTypeDesc(cl.c, replaceTypeVarsT(cl, t.sons[0]))
-  
+ 
+  of tyUserTypeClass:
+    result = t
+
   of tyGenericInst:
     result = instCopyType(cl, t)
     for i in 1 .. <result.sonsLen:
diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim
index 1fe667a3c..d269e9e69 100644
--- a/compiler/sigmatch.nim
+++ b/compiler/sigmatch.nim
@@ -103,7 +103,7 @@ proc initCandidate*(ctx: PContext, c: var TCandidate, callee: PSym,
     for i in 1..min(sonsLen(typeParams), sonsLen(binding)-1):
       var formalTypeParam = typeParams.sons[i-1].typ
       var bound = binding[i].typ
-      if formalTypeParam.kind != tyTypeDesc:
+      if bound != nil and formalTypeParam.kind != tyTypeDesc:
         bound = bound.skipTypes({tyTypeDesc})
       put(c.bindings, formalTypeParam, bound)
 
@@ -140,7 +140,7 @@ proc sumGeneric(t: PType): int =
       result = ord(t.kind == tyGenericInvokation)
       for i in 0 .. <t.len: result += t.sons[i].sumGeneric
       break
-    of tyGenericParam, tyExpr, tyStatic, tyStmt, tyTypeDesc, tyTypeClass: break
+    of tyGenericParam, tyExpr, tyStatic, tyStmt, tyTypeDesc: break
     else: return 0
 
 proc complexDisambiguation(a, b: PType): int =
@@ -399,6 +399,70 @@ proc typeRangeRel(f, a: PType): TTypeRelation {.noinline.} =
   else:
     result = isNone
 
+proc matchUserTypeClass*(c: PContext, m: var TCandidate,
+                         ff, a: PType): TTypeRelation =
+  #if f.n == nil:
+  #  let r = typeRel(m, f, a)
+  #  return if r == isGeneric: arg else: nil
+
+  var body = ff.skipTypes({tyUserTypeClassInst})
+
+  # var prev = PType(idTableGet(m.bindings, f))
+  # if prev != nil:
+  #   if sameType(prev, a): return arg
+  #   else: return nil
+
+  # pushInfoContext(arg.info)
+  openScope(c)
+  inc c.inTypeClass
+
+  finally:
+    dec c.inTypeClass
+    closeScope(c)
+
+  if ff.kind == tyUserTypeClassInst:
+    for i in 1 .. <(ff.len - 1):
+      var
+        typeParamName = ff.base.sons[i-1].sym.name
+        typ = ff.sons[i]
+        param = newSym(skType, typeParamName, body.sym, body.sym.info)
+        
+      param.typ = makeTypeDesc(c, typ)
+      addDecl(c, param)
+
+  for param in body.n[0]:
+    var
+      dummyName: PNode
+      dummyType: PType
+    
+    if param.kind == nkVarTy:
+      dummyName = param[0]
+      dummyType = makeVarType(c, a)
+    else:
+      dummyName = param
+      dummyType = a
+
+    internalAssert dummyName.kind == nkIdent
+    var dummyParam = newSym(skType, dummyName.ident, body.sym, body.sym.info)
+    dummyParam.typ = dummyType
+    addDecl(c, dummyParam)
+
+  var checkedBody = c.semTryExpr(c, copyTree(body.n[3]), bufferErrors = false)
+  m.errors = bufferedMsgs
+  clearBufferedMsgs()
+  if checkedBody == nil: return isNone
+
+  if checkedBody.kind == nkStmtList:
+    for stmt in checkedBody:
+      case stmt.kind
+      of nkReturnStmt: discard
+      of nkTypeSection: discard
+      of nkConstDef: discard
+      else: discard
+    
+  return isGeneric
+  # put(m.bindings, f, a)
+
 proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
   # typeRel can be used to establish various relationships between types:
   #
@@ -418,6 +482,11 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
 
   result = isNone
   assert(f != nil)
+  
+  if f.kind == tyExpr:
+    put(c.bindings, f, aOrig)
+    return isGeneric
+
   assert(aOrig != nil)
 
   # var and static arguments match regular modifier-free types
@@ -751,6 +820,12 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
       else:
         return isNone
 
+  of tyUserTypeClass, tyUserTypeClassInst:
+    considerPreviousT:
+      result = matchUserTypeClass(c.c, c, f, a)
+      if result == isGeneric:
+        put(c.bindings, f, a)
+
   of tyCompositeTypeClass:
     considerPreviousT:
       if typeRel(c, f.sons[1], a) != isNone:
@@ -759,7 +834,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
       else:
         return isNone
 
-  of tyGenericParam, tyTypeClass:
+  of tyGenericParam:
     var x = PType(idTableGet(c.bindings, f))
     if x == nil:
       if c.calleeSym != nil and c.calleeSym.kind == skType and
@@ -822,7 +897,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
                     else: a.sons[0]
       result = typeRel(c, prev.sons[0], toMatch)
   
-  of tyExpr, tyStmt:
+  of tyStmt:
     result = isGeneric
   
   of tyProxy:
@@ -904,57 +979,6 @@ proc localConvMatch(c: PContext, m: var TCandidate, f, a: PType,
       result.typ = getInstantiatedType(c, arg, m, base(f))
     m.baseTypeMatch = true
 
-proc matchUserTypeClass*(c: PContext, m: var TCandidate,
-                         arg: PNode, f, a: PType): PNode =
-  if f.n == nil:
-    let r = typeRel(m, f, a)
-    return if r == isGeneric: arg else: nil
- 
-  var prev = PType(idTableGet(m.bindings, f))
-  if prev != nil:
-    if sameType(prev, a): return arg
-    else: return nil
-
-  # pushInfoContext(arg.info)
-  openScope(c)
-  inc c.inTypeClass
-
-  finally:
-    dec c.inTypeClass
-    closeScope(c)
-
-  for param in f.n[0]:
-    var
-      dummyName: PNode
-      dummyType: PType
-    
-    if param.kind == nkVarTy:
-      dummyName = param[0]
-      dummyType = makeVarType(c, a)
-    else:
-      dummyName = param
-      dummyType = a
-
-    internalAssert dummyName.kind == nkIdent
-    var dummyParam = newSym(skType, dummyName.ident, f.sym, f.sym.info)
-    dummyParam.typ = dummyType
-    addDecl(c, dummyParam)
-
-  for stmt in f.n[3]:
-    var e = c.semTryExpr(c, copyTree(stmt), bufferErrors = false)
-    m.errors = bufferedMsgs
-    clearBufferedMsgs()
-    if e == nil: return nil
-
-    case e.kind
-    of nkReturnStmt: discard
-    of nkTypeSection: discard
-    of nkConstDef: discard
-    else: discard
-  
-  result = arg
-  put(m.bindings, f, a)
-
 proc paramTypesMatchAux(m: var TCandidate, f, argType: PType,
                         argSemantized, argOrig: PNode): PNode =
   var
@@ -975,25 +999,9 @@ proc paramTypesMatchAux(m: var TCandidate, f, argType: PType,
       argType = arg.typ
  
   var
-    r: TTypeRelation
     a = if c.inTypeClass > 0: argType.skipTypes({tyTypeDesc})
         else: argType
  
-  case fMaybeStatic.kind
-  of tyTypeClass, tyParametricTypeClass:
-    if fMaybeStatic.n != nil:
-      let match = matchUserTypeClass(c, m, arg, fMaybeStatic, a)
-      if match != nil:
-        r = isGeneric
-        arg = match
-      else:
-        r = isNone
-    else:
-      r = typeRel(m, f, a)
-  of tyExpr:
-    r = isGeneric
-    put(m.bindings, f, arg.typ)
-  else:
     r = typeRel(m, f, a)
 
   case r
diff --git a/compiler/transf.nim b/compiler/transf.nim
index f22433972..deb821eff 100644
--- a/compiler/transf.nim
+++ b/compiler/transf.nim
@@ -113,8 +113,8 @@ proc newAsgnStmt(c: PTransf, le: PNode, ri: PTransNode): PTransNode =
   result[1] = ri
 
 proc transformSymAux(c: PTransf, n: PNode): PNode =
-  if n.sym.kind == skIterator and n.sym.typ.callConv == ccClosure:
-    return liftIterSym(n)
+  #if n.sym.kind == skIterator and n.sym.typ.callConv == ccClosure:
+  #  return liftIterSym(n)
   var b: PNode
   var tc = c.transCon
   if sfBorrow in n.sym.flags: 
@@ -389,7 +389,7 @@ proc transformConv(c: PTransf, n: PNode): PTransNode =
       result[0] = transform(c, n.sons[1])
     else: 
       result = transform(c, n.sons[1])
-  of tyGenericParam, tyOrdinal, tyTypeClass:
+  of tyGenericParam, tyOrdinal:
     result = transform(c, n.sons[1])
     # happens sometimes for generated assignments, etc.
   else: 
@@ -636,6 +636,8 @@ proc transform(c: PTransf, n: PNode): PTransNode =
           s.ast.sons[bodyPos] = n.sons[bodyPos]
         #n.sons[bodyPos] = liftLambdas(s, n)
         #if n.kind == nkMethodDef: methodDef(s, false)
+    #if n.kind == nkIteratorDef and n.typ != nil:
+    #  return liftIterSym(n.sons[namePos]).PTransNode
     result = PTransNode(n)
   of nkMacroDef:
     # XXX no proper closure support yet:
@@ -708,6 +710,7 @@ proc transform(c: PTransf, n: PNode): PTransNode =
     # XXX comment handling really sucks:
     if importantComments():
       PNode(result).comment = n.comment
+  of nkClosure: return PTransNode(n)
   else:
     result = transformSons(c, n)
   var cnst = getConstExpr(c.module, PNode(result))
@@ -738,8 +741,8 @@ proc transformBody*(module: PSym, n: PNode, prc: PSym): PNode =
     var c = openTransf(module, "")
     result = processTransf(c, n, prc)
     result = liftLambdas(prc, result)
-    if prc.kind == skIterator and prc.typ.callConv == ccClosure:
-      result = lambdalifting.liftIterator(prc, result)
+    #if prc.kind == skIterator and prc.typ.callConv == ccClosure:
+    #  result = lambdalifting.liftIterator(prc, result)
     incl(result.flags, nfTransf)
     when useEffectSystem: trackProc(prc, result)
 
diff --git a/compiler/types.nim b/compiler/types.nim
index d7310596f..4a53a84c9 100644
--- a/compiler/types.nim
+++ b/compiler/types.nim
@@ -404,9 +404,10 @@ const
     "float", "float32", "float64", "float128",
     "uint", "uint8", "uint16", "uint32", "uint64",
     "bignum", "const ",
-    "!", "varargs[$1]", "iter[$1]", "Error Type", "TypeClass",
-    "ParametricTypeClass", "BuiltInTypeClass", "CompositeTypeClass",
-    "and", "or", "not", "any", "static", "TypeFromExpr"]
+    "!", "varargs[$1]", "iter[$1]", "Error Type",
+    "BuiltInTypeClass", "UserTypeClass",
+    "UserTypeClassInst", "CompositeTypeClass",
+    "and", "or", "not", "any", "static", "TypeFromExpr", "FieldAccessor"]
 
 proc typeToString(typ: PType, prefer: TPreferedDesc = preferName): string =
   var t = typ
@@ -434,11 +435,30 @@ proc typeToString(typ: PType, prefer: TPreferedDesc = preferName): string =
   of tyStatic:
     internalAssert t.len > 0
     result = "static[" & typeToString(t.sons[0]) & "]"
-  of tyTypeClass:
+  of tyUserTypeClass:
     internalAssert t.sym != nil and t.sym.owner != nil
     return t.sym.owner.name.s
   of tyBuiltInTypeClass:
-    return "TypeClass"
+    result = case t.base.kind:
+      of tyVar: "var"
+      of tyRef: "ref"
+      of tyPtr: "ptr"
+      of tySequence: "seq"
+      of tyArray: "array"
+      of tySet: "set"
+      of tyRange: "range"
+      of tyDistinct: "distinct"
+      of tyProc: "proc"
+      of tyObject: "object"
+      of tyTuple: "tuple"
+      else: (internalAssert false; "")
+  of tyUserTypeClassInst:
+    let body = t.base
+    result = body.sym.name.s & "["
+    for i in countup(1, sonsLen(t) - 2):
+      if i > 1: add(result, ", ")
+      add(result, typeToString(t.sons[i]))
+    result.add "]"
   of tyAnd:
     result = typeToString(t.sons[0]) & " and " & typeToString(t.sons[1])
   of tyOr:
@@ -448,7 +468,7 @@ proc typeToString(typ: PType, prefer: TPreferedDesc = preferName): string =
   of tyExpr:
     internalAssert t.len == 0
     result = "expr"
-  of tyFromExpr:
+  of tyFromExpr, tyFieldAccessor:
     result = renderTree(t.n)
   of tyArray: 
     if t.sons[0].kind == tyRange: 
@@ -546,7 +566,8 @@ proc firstOrd(t: PType): BiggestInt =
     else: 
       assert(t.n.sons[0].kind == nkSym)
       result = t.n.sons[0].sym.position
-  of tyGenericInst, tyDistinct, tyConst, tyMutable, tyTypeDesc:
+  of tyGenericInst, tyDistinct, tyConst, tyMutable,
+     tyTypeDesc, tyFieldAccessor:
     result = firstOrd(lastSon(t))
   else: 
     internalError("invalid kind for first(" & $t.kind & ')')
@@ -579,7 +600,8 @@ proc lastOrd(t: PType): BiggestInt =
   of tyEnum: 
     assert(t.n.sons[sonsLen(t.n) - 1].kind == nkSym)
     result = t.n.sons[sonsLen(t.n) - 1].sym.position
-  of tyGenericInst, tyDistinct, tyConst, tyMutable, tyTypeDesc: 
+  of tyGenericInst, tyDistinct, tyConst, tyMutable,
+     tyTypeDesc, tyFieldAccessor:
     result = lastOrd(lastSon(t))
   of tyProxy: result = 0
   else: 
@@ -875,9 +897,9 @@ proc sameTypeAux(x, y: PType, c: var TSameTypeClosure): bool =
   of tyGenericInvokation, tyGenericBody, tySequence,
      tyOpenArray, tySet, tyRef, tyPtr, tyVar, tyArrayConstr,
      tyArray, tyProc, tyConst, tyMutable, tyVarargs, tyIter,
-     tyOrdinal, tyTypeClasses:
+     tyOrdinal, tyTypeClasses, tyFieldAccessor:
     cycleCheck()
-    if a.kind == tyTypeClass and a.n != nil: return a.n == b.n
+    if a.kind == tyUserTypeClass and a.n != nil: return a.n == b.n
     result = sameChildrenAux(a, b, c) and sameFlags(a, b)
     if result and a.kind == tyProc:
       result = ((IgnoreCC in c.flags) or a.callConv == b.callConv) and
@@ -1021,7 +1043,7 @@ proc typeAllowedAux(marker: var TIntSet, typ: PType, kind: TSymKind,
   of tyTypeClasses:
     result = true
   of tyGenericBody, tyGenericParam, tyGenericInvokation,
-     tyNone, tyForward, tyFromExpr:
+     tyNone, tyForward, tyFromExpr, tyFieldAccessor:
     result = false
   of tyNil:
     result = kind == skConst
@@ -1231,8 +1253,15 @@ proc getSize(typ: PType): BiggestInt =
   if result < 0: internalError("getSize: " & $typ.kind)
 
 proc containsGenericTypeIter(t: PType, closure: PObject): bool =
-  result = t.kind in GenericTypes + tyTypeClasses + {tyTypeDesc,tyFromExpr} or
-           t.kind == tyStatic and t.n == nil
+  if t.kind in GenericTypes + tyTypeClasses + {tyFromExpr}:
+    return true
+
+  if t.kind == tyTypeDesc:
+    if t.sonsLen == 0: return true
+    if containsGenericTypeIter(t.base, closure): return true
+    return false
+  
+  return t.kind == tyStatic and t.n == nil
 
 proc containsGenericType*(t: PType): bool = 
   result = iterOverType(t, containsGenericTypeIter, nil)
diff --git a/compiler/vm.nim b/compiler/vm.nim
index 9ed18d29e..deca288b5 100644
--- a/compiler/vm.nim
+++ b/compiler/vm.nim
@@ -802,7 +802,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): PNode =
       let t1 = regs[rb].typ.skipTypes({tyTypeDesc})
       let t2 = c.types[regs[rc].intVal.int]
       # XXX: This should use the standard isOpImpl
-      let match = if t2.kind == tyTypeClass: true
+      let match = if t2.kind == tyUserTypeClass: true
                   else: sameType(t1, t2)
       regs[ra].intVal = ord(match)
     of opcSetLenSeq:
@@ -1057,6 +1057,7 @@ proc fixType(result, n: PNode) {.inline.} =
   # XXX do it deeply for complex values; there seems to be no simple
   # solution except to check it deeply here.
   #if result.typ.isNil: result.typ = n.typ
+  discard
 
 proc execute(c: PCtx, start: int): PNode =
   var tos = PStackFrame(prc: nil, comesFrom: 0, next: nil)
@@ -1118,6 +1119,7 @@ proc evalConstExprAux(module, prc: PSym, n: PNode, mode: TEvalMode): PNode =
   var c = globalCtx
   c.mode = mode
   let start = genExpr(c, n, requiresValue = mode!=emStaticStmt)
+  if c.code[start].opcode == opcEof: return emptyNode
   assert c.code[start].opcode != opcEof
   var tos = PStackFrame(prc: prc, comesFrom: 0, next: nil)
   newSeq(tos.slots, c.prc.maxSlots)
diff --git a/doc/docgen.txt b/doc/docgen.txt
new file mode 100644
index 000000000..acd09f2eb
--- /dev/null
+++ b/doc/docgen.txt
@@ -0,0 +1,192 @@
+===================================
+   Nimrod DocGen Tools Guide
+===================================
+
+:Author: Erik O'Leary
+:Version: |nimrodversion|
+
+.. contents::
+
+
+Introduction
+============
+
+This document describes the `documentation generation tools`:idx: built into
+the `Nimrod compiler <nimrodc.html>`_, which can generate HTML and JSON output
+from input .nim files and projects, as well as HTML and LaTeX from input RST
+(reStructuredText) files. The output documentation will include module
+dependencies (``import``), any top-level documentation comments (##), and
+exported symbols (*), including procedures, types, and variables.
+
+
+Documentation Comments
+----------------------
+
+Any comments which are preceded by a double-hash (##), are interpreted as
+documentation.  Comments are parsed as RST (see `reference
+<http://docutils.sourceforge.net/docs/user/rst/quickref.html>`_), providing
+Nimrod module authors the ability to easily generate richly formatted
+documentation with only their well-documented code.
+
+Example:
+
+.. code-block:: nimrod
+  type TPerson* = object
+    ## This type contains a description of a person
+    name: string
+    age: int
+
+Outputs::
+  TPerson* = object
+    name: string
+    age: int
+
+This type contains a description of a person
+
+Field documentation comments can be added to fields like so:
+
+.. code-block:: nimrod
+  var numValues: int ## \
+    ## `numValues` stores the number of values
+
+Note that without the `*` following the name of the type, the documentation for
+this type would not be generated. Documentation will only be generated for
+*exported* types/procedures/etc.
+
+
+Nimrod file input
+-----------------
+
+The following examples will generate documentation for the below contrived
+*Nimrod* module, aptly named 'sample.nim'
+
+sample.nim:
+
+.. code-block:: nimrod
+  ## This module is a sample.
+
+  import strutils
+
+  proc helloWorld*(times: int) =
+    ## Takes an integer and outputs
+    ## as many "hello world!"s
+
+    for i in 0 .. times-1:
+      echo "hello world!"
+
+  helloWorld(5)
+
+
+Document Types
+==============
+
+
+HTML
+----
+
+Generation of HTML documents is done via both the ``doc`` and ``doc2``
+commands. These command take either a single .nim file, outputting a single
+.html file with the same base filename, or multiple .nim files, outputting
+multiple .html files and, optionally, an index file.
+
+The ``doc`` command::
+  nimrod doc sample
+
+Partial Output::
+  ...
+  proc helloWorld*(times: int)
+  ...
+
+Output can be viewed in full here: `docgen_sample.html <docgen_sample.html>`_.
+The next command, called ``doc2``, is very similar to the ``doc`` command, but
+will be run after the compiler performs semantic checking on the input nimrod
+module(s), which allows it to process macros.
+
+The ``doc2`` command::
+  nimrod doc2 sample
+
+Partial Output::
+  ...
+  proc helloWorld(times: int) {.raises: [], tags: [].}
+  ...
+
+The full output can be seen here: `docgen_sample2.html <docgen_sample2.html>`_.
+As you can see, the tool has extracted additional information provided to it by
+the compiler beyond what the ``doc`` command provides, such as pragmas attached
+implicitly by the compiler. This type of information is not available from
+looking at the AST (Abstract Syntax Tree) prior to semantic checking, as the
+``doc`` command does.
+
+
+JSON
+----
+
+Generation of JSON documents is done via the ``jsondoc`` command. This command
+takes in a .nim file, and outputs a .json file with the same base filename.
+Note that this tool is built off of the ``doc`` command, and therefore is
+performed before semantic checking.
+
+The ``jsondoc`` command::
+  nimrod jsondoc sample
+
+Output::
+  [
+    {
+      "comment": "This module is a sample."
+    },
+    {
+      "name": "helloWorld",
+      "type": "skProc",
+      "description": "Takes an integer and outputs as many &quot;hello world!&quot;s",
+      "code": "proc helloWorld*(times: int)"
+    }
+  ]
+
+
+Related Options
+===============
+
+``--project`` switch
+::
+  nimrod doc2 --project sample
+
+This will recursively generate documentation of all nimrod modules imported
+into the input module, including system modules. Be careful with this command,
+as it may end up sprinkling html files all over your filesystem!
+
+
+``--index`` switch
+::
+  nimrod doc2 --index:on sample
+
+This will generate an index of all the exported symbols in the input Nimrod
+module, and put it into a neighboring file with the extension of `.idx`.
+
+
+Other Input Formats
+===================
+
+The *Nimrod compiler* also has support for RST (reStructuredText) files with
+the ``rst2html`` and ``rst2tex`` commands. Documents like this one are
+initially written in a dialect of RST which adds support for nimrod sourcecode
+highlighting with the ``.. code-block:: nimrod`` prefix. ``code-block`` also
+supports highlighting of C++ and some other c-like languages.
+
+Usage::
+  nimrod rst2html docgen.txt
+
+Output::
+  You're reading it!
+
+The input can be viewed here `docgen.txt <docgen.txt>`_. The ``rst2tex``
+command is invoked identically to ``rst2html``, but outputs a .tex file instead
+of .html.
+
+
+Additional Resources
+=========
+
+`Nimrod Compiler User Guide <nimrodc.html#command-line-switches>`_
+
+`RST Quick Reference
+<http://docutils.sourceforge.net/docs/user/rst/quickref.html>`_
diff --git a/doc/docgen_sample.nim b/doc/docgen_sample.nim
new file mode 100644
index 000000000..875993187
--- /dev/null
+++ b/doc/docgen_sample.nim
@@ -0,0 +1,12 @@
+## This module is a sample.
+
+import strutils
+
+proc helloWorld*(times: int) =
+  ## Takes an integer and outputs
+  ## as many "hello world!"s
+
+  for i in 0 .. times-1:
+    echo "hello world!"
+
+helloWorld(5)
diff --git a/doc/grammar.txt b/doc/grammar.txt
index 7fe2b56aa..54c2217d8 100644
--- a/doc/grammar.txt
+++ b/doc/grammar.txt
@@ -42,14 +42,14 @@ par = '(' optInd (&parKeyw complexOrSimpleStmt ^+ ';'
                  | simpleExpr ('=' expr (';' complexOrSimpleStmt ^+ ';' )? )?
                             | (':' expr)? (',' (exprColonEqExpr comma?)*)?  )?
         optPar ')'
+literal = | INT_LIT | INT8_LIT | INT16_LIT | INT32_LIT | INT64_LIT
+          | UINT_LIT | UINT8_LIT | UINT16_LIT | UINT32_LIT | UINT64_LIT
+          | FLOAT_LIT | FLOAT32_LIT | FLOAT64_LIT
+          | STR_LIT | RSTR_LIT | TRIPLESTR_LIT
+          | CHAR_LIT
+          | NIL
 generalizedLit = GENERALIZED_STR_LIT | GENERALIZED_TRIPLESTR_LIT
-identOrLiteral = generalizedLit | symbol 
-               | INT_LIT | INT8_LIT | INT16_LIT | INT32_LIT | INT64_LIT
-               | UINT_LIT | UINT8_LIT | UINT16_LIT | UINT32_LIT | UINT64_LIT
-               | FLOAT_LIT | FLOAT32_LIT | FLOAT64_LIT
-               | STR_LIT | RSTR_LIT | TRIPLESTR_LIT
-               | CHAR_LIT
-               | NIL
+identOrLiteral = generalizedLit | symbol | literal
                | par | arrayConstr | setOrTableConstr
                | castExpr
 tupleConstr = '(' optInd (exprColonEqExpr comma?)* optPar ')'
@@ -59,6 +59,8 @@ primarySuffix = '(' (exprColonEqExpr comma?)* ')' doBlocks?
               | '.' optInd ('type' | 'addr' | symbol) generalizedLit?
               | '[' optInd indexExprList optPar ']'
               | '{' optInd indexExprList optPar '}'
+              | &( '`'|IDENT|literal|'cast') expr ^+ ',' # command syntax
+                     (doBlock | macroColon)?
 condExpr = expr colcom expr optInd
         ('elif' expr colcom expr optInd)*
          'else' colcom expr
@@ -95,18 +97,19 @@ primary = typeKeyw typeDescK
         / 'bind' primary
 typeDesc = simpleExpr
 typeDefAux = simpleExpr
+           | 'generic' typeClass
+macroColon = ':' stmt? ( IND{=} 'of' exprList ':' stmt 
+                       | IND{=} 'elif' expr ':' stmt
+                       | IND{=} 'except' exprList ':' stmt
+                       | IND{=} 'else' ':' stmt )*
 exprStmt = simpleExpr
          (( '=' optInd expr )
          / ( expr ^+ comma
              doBlocks
-              / ':' stmt? ( IND{=} 'of' exprList ':' stmt 
-                          | IND{=} 'elif' expr ':' stmt
-                          | IND{=} 'except' exprList ':' stmt
-                          | IND{=} 'else' ':' stmt )*
+              / macroColon
            ))?
-moduleName = expr ('as' expr)?
-importStmt = 'import' optInd moduleName
-              ((comma moduleName)*
+importStmt = 'import' optInd expr
+              ((comma expr)*
               / 'except' optInd (expr ^+ comma))
 includeStmt = 'include' optInd expr ^+ comma
 fromStmt = 'from' moduleName 'import' optInd expr (comma expr)*
@@ -161,6 +164,9 @@ objectCase = 'case' identWithPragma ':' typeDesc ':'? COMMENT?
 objectPart = IND{>} objectPart^+IND{=} DED
            / objectWhen / objectCase / 'nil' / declColonEquals
 object = 'object' pragma? ('of' typeDesc)? COMMENT? objectPart
+typeClassParam = ('var')? symbol
+typeClass = typeClassParam ^* ',' (pragma)? ('of' typeDesc ^* ',')?
+              &IND{>} stmt
 distinct = 'distinct' optInd typeDesc
 typeDef = identWithPragma genericParamList? '=' optInd typeDefAux
             indAndComment?
diff --git a/doc/manual.txt b/doc/manual.txt
index c90373233..faf62dcee 100644
--- a/doc/manual.txt
+++ b/doc/manual.txt
@@ -2261,8 +2261,8 @@ from different modules having the same name.
   using sdl.SetTimer
 
 Note that ``using`` only *adds* to the current context, it doesn't remove or
-replace, **neither** does it create a new scope. What this means is that if you
-apply this to multiple variables the compiler will find conflicts in what
+replace, **neither** does it create a new scope. What this means is that if one
+applies this to multiple variables the compiler will find conflicts in what
 variable to use:
 
 .. code-block:: nimrod
@@ -2275,7 +2275,7 @@ variable to use:
   echo b
 
 When the compiler reaches the second ``add`` call, both ``a`` and ``b`` could
-be used with the proc, so you get ``Error: expression '(a|b)' has no type (or
+be used with the proc, so one gets ``Error: expression '(a|b)' has no type (or
 is ambiguous)``. To solve this you would need to nest ``using`` with a
 ``block`` statement so as to control the reach of the ``using`` statement.
 
@@ -2368,8 +2368,8 @@ The `addr`:idx: operator returns the address of an l-value. If the type of the
 location is ``T``, the `addr` operator result is of the type ``ptr T``. An
 address is always an untraced reference. Taking the address of an object that
 resides on the stack is **unsafe**, as the pointer may live longer than the
-object on the stack and can thus reference a non-existing object. You can get
-the address of variables, but you can't use it on variables declared through
+object on the stack and can thus reference a non-existing object. One can get
+the address of variables, but one can't use it on variables declared through
 ``let`` statements:
 
 .. code-block:: nimrod
@@ -2764,7 +2764,7 @@ First class iterators
 There are 2 kinds of iterators in Nimrod: *inline* and *closure* iterators.
 An `inline iterator`:idx: is an iterator that's always inlined by the compiler 
 leading to zero overhead for the abstraction, but may result in a heavy
-increasee in code size. Inline iterators are second class
+increase in code size. Inline iterators are second class
 citizens; one cannot pass them around like first class procs.
 
 In contrast to that, a `closure iterator`:idx: can be passed around:
@@ -2835,7 +2835,24 @@ a `collaborative tasking`:idx: system:
 
 The builtin ``system.finished`` can be used to determine if an iterator has
 finished its operation; no exception is raised on an attempt to invoke an
-iterator that has already finished its work. 
+iterator that has already finished its work.
+
+Closure iterators are *resumable functions* and so one has to provide the
+arguments to every call. To get around this limitation one can capture
+parameters of an outer factory proc:
+
+.. code-block:: nimrod
+  proc mycount(a, b: int): iterator (): int =
+    return iterator (): int =
+      var x = a
+      while x <= b:
+        yield x
+        inc x
+
+  let foo = mycount 1, 4
+
+  for f in foo():
+    echo f
 
 
 Type sections
@@ -2923,9 +2940,9 @@ in an implicit try block:
   finally: close(f)
   ...
 
-The ``except`` statement has a limitation in this form: you can't specify the
-type of the exception, you have to catch everything. Also, if you want to use
-both ``finally`` and ``except`` you need to reverse the usual sequence of the
+The ``except`` statement has a limitation in this form: one can't specify the
+type of the exception, one has to catch everything. Also, if one wants to use
+both ``finally`` and ``except`` one needs to reverse the usual sequence of the
 statements. Example:
 
 .. code-block:: nimrod
@@ -3353,7 +3370,7 @@ currently matched type. These instances can act both as variables of the type,
 when used in contexts, where a value is expected, and as the type itself, when
 used in a contexts, where a type is expected.
 
-Please note that the ``is`` operator allows you to easily verify the precise
+Please note that the ``is`` operator allows one to easily verify the precise
 type signatures of the required operations, but since type inference and
 default parameters are still applied in the provided block, it's also possible
 to encode usage protocols that doesn't reveal implementation details.
diff --git a/doc/nimrodc.txt b/doc/nimrodc.txt
index f5fbf3ebb..52e0a6eaf 100644
--- a/doc/nimrodc.txt
+++ b/doc/nimrodc.txt
@@ -538,6 +538,13 @@ on Linux::
   nimrod c --dynlibOverride:lua --passL:liblua.lib program.nim
 

 

+Nimrod documentation tools
+==========================
+
+Nimrod provides the `doc`:idx: and `doc2`:idx: commands to generate HTML
+documentation from ``.nim`` source files. Only exported symbols will appear in
+the output. For more details `see the docgen documentation <docgen.html>`_.
+
 Nimrod idetools integration

 ===========================

 

diff --git a/koch.nim b/koch.nim
index 1814a0efc..35a86a597 100644
--- a/koch.nim
+++ b/koch.nim
@@ -42,7 +42,7 @@ Possible Commands:
   csource [options]        builds the C sources for installation
   zip                      builds the installation ZIP package
   inno [options]           builds the Inno Setup installer (for Windows)
-  tests                    run the testsuite
+  tests [options]          run the testsuite
   update                   updates nimrod to the latest version from github
                            (compile koch with -d:withUpdate to enable)
   temp options             creates a temporary compiler for testing
@@ -260,11 +260,14 @@ when defined(withUpdate):
 
 # -------------- tests --------------------------------------------------------
 
+template `|`(a, b): expr = (if a.len > 0: a else: b)
+
 proc tests(args: string) =
   # we compile the tester with taintMode:on to have a basic
   # taint mode test :-)
-  exec("nimrod cc --taintMode:on tests/testament/tester")
-  exec(getCurrentDir() / "tests/testament/tester".exe & " all")
+  exec "nimrod cc --taintMode:on tests/testament/tester"
+  exec quoteShell(getCurrentDir() / "tests/testament/tester".exe) & " " &
+      (args|"all")
 
 proc temp(args: string) =
   var output = "compiler" / "nimrod".exe
diff --git a/lib/core/macros.nim b/lib/core/macros.nim
index 0356067f1..3b36e31e0 100644
--- a/lib/core/macros.nim
+++ b/lib/core/macros.nim
@@ -300,9 +300,12 @@ when not defined(booting):
     ## that should be inserted verbatim in the program
     ## Example:
     ##
+    ## .. code-block:: nimrod
     ##   emit("echo " & '"' & "hello world".toUpper & '"')
     ##
-    eval: result = e.parseStmt
+    macro payload: stmt {.gensym.} =
+      result = e.parseStmt
+    payload()
 
 proc expectKind*(n: PNimrodNode, k: TNimrodNodeKind) {.compileTime.} =
   ## checks that `n` is of kind `k`. If this is not the case,
@@ -387,7 +390,7 @@ proc treeRepr*(n: PNimrodNode): string {.compileTime.} =
     res.add(($n.kind).substr(3))
 
     case n.kind
-    of nnkEmpty: nil # same as nil node in this representation
+    of nnkEmpty: discard # same as nil node in this representation
     of nnkNilLit: res.add(" nil")
     of nnkCharLit..nnkInt64Lit: res.add(" " & $n.intVal)
     of nnkFloatLit..nnkFloat64Lit: res.add(" " & $n.floatVal)
@@ -412,7 +415,7 @@ proc lispRepr*(n: PNimrodNode): string {.compileTime.} =
   add(result, "(")
 
   case n.kind
-  of nnkEmpty: nil # same as nil node in this representation
+  of nnkEmpty: discard # same as nil node in this representation
   of nnkNilLit: add(result, "nil")
   of nnkCharLit..nnkInt64Lit: add(result, $n.intVal)
   of nnkFloatLit..nnkFloat64Lit: add(result, $n.floatVal)
@@ -645,10 +648,13 @@ iterator children*(n: PNimrodNode): PNimrodNode {.inline.}=
   for i in 0 .. high(n):
     yield n[i]
 
-template findChild*(n: PNimrodNode; cond: expr): PNimrodNode {.immediate, dirty.} =
-  ## Find the first child node matching condition (or nil)
-  ## var res = findChild(n, it.kind == nnkPostfix and it.basename.ident == !"foo")
-  
+template findChild*(n: PNimrodNode; cond: expr): PNimrodNode {.
+  immediate, dirty.} =
+  ## Find the first child node matching condition (or nil).
+  ## 
+  ## .. code-block:: nimrod
+  ##   var res = findChild(n, it.kind == nnkPostfix and
+  ##                          it.basename.ident == !"foo")
   block:
     var result: PNimrodNode
     for it in n.children:
@@ -736,6 +742,6 @@ proc addIdentIfAbsent*(dest: PNimrodNode, ident: string) {.compiletime.} =
       if ident.eqIdent($node): return
     of nnkExprColonExpr:
       if ident.eqIdent($node[0]): return
-    else: nil
+    else: discard
   dest.add(ident(ident))
 
diff --git a/lib/pure/asyncio.nim b/lib/pure/asyncio.nim
index 3c2a5c17a..f13cadaa2 100644
--- a/lib/pure/asyncio.nim
+++ b/lib/pure/asyncio.nim
@@ -139,27 +139,27 @@ type
 proc newDelegate*(): PDelegate =
   ## Creates a new delegate.
   new(result)
-  result.handleRead = (proc (h: PObject) = nil)
-  result.handleWrite = (proc (h: PObject) = nil)
-  result.handleError = (proc (h: PObject) = nil)
+  result.handleRead = (proc (h: PObject) = discard)
+  result.handleWrite = (proc (h: PObject) = discard)
+  result.handleError = (proc (h: PObject) = discard)
   result.hasDataBuffered = (proc (h: PObject): bool = return false)
-  result.task = (proc (h: PObject) = nil)
+  result.task = (proc (h: PObject) = discard)
   result.mode = fmRead
 
 proc newAsyncSocket(): PAsyncSocket =
   new(result)
   result.info = SockIdle
 
-  result.handleRead = (proc (s: PAsyncSocket) = nil)
+  result.handleRead = (proc (s: PAsyncSocket) = discard)
   result.handleWrite = nil
-  result.handleConnect = (proc (s: PAsyncSocket) = nil)
-  result.handleAccept = (proc (s: PAsyncSocket) = nil)
-  result.handleTask = (proc (s: PAsyncSocket) = nil)
+  result.handleConnect = (proc (s: PAsyncSocket) = discard)
+  result.handleAccept = (proc (s: PAsyncSocket) = discard)
+  result.handleTask = (proc (s: PAsyncSocket) = discard)
 
   result.lineBuffer = "".TaintedString
   result.sendBuffer = ""
 
-proc AsyncSocket*(domain: TDomain = AF_INET, typ: TType = SOCK_STREAM, 
+proc asyncSocket*(domain: TDomain = AF_INET, typ: TType = SOCK_STREAM, 
                   protocol: TProtocol = IPPROTO_TCP, 
                   buffered = true): PAsyncSocket =
   ## Initialises an AsyncSocket object. If a socket cannot be initialised
diff --git a/lib/pure/ftpclient.nim b/lib/pure/ftpclient.nim
index d9f9dfd3d..f136e0016 100644
--- a/lib/pure/ftpclient.nim
+++ b/lib/pure/ftpclient.nim
@@ -95,7 +95,7 @@ type
   EInvalidReply* = object of ESynch
   EFTP* = object of ESynch
 
-proc FTPClient*(address: string, port = TPort(21),
+proc ftpClient*(address: string, port = TPort(21),
                 user, pass = ""): PFTPClient =
   ## Create a ``PFTPClient`` object.
   new(result)
@@ -315,7 +315,7 @@ proc listDirs*(ftp: PFTPClient, dir: string = "",
   assertReply ftp.send("NLST " & dir.normalizePathSep), ["125", "150"]
 
   if not async:
-    while not ftp.job.prc(ftp, false): nil
+    while not ftp.job.prc(ftp, false): discard
     result = splitLines(ftp.job.lines)
     ftp.deleteJob()
   else: return @[]
@@ -390,7 +390,7 @@ proc list*(ftp: PFTPClient, dir: string = "", async = false): string =
   assertReply(ftp.send("LIST" & " " & dir.normalizePathSep), ["125", "150"])
 
   if not async:
-    while not ftp.job.prc(ftp, false): nil
+    while not ftp.job.prc(ftp, false): discard
     result = ftp.job.lines
     ftp.deleteJob()
   else:
@@ -405,7 +405,7 @@ proc retrText*(ftp: PFTPClient, file: string, async = false): string =
   assertReply ftp.send("RETR " & file.normalizePathSep), ["125", "150"]
   
   if not async:
-    while not ftp.job.prc(ftp, false): nil
+    while not ftp.job.prc(ftp, false): discard
     result = ftp.job.lines
     ftp.deleteJob()
   else:
@@ -460,7 +460,7 @@ proc retrFile*(ftp: PFTPClient, file, dest: string, async = false) =
   ftp.job.filename = file.normalizePathSep
 
   if not async:
-    while not ftp.job.prc(ftp, false): nil
+    while not ftp.job.prc(ftp, false): discard
     ftp.deleteJob()
 
 proc doUpload(ftp: PFTPClient, async = false): bool =
@@ -518,7 +518,7 @@ proc store*(ftp: PFTPClient, file, dest: string, async = false) =
   assertReply ftp.send("STOR " & dest.normalizePathSep), ["125", "150"]
 
   if not async:
-    while not ftp.job.prc(ftp, false): nil
+    while not ftp.job.prc(ftp, false): discard
     ftp.deleteJob()
 
 proc close*(ftp: PFTPClient) =
@@ -554,10 +554,10 @@ proc csockHandleRead(s: PAsyncSocket, ftp: PAsyncFTPClient) =
     
     ftp.handleEvent(ftp, r)
 
-proc AsyncFTPClient*(address: string, port = TPort(21),
+proc asyncFTPClient*(address: string, port = TPort(21),
                      user, pass = "",
     handleEvent: proc (ftp: PAsyncFTPClient, ev: TFTPEvent) {.closure.} = 
-      (proc (ftp: PAsyncFTPClient, ev: TFTPEvent) = nil)): PAsyncFTPClient =
+      (proc (ftp: PAsyncFTPClient, ev: TFTPEvent) = discard)): PAsyncFTPClient =
   ## Create a ``PAsyncFTPClient`` object.
   ##
   ## Use this if you want to use asyncio's dispatcher.
@@ -604,7 +604,7 @@ when isMainModule:
         ftp.close()
         echo d.len
       else: assert(false)
-  var ftp = AsyncFTPClient("picheta.me", user = "test", pass = "asf", handleEvent = hev)
+  var ftp = asyncFTPClient("picheta.me", user = "test", pass = "asf", handleEvent = hev)
   
   d.register(ftp)
   d.len.echo()
@@ -618,7 +618,7 @@ when isMainModule:
 
 
 when isMainModule and false:
-  var ftp = FTPClient("picheta.me", user = "asdasd", pass = "asfwq")
+  var ftp = ftpClient("picheta.me", user = "asdasd", pass = "asfwq")
   ftp.connect()
   echo ftp.pwd()
   echo ftp.list()
diff --git a/lib/pure/os.nim b/lib/pure/os.nim
index 448ecc1e3..1f42d0d58 100644
--- a/lib/pure/os.nim
+++ b/lib/pure/os.nim
@@ -1586,7 +1586,7 @@ proc getAppFilename*(): string {.rtl, extern: "nos$1", tags: [FReadIO].} =
     # little heuristic that may work on other POSIX-like systems:
     result = string(getEnv("_"))
     if len(result) == 0:
-      result = string(ParamStr(0))
+      result = string(paramStr(0))
       # POSIX guaranties that this contains the executable
       # as it has been executed by the calling process
       if len(result) > 0 and result[0] != DirSep: # not an absolute path?
diff --git a/lib/pure/osproc.nim b/lib/pure/osproc.nim
index afa4a3b07..c7678b214 100644
--- a/lib/pure/osproc.nim
+++ b/lib/pure/osproc.nim
@@ -664,9 +664,8 @@ elif not defined(useNimRtl):
       chck res
 
     else:
-
-      Pid = fork()
-      if Pid < 0: osError(osLastError())
+      pid = fork()
+      if pid < 0: osError(osLastError())
       if pid == 0:
         ## child process:
 
diff --git a/lib/pure/pegs.nim b/lib/pure/pegs.nim
index a6147a96c..70b617393 100644
--- a/lib/pure/pegs.nim
+++ b/lib/pure/pegs.nim
@@ -306,7 +306,7 @@ proc backrefIgnoreStyle*(index: range[1..MaxSubPatterns]): TPeg {.
 
 proc spaceCost(n: TPeg): int =
   case n.kind
-  of pkEmpty: nil
+  of pkEmpty: discard
   of pkTerminal, pkTerminalIgnoreCase, pkTerminalIgnoreStyle, pkChar,
      pkGreedyRepChar, pkCharChoice, pkGreedyRepSet, 
      pkAny..pkWhitespace, pkGreedyAny:
@@ -1117,7 +1117,7 @@ proc handleHexChar(c: var TPegLexer, xi: var int) =
   of 'A'..'F': 
     xi = (xi shl 4) or (ord(c.buf[c.bufpos]) - ord('A') + 10)
     inc(c.bufpos)
-  else: nil
+  else: discard
 
 proc getEscapedChar(c: var TPegLexer, tok: var TToken) = 
   inc(c.bufpos)
@@ -1347,7 +1347,7 @@ proc getTok(c: var TPegLexer, tok: var TToken) =
       of "i": tok.modifier = modIgnoreCase
       of "y": tok.modifier = modIgnoreStyle
       of "v": tok.modifier = modVerbatim
-      else: nil
+      else: discard
       setLen(tok.literal, 0)
       if c.buf[c.bufpos] == '$':
         getDollar(c, tok)
@@ -1494,7 +1494,7 @@ proc primary(p: var TPegParser): TPeg =
   of tkCurlyAt:
     getTok(p)
     return !*\primary(p).token(p)
-  else: nil
+  else: discard
   case p.tok.kind
   of tkIdentifier:
     if p.identIsVerbatim: 
diff --git a/lib/pure/sockets.nim b/lib/pure/sockets.nim
index b3cc38ee7..fd6403118 100644
--- a/lib/pure/sockets.nim
+++ b/lib/pure/sockets.nim
@@ -192,7 +192,7 @@ when defined(Posix):
     of AF_UNIX:        result = posix.AF_UNIX
     of AF_INET:        result = posix.AF_INET
     of AF_INET6:       result = posix.AF_INET6
-    else: nil
+    else: discard
 
   proc toInt(typ: TType): cint =
     case typ
@@ -200,7 +200,7 @@ when defined(Posix):
     of SOCK_DGRAM:     result = posix.SOCK_DGRAM
     of SOCK_SEQPACKET: result = posix.SOCK_SEQPACKET
     of SOCK_RAW:       result = posix.SOCK_RAW
-    else: nil
+    else: discard
 
   proc toInt(p: TProtocol): cint =
     case p
@@ -210,7 +210,7 @@ when defined(Posix):
     of IPPROTO_IPV6:   result = posix.IPPROTO_IPV6
     of IPPROTO_RAW:    result = posix.IPPROTO_RAW
     of IPPROTO_ICMP:   result = posix.IPPROTO_ICMP
-    else: nil
+    else: discard
 
 else:
   proc toInt(domain: TDomain): cint = 
diff --git a/lib/system.nim b/lib/system.nim
index 75bebf702..09e44a45a 100644
--- a/lib/system.nim
+++ b/lib/system.nim
@@ -447,38 +447,38 @@ proc chr*(u: range[0..255]): char {.magic: "Chr", noSideEffect.}
 # --------------------------------------------------------------------------
 # built-in operators
 
-proc ze*(x: int8): int {.magic: "Ze8ToI", noSideEffect.}
-  ## zero extends a smaller integer type to ``int``. This treats `x` as
-  ## unsigned.
-proc ze*(x: int16): int {.magic: "Ze16ToI", noSideEffect.}
-  ## zero extends a smaller integer type to ``int``. This treats `x` as
-  ## unsigned.
-
-proc ze64*(x: int8): int64 {.magic: "Ze8ToI64", noSideEffect.}
-  ## zero extends a smaller integer type to ``int64``. This treats `x` as
-  ## unsigned.
-proc ze64*(x: int16): int64 {.magic: "Ze16ToI64", noSideEffect.}
-  ## zero extends a smaller integer type to ``int64``. This treats `x` as
-  ## unsigned.
-
-proc ze64*(x: int32): int64 {.magic: "Ze32ToI64", noSideEffect.}
-  ## zero extends a smaller integer type to ``int64``. This treats `x` as
-  ## unsigned.
-proc ze64*(x: int): int64 {.magic: "ZeIToI64", noSideEffect.}
-  ## zero extends a smaller integer type to ``int64``. This treats `x` as
-  ## unsigned. Does nothing if the size of an ``int`` is the same as ``int64``.
-  ## (This is the case on 64 bit processors.)
-
-proc toU8*(x: int): int8 {.magic: "ToU8", noSideEffect.}
-  ## treats `x` as unsigned and converts it to a byte by taking the last 8 bits
-  ## from `x`.
-proc toU16*(x: int): int16 {.magic: "ToU16", noSideEffect.}
-  ## treats `x` as unsigned and converts it to an ``int16`` by taking the last
-  ## 16 bits from `x`.
-proc toU32*(x: int64): int32 {.magic: "ToU32", noSideEffect.}
-  ## treats `x` as unsigned and converts it to an ``int32`` by taking the
-  ## last 32 bits from `x`.
-
+when not defined(JS):
+  proc ze*(x: int8): int {.magic: "Ze8ToI", noSideEffect.}
+    ## zero extends a smaller integer type to ``int``. This treats `x` as
+    ## unsigned.
+  proc ze*(x: int16): int {.magic: "Ze16ToI", noSideEffect.}
+    ## zero extends a smaller integer type to ``int``. This treats `x` as
+    ## unsigned.
+
+  proc ze64*(x: int8): int64 {.magic: "Ze8ToI64", noSideEffect.}
+    ## zero extends a smaller integer type to ``int64``. This treats `x` as
+    ## unsigned.
+  proc ze64*(x: int16): int64 {.magic: "Ze16ToI64", noSideEffect.}
+    ## zero extends a smaller integer type to ``int64``. This treats `x` as
+    ## unsigned.
+
+  proc ze64*(x: int32): int64 {.magic: "Ze32ToI64", noSideEffect.}
+    ## zero extends a smaller integer type to ``int64``. This treats `x` as
+    ## unsigned.
+  proc ze64*(x: int): int64 {.magic: "ZeIToI64", noSideEffect.}
+    ## zero extends a smaller integer type to ``int64``. This treats `x` as
+    ## unsigned. Does nothing if the size of an ``int`` is the same as ``int64``.
+    ## (This is the case on 64 bit processors.)
+
+  proc toU8*(x: int): int8 {.magic: "ToU8", noSideEffect.}
+    ## treats `x` as unsigned and converts it to a byte by taking the last 8 bits
+    ## from `x`.    
+  proc toU16*(x: int): int16 {.magic: "ToU16", noSideEffect.}
+    ## treats `x` as unsigned and converts it to an ``int16`` by taking the last
+    ## 16 bits from `x`.
+  proc toU32*(x: int64): int32 {.magic: "ToU32", noSideEffect.}
+    ## treats `x` as unsigned and converts it to an ``int32`` by taking the
+    ## last 32 bits from `x`.
 
 # integer calculations:
 proc `+` *(x: int): int {.magic: "UnaryPlusI", noSideEffect.}
@@ -1330,7 +1330,7 @@ iterator `||`*[S, T](a: S, b: T, annotation=""): T {.
   ## such isn't aware of the parallelism in your code! Be careful! Later
   ## versions of ``||`` will get proper support by Nimrod's code generator
   ## and GC.
-  nil
+  discard
 
 {.push stackTrace:off.}
 proc min*(x, y: int): int {.magic: "MinI", noSideEffect.} =
diff --git a/lib/system/excpt.nim b/lib/system/excpt.nim
index 1964e4d3d..a3f6669d4 100644
--- a/lib/system/excpt.nim
+++ b/lib/system/excpt.nim
@@ -11,7 +11,7 @@
 # use the heap (and nor exceptions) do not include the GC or memory allocator.
 
 var
-  errorMessageWriter*: (proc(msg: string): void {.tags: [FWriteIO].})
+  errorMessageWriter*: (proc(msg: string) {.tags: [FWriteIO].})
     ## Function that will be called
     ## instead of stdmsg.write when printing stacktrace.
     ## Unstable API.
@@ -80,9 +80,9 @@ when defined(nativeStacktrace) and nativeStackTraceSupported:
   type
     TDl_info {.importc: "Dl_info", header: "<dlfcn.h>", 
                final, pure.} = object
-      dli_fname: CString
+      dli_fname: cstring
       dli_fbase: pointer
-      dli_sname: CString
+      dli_sname: cstring
       dli_saddr: pointer
 
   proc backtrace(symbols: ptr pointer, size: int): int {.
diff --git a/lib/system/jssys.nim b/lib/system/jssys.nim
index 850dd1e11..4fc5f479b 100644
--- a/lib/system/jssys.nim
+++ b/lib/system/jssys.nim
@@ -472,17 +472,17 @@ proc Ze(a: int): int {.compilerproc.} =
 proc Ze64(a: int64): int64 {.compilerproc.} =
   result = a
 
-proc toU8(a: int): int8 {.noStackFrame, compilerproc.} =
+proc ToU8(a: int): int8 {.noStackFrame, compilerproc.} =
   asm """
     return `a`;
   """
 
-proc toU16(a: int): int16 {.noStackFrame, compilerproc.} =
+proc ToU16(a: int): int16 {.noStackFrame, compilerproc.} =
   asm """
     return `a`;
   """
 
-proc toU32(a: int): int32 {.noStackFrame, compilerproc.} =
+proc ToU32(a: int): int32 {.noStackFrame, compilerproc.} =
   asm """
     return `a`;
   """
diff --git a/tests/assert/tfailedassert.nim b/tests/assert/tfailedassert.nim
index d99e6dc60..263893767 100644
--- a/tests/assert/tfailedassert.nim
+++ b/tests/assert/tfailedassert.nim
@@ -3,7 +3,7 @@ discard """
 WARNING: false first asseertion from bar
 ERROR: false second assertion from bar
 -1
-tests/run/tfailedassert.nim:27 false assertion from foo
+tests/assert/tfailedassert.nim:27 false assertion from foo
 '''
 """
 
diff --git a/tests/closure/tnamedparamanonproc.nim b/tests/closure/tnamedparamanonproc.nim
index 272b84e91..94e32894f 100644
--- a/tests/closure/tnamedparamanonproc.nim
+++ b/tests/closure/tnamedparamanonproc.nim
@@ -4,8 +4,8 @@ type
   TButtonClicked = proc(button: PButton) {.nimcall.}
 
 proc newButton*(onClick: TButtonClicked) =
-  nil
-  
+  discard
+
 proc main() =
   newButton(onClick = proc(b: PButton) =
     var requestomat = 12
diff --git a/tests/block/tblock1.nim b/tests/controlflow/tblock1.nim
index 5c41aaf82..5c41aaf82 100644
--- a/tests/block/tblock1.nim
+++ b/tests/controlflow/tblock1.nim
diff --git a/tests/ifstmt/tnestif.nim b/tests/controlflow/tnestif.nim
index bfcd8751c..bfcd8751c 100644
--- a/tests/ifstmt/tnestif.nim
+++ b/tests/controlflow/tnestif.nim
diff --git a/tests/iter/tanoniter1.nim b/tests/iter/tanoniter1.nim
new file mode 100644
index 000000000..9db5ab8ec
--- /dev/null
+++ b/tests/iter/tanoniter1.nim
@@ -0,0 +1,32 @@
+discard """
+  output: '''1
+2
+3
+4
+1
+2'''
+"""
+
+proc factory(a, b: int): iterator (): int =
+  iterator foo(): int =
+    var x = a
+    while x <= b:
+      yield x
+      inc x
+  return foo
+
+proc factory2(a, b: int): iterator (): int =
+  return iterator (): int =
+    var x = a
+    while x <= b:
+      yield x
+      inc x
+
+let foo = factory 1, 4
+
+for f in foo():
+  echo f
+
+let foo2 = factory2 1,2
+
+for f in foo2(): echo f
diff --git a/tests/iter/titer2.nim b/tests/iter/titer2.nim
index dab2713e8..f8967109e 100644
--- a/tests/iter/titer2.nim
+++ b/tests/iter/titer2.nim
@@ -1,6 +1,6 @@
 discard """
   output: '''true'''
-  cmd: "nimrod cc --gc:none --hints:on $# $#"
+  cmd: "nimrod cc --gc:none --hints:on --warnings:off $# $#"
 """
 
 import hashes
diff --git a/tests/macros/tmemit.nim b/tests/macros/tmemit.nim
new file mode 100644
index 000000000..e4bb2daed
--- /dev/null
+++ b/tests/macros/tmemit.nim
@@ -0,0 +1,7 @@
+discard """
+  out: '''HELLO WORLD'''
+"""
+
+import macros, strutils
+
+emit("echo " & '"' & "hello world".toUpper & '"')
diff --git a/tests/static/tstaticparams.nim b/tests/metatype/tstaticparams.nim
index b1377443b..b1377443b 100644
--- a/tests/static/tstaticparams.nim
+++ b/tests/metatype/tstaticparams.nim
diff --git a/tests/object/tobjconstr.nim b/tests/objects/tobjconstr.nim
index 3bd785728..3bd785728 100644
--- a/tests/object/tobjconstr.nim
+++ b/tests/objects/tobjconstr.nim
diff --git a/tests/object/tobjconstr2.nim b/tests/objects/tobjconstr2.nim
index cb47e146d..cb47e146d 100644
--- a/tests/object/tobjconstr2.nim
+++ b/tests/objects/tobjconstr2.nim
diff --git a/tests/object/tobjcov.nim b/tests/objects/tobjcov.nim
index fc44edf8e..fc44edf8e 100644
--- a/tests/object/tobjcov.nim
+++ b/tests/objects/tobjcov.nim
diff --git a/tests/object/tobject.nim b/tests/objects/tobject.nim
index 5fec84441..5fec84441 100644
--- a/tests/object/tobject.nim
+++ b/tests/objects/tobject.nim
diff --git a/tests/object/tobject2.nim b/tests/objects/tobject2.nim
index 0f1869695..0f1869695 100644
--- a/tests/object/tobject2.nim
+++ b/tests/objects/tobject2.nim
diff --git a/tests/object/tobject3.nim b/tests/objects/tobject3.nim
index 935e6ca8c..935e6ca8c 100644
--- a/tests/object/tobject3.nim
+++ b/tests/objects/tobject3.nim
diff --git a/tests/operator/tofopr.nim b/tests/objects/tofopr.nim
index 961d81bd3..961d81bd3 100644
--- a/tests/operator/tofopr.nim
+++ b/tests/objects/tofopr.nim
diff --git a/tests/object/toop.nim b/tests/objects/toop.nim
index 0b42c2c22..0b42c2c22 100644
--- a/tests/object/toop.nim
+++ b/tests/objects/toop.nim
diff --git a/tests/object/toop1.nim b/tests/objects/toop1.nim
index 350799f51..350799f51 100644
--- a/tests/object/toop1.nim
+++ b/tests/objects/toop1.nim
diff --git a/tests/parser/tcommand_as_expr.nim b/tests/parser/tcommand_as_expr.nim
new file mode 100644
index 000000000..f6868a2fc
--- /dev/null
+++ b/tests/parser/tcommand_as_expr.nim
@@ -0,0 +1,12 @@
+discard """
+  output: "12"
+"""
+
+proc foo(x: int): int = x-1
+proc foo(x, y: int): int = x-y
+
+let x = foo 7.foo,  # comment here
+            foo(1, foo 8)
+#  12 =       6     -     -6
+echo x
+
diff --git a/tests/parser/tdomulttest.nim b/tests/parser/tdomulttest.nim
new file mode 100644
index 000000000..4ee6de128
--- /dev/null
+++ b/tests/parser/tdomulttest.nim
@@ -0,0 +1,17 @@
+discard """
+  file: "tdomulttest.nim"
+  output: "555\ntest\nmulti lines\n99999999\nend"
+  disabled: true
+"""
+proc foo(bar, baz: proc (x: int): int) =
+  echo bar(555)
+  echo baz(99999999)
+
+foo do (x: int) -> int:
+  return x
+do (x: int) -> int:
+  echo("test")
+  echo("multi lines")
+  return x
+
+echo("end")
\ No newline at end of file
diff --git a/tests/parser/tinvwhen.nim b/tests/parser/tinvwhen.nim
new file mode 100644
index 000000000..5ff94cc6c
--- /dev/null
+++ b/tests/parser/tinvwhen.nim
@@ -0,0 +1,15 @@
+discard """
+  file: "tinvwhen.nim"
+  line: 11
+  errormsg: "invalid indentation"
+"""
+# This was parsed even though it should not!

+

+proc chdir(path: cstring): cint {.importc: "chdir", header: "dirHeader".}

+

+proc getcwd(buf: cstring, buflen: cint): cstring

+    when defined(unix): {.importc: "getcwd", header: "<unistd.h>".} #ERROR_MSG invalid indentation

+    elif defined(windows): {.importc: "getcwd", header: "<direct.h>"}

+    else: {.error: "os library not ported to your OS. Please help!".}

+
+
diff --git a/tests/operator/toprprec.nim b/tests/parser/toprprec.nim
index ce33934b5..ce33934b5 100644
--- a/tests/operator/toprprec.nim
+++ b/tests/parser/toprprec.nim
diff --git a/tests/operator/tprecedence.nim b/tests/parser/tprecedence.nim
index 6b1b250a2..6b1b250a2 100644
--- a/tests/operator/tprecedence.nim
+++ b/tests/parser/tprecedence.nim
diff --git a/tests/pattern/tpatterns.nim b/tests/patterns/tpatterns.nim
index 6bc8772e3..6bc8772e3 100644
--- a/tests/pattern/tpatterns.nim
+++ b/tests/patterns/tpatterns.nim
diff --git a/tests/pragma/tuserpragma.nim b/tests/pragmas/tuserpragma.nim
index 784baa176..784baa176 100644
--- a/tests/pragma/tuserpragma.nim
+++ b/tests/pragmas/tuserpragma.nim
diff --git a/tests/important/tdrdobbs_examples.nim b/tests/showoff/tdrdobbs_examples.nim
index d1e0585d2..d1e0585d2 100644
--- a/tests/important/tdrdobbs_examples.nim
+++ b/tests/showoff/tdrdobbs_examples.nim
diff --git a/todo.txt b/todo.txt
index 21416f279..d0aec9c8c 100644
--- a/todo.txt
+++ b/todo.txt
@@ -1,18 +1,8 @@
 version 0.9.4
 =============
 
-- test&finish first class iterators:
-  * nested iterators
-- ensure (ref T)(a, b) works as a type conversion and type constructor
+- better debugging support for writes to locations
 - document new templating symbol binding rules
-- make '--implicitStatic:on' the default
-
-- special rule for ``[]=``
-- ``=`` should be overloadable; requires specialization for ``=``; general
-  lift mechanism in the compiler is already implemented for 'fields'
-- built-in 'getImpl'
-- optimize 'genericReset'; 'newException' leads to code bloat
-- stack-less GC
 - fix eval in macros.nim
 
 
@@ -27,8 +17,6 @@ Bugs
 - docgen: sometimes effects are listed twice
 - 'result' is not properly cleaned for NRVO --> use uninit checking instead
 - sneaking with qualifiedLookup() is really broken!
-- aporia.nim(968, 5) Error: ambiguous identifier: 'DELETE' -- 
-  use a qualifier
 - blocks can "export" an identifier but the CCG generates {} for them ...
 - osproc execProcesses can deadlock if all processes fail (as experienced
   in c++ mode)
@@ -37,12 +25,29 @@ Bugs
 version 0.9.x
 =============
 
-- macros as type pragmas
+- ensure (ref T)(a, b) works as a type conversion and type constructor
+- optimize 'genericReset'; 'newException' leads to code bloat
+- stack-less GC
+- implement strongSpaces:on
+- make '--implicitStatic:on' the default
 - implicit deref for parameter matching
+
+- special rule for ``[]=``
+- ``=`` should be overloadable; requires specialization for ``=``; general
+  lift mechanism in the compiler is already implemented for 'fields'
+- built-in 'getImpl'
+
+- change comment handling in the AST; that's lots of work as c2nim and pas2nim
+  make use of the fast every node can have a comment!
+
+
+version 0.9.X
+=============
+
+- macros as type pragmas
 - lazy overloading resolution:
   * special case ``tyStmt``
 - FFI:
-  * test libffi on windows
   * test: times.format with the FFI
 - document NimMain and check whether it works for threading
 - 'quote' without 'do' doesn't work: parser/grammar issue; could be supported
@@ -54,7 +59,6 @@ version 0.9.X
 - implement the missing features wrt inheritance
 - better support for macros that rewrite procs
 - macros need access to types and symbols (partially implemented)
-- perhaps: change comment handling in the AST
 - enforce 'simpleExpr' more often --> doesn't work; tkProc is
   part of primary!
 - the typeDesc/expr unification is weird and only necessary because of
diff --git a/tools/nimweb.nim b/tools/nimweb.nim
index 84b790248..56d6bcadb 100644
--- a/tools/nimweb.nim
+++ b/tools/nimweb.nim
@@ -204,6 +204,18 @@ proc exec(cmd: string) =
   echo(cmd)
   if os.execShellCmd(cmd) != 0: quit("external program failed")
 
+proc buildDocSamples(c: var TConfigData, destPath: string) =
+  ## Special case documentation sample proc.
+  ##
+  ## The docgen sample needs to be generated twice with different commands, so
+  ## it didn't make much sense to integrate into the existing generic
+  ## documentation builders.
+  const src = "doc"/"docgen_sample.nim"
+  Exec("nimrod doc $# -o:$# $#" %
+    [c.nimrodArgs, destPath / "docgen_sample.html", src])
+  Exec("nimrod doc2 $# -o:$# $#" %
+    [c.nimrodArgs, destPath / "docgen_sample2.html", src])
+
 proc buildDoc(c: var TConfigData, destPath: string) =
   # call nim for the documentation:
   for d in items(c.doc):
@@ -352,7 +364,9 @@ proc main(c: var TConfigData) =
   copyDir("web/assets", "web/upload/assets")
   buildNewsRss(c, "web/upload")
   buildAddDoc(c, "web/upload")
+  buildDocSamples(c, "web/upload")
   buildDoc(c, "web/upload")
+  buildDocSamples(c, "doc")
   buildDoc(c, "doc")
   buildPdfDoc(c, "doc")
 
diff --git a/web/news.txt b/web/news.txt
index 1ed447009..a045eb880 100644
--- a/web/news.txt
+++ b/web/news.txt
@@ -28,8 +28,8 @@ Changes affecting backwards compatibility
   require an error code to be passed to them. This error code can be retrieved
   using the new ``OSLastError`` proc.
 - ``os.parentDir`` now returns "" if there is no parent dir.
-- In CGI scripts stacktraces are shown user only if cgi.setStackTraceStdout
-  is used.
+- In CGI scripts stacktraces are shown to the user only 
+  if ``cgi.setStackTraceStdout`` is used.
 - The symbol binding rules for clean templates changed: ``bind`` for any
   symbol that's not a parameter is now the default. ``mixin`` can be used
   to require instantiation scope for a symbol.
@@ -71,8 +71,11 @@ Language Additions
 - Added a new ``delegator pragma`` for handling calls to missing procs and
   fields at compile-time.
 - The overload resolution now supports ``static[T]`` params that must be
-  evaluatable at compile-time.
+  evaluable at compile-time.
 - Support for user-defined type classes has been added.
+- The *command syntax* is supported in a lot more contexts.
+- Anonymous iterators are now supported and iterators can capture variables
+  of an outer proc.
 
 
 Tools improvements
diff --git a/web/nimrod.ini b/web/nimrod.ini
index 6942f20a9..9af3bc226 100644
--- a/web/nimrod.ini
+++ b/web/nimrod.ini
@@ -37,7 +37,7 @@ 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;c2nim;niminst;nimgrep;gc;estp;idetools"
+doc: "tools;c2nim;niminst;nimgrep;gc;estp;idetools;docgen"
 pdf: "manual;lib;tut1;tut2;nimrodc;c2nim;niminst;gc"
 srcdoc2: "system.nim;impure/graphics;wrappers/sdl"
 srcdoc2: "core/macros;pure/marshal;core/typeinfo;core/unsigned"