More elaborate nkStmtListExpr lowering

This commit is contained in:
Yuriy Glukhov
2018-05-08 01:25:08 +03:00
parent ac86b8ce61
commit 14ca79fe1f
2 changed files with 696 additions and 185 deletions

View File

@@ -149,7 +149,6 @@ type
exitStateIdx: int # index of the last state
tempVarId: int # unique name counter
tempVars: PNode # Temp var decls, nkVarSection
loweredStmtListExpr: PNode # Temporary used for nkStmtListExpr lowering
exceptionTable: seq[int] # For state `i` jump to state `exceptionTable[i]` if exception is raised
hasExceptions: bool # Does closure have yield in try?
curExcHandlingState: int # Negative for except, positive for finally
@@ -177,6 +176,7 @@ proc newStateAssgn(ctx: var Ctx, stateNo: int = -2): PNode =
proc newEnvVar(ctx: var Ctx, name: string, typ: PType): PSym =
result = newSym(skVar, getIdent(name), ctx.fn, ctx.fn.info)
result.typ = typ
assert(not typ.isNil)
if not ctx.stateVarSym.isNil:
# We haven't gone through labmda lifting yet, so just create a local var,
@@ -197,7 +197,6 @@ proc newEnvVarAccess(ctx: Ctx, s: PSym): PNode =
proc newTmpResultAccess(ctx: var Ctx): PNode =
if ctx.tmpResultSym.isNil:
debug(ctx.fn.typ)
ctx.tmpResultSym = ctx.newEnvVar(":tmpResult", ctx.fn.typ[0])
ctx.newEnvVarAccess(ctx.tmpResultSym)
@@ -245,9 +244,8 @@ proc addGotoOut(n: PNode, gotoOut: PNode): PNode =
if result.len != 0 and result.sons[^1].kind != nkGotoState:
result.add(gotoOut)
proc newTempVarAccess(ctx: var Ctx, typ: PType, i: TLineInfo): PNode =
let s = ctx.newEnvVar(":tmpSlLower" & $ctx.tempVarId, typ)
result = ctx.newEnvVarAccess(s)
proc newTempVar(ctx: var Ctx, typ: PType): PSym =
result = ctx.newEnvVar(":tmpSlLower" & $ctx.tempVarId, typ)
inc ctx.tempVarId
proc hasYields(n: PNode): bool =
@@ -390,35 +388,382 @@ proc hasYieldsInExpressions(n: PNode): bool =
nkSym, nkIdent, procDefs, nkTemplateDef:
discard
of nkStmtListExpr:
result = n.hasYields
of nkStmtList, nkWhileStmt, nkCaseStmt, nkIfStmt:
discard
if isEmptyType(n.typ):
for c in n:
if c.hasYieldsInExpressions:
return true
else:
result = n.hasYields
else:
for c in n:
if c.hasYieldsInExpressions:
return true
proc lowerStmtListExpr(ctx: var Ctx, n: PNode): PNode =
proc exprToStmtList(n: PNode): tuple[s, res: PNode] =
assert(n.kind == nkStmtListExpr)
var parent = n
var lastSon = n[^1]
while lastSon.kind == nkStmtListExpr:
parent = lastSon
lastSon = lastSon[^1]
result.s = newNodeI(nkStmtList, n.info)
result.s.sons = parent.sons
result.s.sons.setLen(result.s.sons.len - 1) # delete last son
result.res = lastSon
proc newEnvVarAsgn(ctx: Ctx, s: PSym, v: PNode): PNode =
result = newNode(nkFastAsgn)
result.add(ctx.newEnvVarAccess(s))
result.add(v)
proc addExprAssgn(ctx: Ctx, output, input: PNode, sym: PSym) =
if input.kind == nkStmtListExpr:
let (st, res) = exprToStmtList(input)
output.add(st)
output.add(ctx.newEnvVarAsgn(sym, res))
else:
output.add(ctx.newEnvVarAsgn(sym, input))
proc convertExprBodyToAsgn(ctx: Ctx, exprBody: PNode, res: PSym): PNode =
result = newNode(nkStmtList)
ctx.addExprAssgn(result, exprBody, res)
proc newNotCall(e: PNode): PNode =
result = newNode(nkCall)
result.add(newSymNode(getSysMagic("not", mNot)))
result.add(e)
result.typ = getSysType(tyBool)
proc lowerStmtListExprs(ctx: var Ctx, n: PNode, needsSplit: var bool): PNode =
result = n
case n.kind
of nkCharLit..nkUInt64Lit, nkFloatLit..nkFloat128Lit, nkStrLit..nkTripleStrLit,
nkSym, nkIdent, procDefs, nkTemplateDef:
discard
of nkStmtListExpr:
if n.hasYields:
for i in 0 .. n.len - 2:
ctx.loweredStmtListExpr.add(n[i])
let tv = ctx.newTempVarAccess(n.typ, n[^1].info)
let asgn = newNode(nkAsgn)
asgn.add(tv)
asgn.add(n[^1])
ctx.loweredStmtListExpr.add(asgn)
result = tv
of nkYieldStmt:
var ns = false
for i in 0 ..< n.len:
n[i] = ctx.lowerStmtListExprs(n[i], ns)
if ns:
assert(n[0].kind == nkStmtListExpr)
result = newNodeI(nkStmtList, n.info)
let (st, ex) = exprToStmtList(n[0])
result.add(st)
n[0] = ex
result.add(n)
needsSplit = true
of nkPar, nkObjConstr, nkTupleConstr, nkBracket, nkArgList:
var ns = false
for i in 0 ..< n.len:
n[i] = ctx.lowerStmtListExprs(n[i], ns)
if ns:
needsSplit = true
result = newNodeI(nkStmtListExpr, n.info)
if n.typ.isNil: internalError("lowerStmtListExprs: constr typ.isNil")
result.typ = n.typ
for i in 0 ..< n.len:
if n[i].kind == nkStmtListExpr:
let (st, ex) = exprToStmtList(n[i])
result.add(st)
n[i] = ex
result.add(n)
of nkIfStmt, nkIfExpr:
var ns = false
for i in 0 ..< n.len:
n[i] = ctx.lowerStmtListExprs(n[i], ns)
if ns:
needsSplit = true
var tmp: PSym
var s: PNode
let isExpr = not isEmptyType(n.typ)
if isExpr:
tmp = ctx.newTempVar(n.typ)
result = newNode(nkStmtListExpr)
result.typ = n.typ
else:
result = newNode(nkStmtList)
var curS = result
for branch in n:
case branch.kind
of nkElseExpr, nkElse:
if isExpr:
var newBranch = newNodeI(nkElse, branch.info)
let branchBody = newNode(nkStmtList)
ctx.addExprAssgn(branchBody, branch[0], tmp)
newBranch.add(branchBody)
curS.add(newBranch)
else:
curS.add(branch)
of nkElifExpr, nkElifBranch:
var newBranch: PNode
if branch[0].kind == nkStmtListExpr:
let elseBody = newNode(nkStmtList)
let (st, res) = exprToStmtList(branch[0])
elseBody.add(st)
newBranch = newNodeI(nkElifBranch, branch.info)
newBranch.add(res)
newBranch.add(branch[1])
let newIf = newNodeI(nkIfStmt, branch.info)
newIf.add(newBranch)
elseBody.add(newIf)
if curS.kind == nkIfStmt:
let newElse = newNodeI(nkElse, branch.info)
newElse.add(elseBody)
curS.add(newElse)
else:
curS.add(elseBody)
curS = newIf
else:
newBranch = branch
if curS.kind == nkIfStmt:
curS.add(newBranch)
else:
let newIf = newNodeI(nkIfStmt, branch.info)
newIf.add(newBranch)
curS.add(newIf)
curS = newIf
if isExpr:
let branchBody = newNode(nkStmtList)
ctx.addExprAssgn(branchBody, branch[1], tmp)
newBranch[1] = branchBody
else:
internalError("lowerStmtListExpr(nkIf): " & $branch.kind)
if isExpr: result.add(ctx.newEnvVarAccess(tmp))
of nkTryStmt:
var ns = false
for i in 0 ..< n.len:
n[i] = ctx.lowerStmtListExprs(n[i], ns)
if ns:
needsSplit = true
let isExpr = not isEmptyType(n.typ)
if isExpr:
result = newNodeI(nkStmtListExpr, n.info)
result.typ = n.typ
let tmp = ctx.newTempVar(n.typ)
n[0] = ctx.convertExprBodyToAsgn(n[0], tmp)
for i in 1 ..< n.len:
let branch = n[i]
case branch.kind
of nkExceptBranch:
if branch[0].kind == nkType:
branch[1] = ctx.convertExprBodyToAsgn(branch[1], tmp)
else:
branch[0] = ctx.convertExprBodyToAsgn(branch[0], tmp)
of nkFinally:
discard
else:
internalError("lowerStmtListExpr(nkTryStmt): " & $branch.kind)
result.add(n)
result.add(ctx.newEnvVarAccess(tmp))
of nkCaseStmt:
var ns = false
for i in 0 ..< n.len:
n[i] = ctx.lowerStmtListExprs(n[i], ns)
if ns:
needsSplit = true
let isExpr = not isEmptyType(n.typ)
if isExpr:
let tmp = ctx.newTempVar(n.typ)
result = newNodeI(nkStmtListExpr, n.info)
result.typ = n.typ
if n[0].kind == nkStmtListExpr:
let (st, ex) = exprToStmtList(n[0])
result.add(st)
n[0] = ex
for i in 1 ..< n.len:
let branch = n[i]
case branch.kind
of nkOfBranch:
branch[1] = ctx.convertExprBodyToAsgn(branch[1], tmp)
of nkElse:
branch[0] = ctx.convertExprBodyToAsgn(branch[0], tmp)
else:
internalError("lowerStmtListExpr(nkCaseStmt): " & $branch.kind)
result.add(n)
result.add(ctx.newEnvVarAccess(tmp))
of nkCallKinds:
var ns = false
for i in 0 ..< n.len:
n[i] = ctx.lowerStmtListExprs(n[i], ns)
if ns:
needsSplit = true
let isExpr = not isEmptyType(n.typ)
if isExpr:
result = newNodeI(nkStmtListExpr, n.info)
result.typ = n.typ
else:
result = newNode(nkStmtList, n.info)
if n[0].kind == nkSym and n[0].sym.magic in {mAnd, mOr}: # `and`/`or` short cirquiting
var cond = n[1]
if cond.kind == nkStmtListExpr:
let (st, ex) = exprToStmtList(cond)
result.add(st)
cond = ex
let tmp = ctx.newTempVar(cond.typ)
result.add(ctx.newEnvVarAsgn(tmp, cond))
let ifNode = newNode(nkIfStmt)
let ifBranch = newNode(nkElifBranch)
var check = ctx.newEnvVarAccess(tmp)
if n[0].sym.magic == mOr:
check = newNotCall(check)
ifBranch.add(check)
cond = n[2]
let ifBody = newNode(nkStmtList)
if cond.kind == nkStmtListExpr:
let (st, ex) = exprToStmtList(cond)
ifBody.add(st)
cond = ex
ifBody.add(ctx.newEnvVarAsgn(tmp, cond))
ifBranch.add(ifBody)
ifNode.add(ifBranch)
result.add(ifNode)
result.add(ctx.newEnvVarAccess(tmp))
else:
for i in 0 ..< n.len:
if n[i].kind == nkStmtListExpr:
let (st, ex) = exprToStmtList(n[i])
result.add(st)
n[i] = ex
if n[i].kind in nkCallKinds: # XXX: This should better be some sort of side effect tracking
let tmp = ctx.newTempVar(n[i].typ)
result.add(ctx.newEnvVarAsgn(tmp, n[i]))
n[i] = ctx.newEnvVarAccess(tmp)
result.add(n)
of nkVarSection, nkLetSection:
result = newNodeI(nkStmtList, n.info)
for c in n:
let varSect = newNodeI(n.kind, n.info)
varSect.add(c)
var ns = false
c[^1] = ctx.lowerStmtListExprs(c[^1], ns)
if ns:
needsSplit = true
assert(c[^1].kind == nkStmtListExpr)
let (st, ex) = exprToStmtList(c[^1])
result.add(st)
c[^1] = ex
result.add(varSect)
of nkDiscardStmt, nkReturnStmt, nkRaiseStmt:
var ns = false
for i in 0 ..< n.len:
n[i] = ctx.lowerStmtListExprs(n[i], ns)
if ns:
needsSplit = true
result = newNodeI(nkStmtList, n.info)
let (st, ex) = exprToStmtList(n[0])
result.add(st)
n[0] = ex
result.add(n)
of nkCast:
var ns = false
for i in 0 ..< n.len:
n[i] = ctx.lowerStmtListExprs(n[i], ns)
if ns:
needsSplit = true
result = newNodeI(nkStmtListExpr, n.info)
result.typ = n.typ
let (st, ex) = exprToStmtList(n[1])
result.add(st)
n[1] = ex
result.add(n)
of nkAsgn, nkFastAsgn:
var ns = false
for i in 0 ..< n.len:
n[i] = ctx.lowerStmtListExprs(n[i], ns)
if ns:
needsSplit = true
result = newNodeI(nkStmtList, n.info)
if n[0].kind == nkStmtListExpr:
let (st, ex) = exprToStmtList(n[0])
result.add(st)
n[0] = ex
if n[1].kind == nkStmtListExpr:
let (st, ex) = exprToStmtList(n[1])
result.add(st)
n[1] = ex
result.add(n)
of nkWhileStmt:
var ns = false
var condNeedsSplit = false
n[0] = ctx.lowerStmtListExprs(n[0], condNeedsSplit)
var bodyNeedsSplit = false
n[1] = ctx.lowerStmtListExprs(n[1], bodyNeedsSplit)
if condNeedsSplit or bodyNeedsSplit:
needsSplit = true
if condNeedsSplit:
let newBody = newNode(nkStmtList)
let (st, ex) = exprToStmtList(n[0])
newBody.add(st)
let check = newNode(nkIfStmt)
let branch = newNode(nkElifBranch)
branch.add(newNotCall(ex))
let brk = newNode(nkBreakStmt)
brk.add(emptyNode)
branch.add(brk)
check.add(branch)
newBody.add(check)
newBody.add(n[1])
n[0] = newSymNode(getSysSym("true"))
n[1] = newBody
else:
for i in 0 ..< n.len:
n[i] = ctx.lowerStmtListExpr(n[i])
n[i] = ctx.lowerStmtListExprs(n[i], needsSplit)
proc newEndFinallyNode(ctx: var Ctx): PNode =
# Generate the following code:
@@ -448,7 +793,7 @@ proc newEndFinallyNode(ctx: var Ctx): PNode =
branch.add(cmp)
let retStmt = newNode(nkReturnStmt)
let asgn = newNode(nkAsgn)
let asgn = newNode(nkFastAsgn)
addSon(asgn, newSymNode(getClosureIterResult(ctx.fn)))
addSon(asgn, ctx.newTmpResultAccess())
retStmt.add(asgn)
@@ -482,7 +827,7 @@ proc transformReturnsInTry(ctx: var Ctx, n: PNode): PNode =
asgn.add(newIntTypeNode(nkIntLit, 1, getSysType(tyBool)))
result.add(asgn)
if n[0].kind != nkEmpty: # TODO: And not void!
if n[0].kind != nkEmpty:
let asgnTmpResult = newNodeI(nkAsgn, n.info)
asgnTmpResult.add(ctx.newTmpResultAccess())
asgnTmpResult.add(n[0])
@@ -508,17 +853,15 @@ proc transformClosureIteratorBody(ctx: var Ctx, n: PNode, gotoOut: PNode): PNode
nkSym, nkIdent, procDefs, nkTemplateDef:
discard
of nkStmtList:
of nkStmtList, nkStmtListExpr:
assert(isEmptyType(n.typ), "nkStmtListExpr not lowered")
result = addGotoOut(result, gotoOut)
for i in 0 ..< n.len:
if n[i].hasYieldsInExpressions:
# Lower nkStmtListExpr nodes inside `n[i]` first
assert(ctx.loweredStmtListExpr.isNil)
ctx.loweredStmtListExpr = newNodeI(nkStmtList, n.info)
n[i] = ctx.lowerStmtListExpr(n[i])
ctx.loweredStmtListExpr.add(n[i])
n[i] = ctx.loweredStmtListExpr
ctx.loweredStmtListExpr = nil
var ns = false
n[i] = ctx.lowerStmtListExprs(n[i], ns)
if n[i].hasYields:
# Create a new split
@@ -534,9 +877,6 @@ proc transformClosureIteratorBody(ctx: var Ctx, n: PNode, gotoOut: PNode): PNode
discard ctx.transformClosureIteratorBody(s, gotoOut)
break
of nkStmtListExpr:
assert(false, "nkStmtListExpr not lowered")
of nkYieldStmt:
result = newNodeI(nkStmtList, n.info)
result.add(n)

View File

@@ -5,197 +5,368 @@ output: "ok"
var closureIterResult = newSeq[int]()
proc checkpoint(arg: int) =
closureIterResult.add(arg)
closureIterResult.add(arg)
type
TestException = object of Exception
AnotherException = object of Exception
TestException = object of Exception
AnotherException = object of Exception
proc testClosureIterAux(it: iterator(): int, exceptionExpected: bool, expectedResults: varargs[int]) =
closureIterResult.setLen(0)
closureIterResult.setLen(0)
var exceptionCaught = false
var exceptionCaught = false
try:
for i in it():
closureIterResult.add(i)
except TestException:
exceptionCaught = true
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)
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)
testClosureIterAux(it, false, expectedResults)
proc testExc(it: iterator(): int, expectedResults: varargs[int]) =
testClosureIterAux(it, true, expectedResults)
testClosureIterAux(it, true, expectedResults)
proc raiseException() =
raise newException(TestException, "Test exception!")
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
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)
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)
iterator it(): int {.closure.} =
yield 0
try:
checkpoint(1)
raiseException()
except TestException:
checkpoint(2)
yield 3
checkpoint(4)
finally:
checkpoint(5)
checkpoint(6)
checkpoint(6)
test(it, 0, 1, 2, 3, 4, 5, 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
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)
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
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)
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)
iterator it(): int {.closure.} =
try:
try:
raiseException()
except AnotherException:
yield 123
finally:
checkpoint(3)
finally:
checkpoint(4)
testExc(it, 1, 2)
testExc(it, 3, 4)
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)
iterator it(): int {.closure.} =
try:
yield 1
raiseException()
except AnotherException:
checkpoint(123)
finally:
checkpoint(2)
checkpoint(3)
test(it, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9)
testExc(it, 1, 2)
block:
iterator it(): int {.closure.} =
iterator it(): int {.closure.} =
try:
yield 0
try:
yield 1
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
yield 2
raiseException()
except AnotherException:
yield 2
return
yield 123
finally:
yield 3
checkpoint(123)
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)
test(it, 0, 3)
echo "ok"