summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorAndreas Rumpf <rumpf_a@web.de>2016-01-03 23:20:53 +0100
committerAndreas Rumpf <rumpf_a@web.de>2016-01-03 23:20:53 +0100
commitb4c62d5fedf155cbab57cfeead97eccc94345c71 (patch)
treeb424e6e98ecd20bef623e34e36900b0e0189708b
parent813f98fb342418606f82a082373636137b811bae (diff)
downloadNim-b4c62d5fedf155cbab57cfeead97eccc94345c71.tar.gz
async works again
-rw-r--r--compiler/lambdalifting.nim48
-rw-r--r--tests/closure/tclosure0.nim87
-rw-r--r--tests/iter/tclosureiters.nim73
3 files changed, 188 insertions, 20 deletions
diff --git a/compiler/lambdalifting.nim b/compiler/lambdalifting.nim
index 378f3a187..8150e30c8 100644
--- a/compiler/lambdalifting.nim
+++ b/compiler/lambdalifting.nim
@@ -451,15 +451,19 @@ proc newEnvVar(owner: PSym; typ: PType): PNode =
   var v = newSym(skVar, getIdent(envName), owner, owner.info)
   incl(v.flags, sfShadowed)
   v.typ = typ
-  if owner.kind == skIterator and owner.typ.callConv == ccClosure:
-    let it = getHiddenParam(owner)
-    addUniqueField(it.typ.sons[0], v)
-    result = indirectAccess(newSymNode(it), v, v.info)
-  else:
-    result = newSymNode(v)
+  result = newSymNode(v)
+  when false:
+    if owner.kind == skIterator and owner.typ.callConv == ccClosure:
+      let it = getHiddenParam(owner)
+      addUniqueField(it.typ.sons[0], v)
+      result = indirectAccess(newSymNode(it), v, v.info)
+    else:
+      result = newSymNode(v)
 
 proc setupEnvVar(owner: PSym; d: DetectionPass;
                  c: var LiftingPass): PNode =
+  if owner.isIterator:
+    return getHiddenParam(owner).newSymNode
   result = c.envvars.getOrDefault(owner.id)
   if result.isNil:
     let envVarType = d.ownerToType.getOrDefault(owner.id)
@@ -482,20 +486,24 @@ proc rawClosureCreation(owner: PSym;
                         d: DetectionPass; c: var LiftingPass): PNode =
   result = newNodeI(nkStmtList, owner.info)
 
-  let env = setupEnvVar(owner, d, c)
-  if env.kind == nkSym:
-    var v = newNodeI(nkVarSection, env.info)
-    addVar(v, env)
-    result.add(v)
-  # add 'new' statement:
-  result.add(newCall(getSysSym"internalNew", env))
-  # add assignment statements for captured parameters:
-  for i in 1..<owner.typ.n.len:
-    let local = owner.typ.n[i].sym
-    if local.id in d.capturedVars:
-      let fieldAccess = indirectAccess(env, local, env.info)
-      # add ``env.param = param``
-      result.add(newAsgnStmt(fieldAccess, newSymNode(local), env.info))
+  var env: PNode
+  if owner.isIterator:
+    env = getHiddenParam(owner).newSymNode
+  else:
+    env = setupEnvVar(owner, d, c)
+    if env.kind == nkSym:
+      var v = newNodeI(nkVarSection, env.info)
+      addVar(v, env)
+      result.add(v)
+    # add 'new' statement:
+    result.add(newCall(getSysSym"internalNew", env))
+    # add assignment statements for captured parameters:
+    for i in 1..<owner.typ.n.len:
+      let local = owner.typ.n[i].sym
+      if local.id in d.capturedVars:
+        let fieldAccess = indirectAccess(env, local, env.info)
+        # add ``env.param = param``
+        result.add(newAsgnStmt(fieldAccess, newSymNode(local), env.info))
 
   let upField = lookupInRecord(env.typ.lastSon.n, getIdent(upName))
   if upField != nil:
diff --git a/tests/closure/tclosure0.nim b/tests/closure/tclosure0.nim
new file mode 100644
index 000000000..9952268d5
--- /dev/null
+++ b/tests/closure/tclosure0.nim
@@ -0,0 +1,87 @@
+discard """
+  output: '''foo88
+23 24foo 88
+18
+18
+99
+99
+99
+99 99
+99 99
+12 99 99
+12 99 99'''
+"""
+
+when true:
+  # test simple closure within dummy 'main':
+  proc dummy =
+    proc main2(param: int) =
+      var fooB = 23
+      proc outer(outerParam: string) =
+        var outerVar = 88
+        echo outerParam, outerVar
+        proc inner() =
+          block Test:
+            echo fooB, " ", param, outerParam, " ", outerVar
+        inner()
+      outer("foo")
+    main2(24)
+
+  dummy()
+
+when true:
+  proc outer2(x:int) : proc(y:int):int =   # curry-ed application
+      return proc(y:int):int = x*y
+
+  var fn = outer2(6)  # the closure
+  echo fn(3)   # it works
+
+  var rawP = fn.rawProc()
+  var rawE = fn.rawEnv()
+
+  # A type to cast the function pointer into a nimcall
+  type
+    TimesClosure = proc(a: int, x: pointer): int {.nimcall.}
+
+  # Call the function with its closure
+  echo cast[TimesClosure](rawP)(3, rawE)
+
+when true:
+  proc outer =
+    var x, y: int = 99
+    proc innerA = echo x
+    proc innerB =
+      echo y
+      innerA()
+
+    innerA()
+    innerB()
+
+  outer()
+
+when true:
+  proc indirectDep =
+    var x, y: int = 99
+    proc innerA = echo x, " ", y
+    proc innerB =
+      innerA()
+
+    innerA()
+    innerB()
+
+  indirectDep()
+
+when true:
+  proc needlessIndirection =
+    var x, y: int = 99
+    proc indirection =
+      var z = 12
+      proc innerA = echo z, " ", x, " ", y
+      proc innerB =
+        innerA()
+
+      innerA()
+      innerB()
+    indirection()
+
+  needlessIndirection()
diff --git a/tests/iter/tclosureiters.nim b/tests/iter/tclosureiters.nim
new file mode 100644
index 000000000..0eb624a8c
--- /dev/null
+++ b/tests/iter/tclosureiters.nim
@@ -0,0 +1,73 @@
+discard """
+  output: '''0
+1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+5 5
+7 7
+9 9
+0
+0
+0
+0
+1
+2'''
+"""
+
+when true:
+  proc main() =
+    let
+      lo=0
+      hi=10
+
+    iterator itA(): int =
+      for x in lo..hi:
+        yield x
+
+    for x in itA():
+      echo x
+
+    var y: int
+
+    iterator itB(): int =
+      while y <= hi:
+        yield y
+        inc y
+
+    y = 5
+    for x in itB():
+      echo x, " ", y
+      inc y
+
+  main()
+
+
+iterator infinite(): int {.closure.} =
+  var i = 0
+  while true:
+    yield i
+    inc i
+
+iterator take[T](it: iterator (): T, numToTake: int): T {.closure.} =
+  var i = 0
+  for x in it():
+    if i >= numToTake:
+      break
+    yield x
+    inc i
+
+# gives wrong reasult (3 times 0)
+for x in infinite.take(3):
+  echo x
+
+# does what we want
+let inf = infinite
+for x in inf.take(3):
+  echo x