summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--compiler/lambdalifting.nim54
-rw-r--r--doc/manual.txt16
-rw-r--r--tests/closure/tnamedparamanonproc.nim4
-rw-r--r--todo.txt35
4 files changed, 76 insertions, 33 deletions
diff --git a/compiler/lambdalifting.nim b/compiler/lambdalifting.nim
index 352b40693..a9c4a8757 100644
--- a/compiler/lambdalifting.nim
+++ b/compiler/lambdalifting.nim
@@ -116,7 +116,7 @@ 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
     up: PEnv
@@ -544,19 +544,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))
@@ -577,6 +578,21 @@ 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
@@ -635,8 +651,16 @@ proc transformOuterProc(o: POuterContext, n: PNode): PNode =
 
     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:
+        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:
@@ -646,7 +670,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)
     
diff --git a/doc/manual.txt b/doc/manual.txt
index 9f84bc951..faf62dcee 100644
--- a/doc/manual.txt
+++ b/doc/manual.txt
@@ -2837,8 +2837,22 @@ 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.
 
-One always has to 
+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
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/todo.txt b/todo.txt
index 943d982c4..d0aec9c8c 100644
--- a/todo.txt
+++ b/todo.txt
@@ -1,20 +1,8 @@
 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
+- better debugging support for writes to locations
 - document new templating symbol binding rules
-- make '--implicitStatic:on' the default
-- change comment handling in the AST
-
-- 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
 
 
@@ -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