summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--compiler/ast.nim1
-rw-r--r--compiler/lambdalifting.nim134
-rw-r--r--compiler/lexer.nim2
-rw-r--r--compiler/parser.nim4
-rw-r--r--compiler/renderer.nim5
-rw-r--r--compiler/semstmts.nim11
-rw-r--r--compiler/transf.nim3
-rw-r--r--doc/manual.txt25
-rw-r--r--koch.nim9
-rw-r--r--lib/core/macros.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/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/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/showoff/tdrdobbs_examples.nim (renamed from tests/important/tdrdobbs_examples.nim)0
-rw-r--r--todo.txt1
28 files changed, 163 insertions, 70 deletions
diff --git a/compiler/ast.nim b/compiler/ast.nim
index 0e351a31a..82cc2c96f 100644
--- a/compiler/ast.nim
+++ b/compiler/ast.nim
@@ -287,6 +287,7 @@ const
 
   sfNoRoot* = sfBorrow # a local variable is provably no root so it doesn't
                        # require RC ops
+  sfClosureCreated* = sfDiscriminant # for transf-lambdalifting interaction
 
 const
   # getting ready for the future expr/stmt merge
diff --git a/compiler/lambdalifting.nim b/compiler/lambdalifting.nim
index ed92fefb4..2189a1d67 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
+    closure: 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
   
@@ -149,7 +149,19 @@ proc newInnerContext(fn: PSym): PInnerContext =
   new(result)
   result.fn = fn
   initIdNodeTable(result.localsToAccess)
-  
+
+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 newEnv(outerProc: PSym, up: PEnv, n: PNode): PEnv =
   new(result)
   result.deps = @[]
@@ -170,6 +182,9 @@ proc addField(tup: PType, s: PSym) =
 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 +204,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)
@@ -220,18 +236,30 @@ proc getHiddenParam(routine: PSym): PSym =
   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 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) =
@@ -344,6 +372,7 @@ proc transformOuterConv(n: PNode): PNode =
 proc makeClosure(prc, env: PSym, info: TLineInfo): PNode =
   result = newNodeIT(nkClosure, info, prc.typ)
   result.add(newSymNode(prc))
+  if prc.kind == skIterator: incl(prc.flags, sfClosureCreated)
   if env == nil:
     result.add(newNodeIT(nkNilLit, info, getSysType(tyNil)))
   else:
@@ -366,10 +395,10 @@ 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 nkProcDef, nkMethodDef, nkConverterDef, nkMacroDef, nkTemplateDef,
-     nkIteratorDef:
+  of nkLambdaKinds, nkIteratorDef:
+    if n.typ != nil:
+      result = transformInnerProc(o, i, n.sons[namePos])
+  of nkProcDef, nkMethodDef, nkConverterDef, nkMacroDef, nkTemplateDef:
     # don't recurse here:
     discard
   else:
@@ -400,8 +429,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
@@ -437,8 +467,7 @@ proc searchForInnerProcs(o: POuterContext, n: PNode) =
         searchForInnerProcs(o, it.sons[L-1])
       else:
         internalError(it.info, "transformOuter")
-  of nkProcDef, nkMethodDef, nkConverterDef, nkMacroDef, nkTemplateDef, 
-     nkIteratorDef:
+  of nkProcDef, nkMethodDef, nkConverterDef, nkMacroDef, nkTemplateDef:
     # don't recurse here:
     # XXX recurse here and setup 'up' pointers
     discard
@@ -535,10 +564,10 @@ 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:
     # don't recurse here:
     discard
   of nkHiddenStdConv, nkHiddenSubConv, nkConv:
@@ -607,11 +636,14 @@ type
     tup: PType
 
 proc newIterResult(iter: PSym): PSym =
-  result = iter.ast.sons[resultPos].sym
-  when false:
+  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 interestingIterVar(s: PSym): bool {.inline.} =
   result = s.kind in {skVar, skLet, skTemp, skForVar} and sfGlobal notin s.flags
@@ -663,36 +695,40 @@ proc transfIterBody(c: var TIterContext, n: PNode): PNode =
       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
+proc initIterContext(c: var TIterContext, iter: PSym) =
   c.iter = iter
   c.capturedVars = initIntSet()
 
-  c.tup = newType(tyTuple, iter)
-  c.tup.n = newNodeI(nkRecList, iter.info)
+  var cp = getEnvParam(iter)
+  if cp == nil:
+    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)
+    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 = newSym(skField, getIdent(":state"), iter, iter.info)
-  c.state.typ = getStateType(iter)
-  addField(c.tup, c.state)
+    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))
+    #iter.ast.add(newSymNode(c.resultSym))
+
+proc liftIterator*(iter: PSym, body: PNode): PNode =
+  var c: TIterContext
+  initIterContext c, iter
 
   result = newNodeI(nkStmtList, iter.info)
   var gs = newNodeI(nkGotoState, iter.info)
@@ -716,12 +752,14 @@ proc liftIterator*(iter: PSym, body: PNode): PNode =
 
 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
+  if sfClosureCreated in iter.flags: return n
+  
+  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 +804,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 d255949a4..2b845f3da 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.
@@ -31,7 +31,7 @@ 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
diff --git a/compiler/renderer.nim b/compiler/renderer.nim
index b5e3c0e74..6588caa04 100644
--- a/compiler/renderer.nim
+++ b/compiler/renderer.nim
@@ -1251,6 +1251,11 @@ 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)
   else: 
     #nkNone, nkExplicitTypeListCall: 
     internalError(n.info, "rnimsyn.gsub(" & $n.kind & ')')
diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim
index fc1706200..a26d89836 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
@@ -949,11 +951,13 @@ 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
 
     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)
@@ -996,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:
@@ -1078,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
diff --git a/compiler/transf.nim b/compiler/transf.nim
index f22433972..973e8848a 100644
--- a/compiler/transf.nim
+++ b/compiler/transf.nim
@@ -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))
diff --git a/doc/manual.txt b/doc/manual.txt
index c90373233..9f84bc951 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,10 @@ 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.
+
+One always has to 
+
 
 
 Type sections
@@ -2923,9 +2926,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 +3356,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/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 7cb084653..3b36e31e0 100644
--- a/lib/core/macros.nim
+++ b/lib/core/macros.nim
@@ -390,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)
@@ -415,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)
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/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/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/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 15ce93df7..943d982c4 100644
--- a/todo.txt
+++ b/todo.txt
@@ -3,6 +3,7 @@ version 0.9.4
 
 - test&finish first class iterators:
   * nested iterators
+- implement strongSpaces:on
 - ensure (ref T)(a, b) works as a type conversion and type constructor
 - document new templating symbol binding rules
 - make '--implicitStatic:on' the default