discard """ targets: "c cpp" output: "ok" """ var closureIterResult = newSeq[int]() proc checkpoint(arg: int) = closureIterResult.add(arg) type TestException = object of Exception AnotherException = object of Exception proc testClosureIterAux(it: iterator(): int, exceptionExpected: bool, expectedResults: varargs[int]) = closureIterResult.setLen(0) var exceptionCaught = false try: for i in it(): closureIterResult.add(i) except TestException: exceptionCaught = true if closureIterResult != @expectedResults or exceptionCaught != exceptionExpected: if closureIterResult != @expectedResults: echo "Expected: ", @expectedResults echo "Actual: ", closureIterResult if exceptionCaught != exceptionExpected: echo "Expected exception: ", exceptionExpected echo "Got exception: ", exceptionCaught doAssert(false) proc test(it: iterator(): int, expectedResults: varargs[int]) = testClosureIterAux(it, false, expectedResults) proc testExc(it: iterator(): int, expectedResults: varargs[int]) = testClosureIterAux(it, true, expectedResults) proc raiseException() = raise newException(TestException, "Test exception!") block: iterator it(): int {.closure.} = var i = 5 while i != 0: yield i if i == 3: yield 123 dec i test(it, 5, 4, 3, 123, 2, 1) block: iterator it(): int {.closure.} = yield 0 try: checkpoint(1) raiseException() except TestException: checkpoint(2) yield 3 checkpoint(4) finally: checkpoint(5) checkpoint(6) test(it, 0, 1, 2, 3, 4, 5, 6) block: iterator it(): int {.closure.} = yield 0 try: yield 1 checkpoint(2) finally: checkpoint(3) yield 4 checkpoint(5) yield 6 test(it, 0, 1, 2, 3, 4, 5, 6) block: iterator it(): int {.closure.} = yield 0 try: yield 1 raiseException() yield 2 finally: checkpoint(3) yield 4 checkpoint(5) yield 6 testExc(it, 0, 1, 3, 4, 5, 6) block: iterator it(): int {.closure.} = try: try: raiseException() except AnotherException: yield 123 finally: checkpoint(3) finally: checkpoint(4) testExc(it, 3, 4) block: iterator it(): int {.closure.} = try: yield 1 raiseException() except AnotherException: checkpoint(123) finally: checkpoint(2) checkpoint(3) testExc(it, 1, 2) block: iterator it(): int {.closure.} = try: yield 0 try: yield 1 try: yield 2 raiseException() except AnotherException: yield 123 finally: yield 3 except AnotherException: yield 124 finally: yield 4 checkpoint(1234) except: yield 5 checkpoint(6) finally: checkpoint(7) yield 8 checkpoint(9) test(it, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9) block: iterator it(): int {.closure.} = try: yield 0 return 2 finally: checkpoint(1) checkpoint(123) test(it, 0, 1) block: iterator it(): int {.closure.} = try: try: yield 0 raiseException() finally: checkpoint(1) except TestException: yield 2 return finally: yield 3 checkpoint(123) test(it, 0, 1, 2, 3) block: iterator it(): int {.closure.} = try: try: yield 0 raiseException() finally: return # Return in finally should stop exception propagation except AnotherException: yield 2 return finally: yield 3 checkpoint(123) test(it, 0, 3) block: # Yield in yield iterator it(): int {.closure.} = template foo(): int = yield 1 2 for i in 0 .. 2: checkpoint(0) yield foo() test(it, 0, 1, 2, 0, 1, 2, 0, 1, 2) block: iterator it(): int {.closure.} = let i = if true: yield 0 1 else: 2 yield i test(it, 0, 1) block: iterator it(): int {.closure.} = var foo = 123 let i = try: yield 0 raiseException() 1 except TestException as e: assert(e.msg == "Test exception!") case foo of 1: yield 123 2 of 123: yield 5 6 else: 7 yield i test(it, 0, 5, 6) block: iterator it(): int {.closure.} = proc voidFoo(i1, i2, i3: int) = checkpoint(i1) checkpoint(i2) checkpoint(i3) proc foo(i1, i2, i3: int): int = voidFoo(i1, i2, i3) i3 proc bar(i1: int): int = checkpoint(i1) template tryexcept: int = try: yield 1 raiseException() 123 except TestException: yield 2 checkpoint(3) 4 let e1 = true template ifelse1: int = if e1: yield 10 11 else: 12 template ifelse2: int = if ifelse1() == 12: yield 20 21 else: yield 22 23 let i = foo(bar(0), tryexcept, ifelse2) discard foo(bar(0), tryexcept, ifelse2) voidFoo(bar(0), tryexcept, ifelse2) yield i test(it, # let i = foo(bar(0), tryexcept, ifelse2) 0, # bar(0) 1, 2, 3, # tryexcept 10, # ifelse1 22, # ifelse22 0, 4, 23, # foo # discard foo(bar(0), tryexcept, ifelse2) 0, # bar(0) 1, 2, 3, # tryexcept 10, # ifelse1 22, # ifelse22 0, 4, 23, # foo # voidFoo(bar(0), tryexcept, ifelse2) 0, # bar(0) 1, 2, 3, # tryexcept 10, # ifelse1 22, # ifelse22 0, 4, 23, # foo 23 # i ) block: iterator it(): int {.closure.} = checkpoint(0) for i in 0 .. 1: try: yield 1 raiseException() except TestException as e: doAssert(e.msg == "Test exception!") yield 2 except AnotherException: yield 123 except: yield 1234 finally: yield 3 checkpoint(4) yield 5 test(it, 0, 1, 2, 3, 4, 5, 1, 2, 3, 4, 5) block: iterator it(): int {.closure.} = var i = 5 template foo(): bool = yield i true while foo(): dec i if i == 0: break test(it, 5, 4, 3, 2, 1) block: # Short cirquits iterator it(): int {.closure.} = template trueYield: bool = yield 1 true template falseYield: bool = yield 0 false if trueYield or falseYield: discard falseYield and trueYield if falseYield and trueYield: checkpoint(123) test(it, 1, 0, 0) block: #7969 type SomeObj = object id: int iterator it(): int {.closure.} = template yieldAndSomeObj: SomeObj = var s: SomeObj s.id = 2 yield 1 s checkpoint(yieldAndSomeObj().id) var i = 5 case i of 0: checkpoint(123) of 1, 2, 5: checkpoint(3) else: checkpoint(123) test(it, 1, 2, 3) block: # yield in blockexpr iterator it(): int {.closure.} = yield(block: checkpoint(1) yield 2 3 ) test(it, 1, 2, 3) block: #8851 type Foo = ref object of RootObj template someFoo(): Foo = var f: Foo yield 1 f iterator it(): int {.closure.} = var o: RootRef o = someFoo() test(it, 1) block: # 8243 iterator it(): int {.closure.} = template yieldAndSeq: seq[int] = yield 1 @[123, 5, 123] checkpoint(yieldAndSeq[1]) test(it, 1, 5) block: iterator it(): int {.closure.} = template yieldAndSeq: seq[int] = yield 1 @[123, 5, 123] template yieldAndNum: int = yield 2 1 checkpoint(yieldAndSeq[yieldAndNum]) test(it, 1, 2, 5) block: #9694 - yield in ObjConstr type Foo = object a, b: int template yieldAndNum: int = yield 1 2 iterator it(): int {.closure.} = let a = Foo(a: 5, b: yieldAndNum()) checkpoint(a.b) test(it, 1, 2) block: #9716 iterator it(): int {.closure.} = var a = 0 for i in 1 .. 3: var a: int # Make sure the "local" var is reset var b: string # ditto yield 1 a += 5 b &= "hello" doAssert(a == 5) doAssert(b == "hello") test(it, 1, 1, 1) block: # nnkChckRange type Foo = distinct uint64 template yieldDistinct: Foo = yield 2 Foo(0) iterator it(): int {.closure.} = yield 1 var a: int a = int(yieldDistinct()) yield 3 test(it, 1, 2, 3) echo "ok"