|
|
|
|
@@ -64,7 +64,8 @@
|
|
|
|
|
# the target state is `except` block. For all states in `except` block
|
|
|
|
|
# the target state is `finally` block. For all other states there is no
|
|
|
|
|
# target state (0, as the first state can never be except nor finally).
|
|
|
|
|
# - env var :curExcLevel is created, finallies use it to decide their exit logic
|
|
|
|
|
# - env var :curExc is created, where "current" exception within the iterator is stored,
|
|
|
|
|
# also finallies use it to decide their exit logic
|
|
|
|
|
# - if there are finallies, env var :finallyPath is created. It contains exit state labels
|
|
|
|
|
# for every finally level, and is changed in runtime in try, except, break, and return
|
|
|
|
|
# nodes to control finally exit behavior.
|
|
|
|
|
@@ -111,7 +112,6 @@
|
|
|
|
|
# :state = 2 # And we continue to our finally
|
|
|
|
|
# break :stateLoop
|
|
|
|
|
# of 1: # Except
|
|
|
|
|
# inc(:curExcLevel, -1) # Exception is caught
|
|
|
|
|
# yield 1
|
|
|
|
|
# :tmpResult = 3 # Return
|
|
|
|
|
# :finalyPath[LEVEL] = 0 # Configure finally path.
|
|
|
|
|
@@ -123,7 +123,7 @@
|
|
|
|
|
# of 2: # Finally
|
|
|
|
|
# yield 2
|
|
|
|
|
# if :finallyPath[LEVEL] == 0: # This node is created by `newEndFinallyNode`
|
|
|
|
|
# if :curExcLevel == 0:
|
|
|
|
|
# if :curExc == nil:
|
|
|
|
|
# :state = -1
|
|
|
|
|
# return result = :tmpResult
|
|
|
|
|
# else:
|
|
|
|
|
@@ -165,7 +165,8 @@ type
|
|
|
|
|
fn: PSym
|
|
|
|
|
tmpResultSym: PSym # Used when we return, but finally has to interfere
|
|
|
|
|
finallyPathSym: PSym
|
|
|
|
|
curExcLevelSym: PSym # Current exception level (because exceptions are stacked)
|
|
|
|
|
curExcSym: PSym # Current exception
|
|
|
|
|
externExcSym: PSym # Extern exception: what would getCurrentException() return outside of closure iter
|
|
|
|
|
|
|
|
|
|
states: seq[State] # The resulting states. Label is int literal.
|
|
|
|
|
finallyPathStack: seq[FinallyTarget] # Stack of split blocks, whiles and finallies
|
|
|
|
|
@@ -173,6 +174,7 @@ type
|
|
|
|
|
tempVarId: int # unique name counter
|
|
|
|
|
hasExceptions: bool # Does closure have yield in try?
|
|
|
|
|
curExcLandingState: PNode
|
|
|
|
|
curExceptLevel: int
|
|
|
|
|
curFinallyLevel: int
|
|
|
|
|
idgen: IdGenerator
|
|
|
|
|
varStates: Table[ItemId, int] # Used to detect if local variable belongs to multiple states
|
|
|
|
|
@@ -242,10 +244,11 @@ proc newFinallyPathAssign(ctx: var Ctx, level: int, label: PNode, info: TLineInf
|
|
|
|
|
let fp = newFinallyPathAccess(ctx, level, info)
|
|
|
|
|
result = newTree(nkAsgn, fp, label)
|
|
|
|
|
|
|
|
|
|
proc newCurExcLevelAccess(ctx: var Ctx): PNode =
|
|
|
|
|
if ctx.curExcLevelSym.isNil:
|
|
|
|
|
ctx.curExcLevelSym = ctx.newEnvVar(":curExcLevel", ctx.g.getSysType(ctx.fn.info, tyInt16))
|
|
|
|
|
ctx.newEnvVarAccess(ctx.curExcLevelSym)
|
|
|
|
|
proc newCurExcAccess(ctx: var Ctx): PNode =
|
|
|
|
|
if ctx.curExcSym.isNil:
|
|
|
|
|
let getCurExc = ctx.g.callCodegenProc("getCurrentException")
|
|
|
|
|
ctx.curExcSym = ctx.newEnvVar(":curExc", getCurExc.typ)
|
|
|
|
|
ctx.newEnvVarAccess(ctx.curExcSym)
|
|
|
|
|
|
|
|
|
|
proc newStateLabel(ctx: Ctx): PNode =
|
|
|
|
|
ctx.g.newIntLit(TLineInfo(), 0)
|
|
|
|
|
@@ -284,6 +287,15 @@ proc newTempVar(ctx: var Ctx, typ: PType, parent: PNode, initialValue: PNode = n
|
|
|
|
|
assert(not typ.isNil, "Temp var needs a type")
|
|
|
|
|
parent.add(ctx.newTempVarDef(result, initialValue))
|
|
|
|
|
|
|
|
|
|
proc newExternExcAccess(ctx: var Ctx): PNode =
|
|
|
|
|
if ctx.externExcSym == nil:
|
|
|
|
|
ctx.externExcSym = newSym(skVar, getIdent(ctx.g.cache, ":externExc"), ctx.idgen, ctx.fn, ctx.fn.info)
|
|
|
|
|
ctx.externExcSym.typ = ctx.curExcSym.typ
|
|
|
|
|
newSymNode(ctx.externExcSym, ctx.fn.info)
|
|
|
|
|
|
|
|
|
|
proc newRestoreExternException(ctx: var Ctx): PNode =
|
|
|
|
|
ctx.g.callCodegenProc("closureIterSetExc", ctx.fn.info, ctx.newExternExcAccess())
|
|
|
|
|
|
|
|
|
|
proc hasYields(n: PNode): bool =
|
|
|
|
|
# TODO: This is very inefficient. It traverses the node, looking for nkYieldStmt.
|
|
|
|
|
case n.kind
|
|
|
|
|
@@ -298,21 +310,13 @@ proc hasYields(n: PNode): bool =
|
|
|
|
|
result = true
|
|
|
|
|
break
|
|
|
|
|
|
|
|
|
|
proc newNullifyCurExcLevel(ctx: var Ctx, info: TLineInfo, decrement = false): PNode =
|
|
|
|
|
# :curEcx = 0
|
|
|
|
|
let curExc = ctx.newCurExcLevelAccess()
|
|
|
|
|
proc newNullifyCurExc(ctx: var Ctx, info: TLineInfo): PNode =
|
|
|
|
|
# :curEcx = nil
|
|
|
|
|
let curExc = ctx.newCurExcAccess()
|
|
|
|
|
curExc.info = info
|
|
|
|
|
let nilnode = ctx.g.newIntLit(info, 0)
|
|
|
|
|
let nilnode = newNodeIT(nkNilLit, info, getSysType(ctx.g, info, tyNil))
|
|
|
|
|
result = newTree(nkAsgn, curExc, nilnode)
|
|
|
|
|
|
|
|
|
|
proc newChangeCurExcLevel(ctx: var Ctx, info: TLineInfo, by: int): PNode =
|
|
|
|
|
# inc(:curEcxLevel, by)
|
|
|
|
|
let curExc = ctx.newCurExcLevelAccess()
|
|
|
|
|
curExc.info = info
|
|
|
|
|
result = newTreeIT(nkCall, info, ctx.g.getSysType(info, tyVoid),
|
|
|
|
|
newSymNode(ctx.g.getSysMagic(info, "inc", mInc)), curExc,
|
|
|
|
|
ctx.g.newIntLit(info, by))
|
|
|
|
|
|
|
|
|
|
proc newOr(g: ModuleGraph, a, b: PNode): PNode {.inline.} =
|
|
|
|
|
result = newTreeIT(nkCall, a.info, g.getSysType(a.info, tyBool),
|
|
|
|
|
newSymNode(g.getSysMagic(a.info, "or", mOr)), a, b)
|
|
|
|
|
@@ -344,7 +348,7 @@ proc collectExceptState(ctx: var Ctx, n: PNode): PNode {.inline.} =
|
|
|
|
|
else:
|
|
|
|
|
ifBranch = newNodeI(nkElse, c.info)
|
|
|
|
|
|
|
|
|
|
ifBranch.add(newTreeI(nkStmtList, c.info, ctx.newChangeCurExcLevel(c.info, -1), c[^1]))
|
|
|
|
|
ifBranch.add(c[^1])
|
|
|
|
|
ifStmt.add(ifBranch)
|
|
|
|
|
|
|
|
|
|
if ifStmt.len != 0:
|
|
|
|
|
@@ -352,9 +356,10 @@ proc collectExceptState(ctx: var Ctx, n: PNode): PNode {.inline.} =
|
|
|
|
|
else:
|
|
|
|
|
result = ctx.g.emptyNode
|
|
|
|
|
|
|
|
|
|
proc addElseToExcept(ctx: var Ctx, n, gotoOut: PNode) =
|
|
|
|
|
proc addElseToExcept(ctx: var Ctx, n, gotoOut: PNode): PNode =
|
|
|
|
|
# We should adjust finallyPath to gotoOut if exception is handled
|
|
|
|
|
# if there is no finally node next to this except, gotoOut must be nil
|
|
|
|
|
result = n
|
|
|
|
|
if n.kind == nkStmtList:
|
|
|
|
|
if n[0].kind == nkIfStmt and n[0][^1].kind != nkElse:
|
|
|
|
|
# Not all cases are covered, which means exception is not handled
|
|
|
|
|
@@ -377,6 +382,7 @@ proc addElseToExcept(ctx: var Ctx, n, gotoOut: PNode) =
|
|
|
|
|
# raised one.
|
|
|
|
|
n.add newTree(nkCall,
|
|
|
|
|
newSymNode(ctx.g.getCompilerProc("popCurrentException")))
|
|
|
|
|
n.add ctx.newNullifyCurExc(n.info)
|
|
|
|
|
if gotoOut != nil:
|
|
|
|
|
# We have a finally node following this except block, and exception is handled
|
|
|
|
|
# Configure its path to continue normally
|
|
|
|
|
@@ -823,7 +829,7 @@ proc lowerStmtListExprs(ctx: var Ctx, n: PNode, needsSplit: var bool): PNode =
|
|
|
|
|
proc newEndFinallyNode(ctx: var Ctx, info: TLineInfo): PNode =
|
|
|
|
|
# Generate the following code:
|
|
|
|
|
# if :finallyPath[FINALLY_LEVEL] == 0:
|
|
|
|
|
# if :curExcLevel == 0:
|
|
|
|
|
# if :curExc == nil:
|
|
|
|
|
# :state = -1
|
|
|
|
|
# return result = :tmpResult
|
|
|
|
|
# else:
|
|
|
|
|
@@ -837,9 +843,9 @@ proc newEndFinallyNode(ctx: var Ctx, info: TLineInfo): PNode =
|
|
|
|
|
|
|
|
|
|
let excNilCmp = newTreeIT(nkCall,
|
|
|
|
|
info, ctx.g.getSysType(info, tyBool),
|
|
|
|
|
newSymNode(ctx.g.getSysMagic(info, "==", mEqI), info),
|
|
|
|
|
ctx.newCurExcLevelAccess(),
|
|
|
|
|
ctx.g.newIntLit(info, 0))
|
|
|
|
|
newSymNode(ctx.g.getSysMagic(info, "==", mEqRef), info),
|
|
|
|
|
ctx.newCurExcAccess(),
|
|
|
|
|
newNodeIT(nkNilLit, info, getSysType(ctx.g, info, tyNil)))
|
|
|
|
|
|
|
|
|
|
let retStmt =
|
|
|
|
|
block:
|
|
|
|
|
@@ -918,7 +924,9 @@ proc transformReturnStmt(ctx: var Ctx, n: PNode): PNode =
|
|
|
|
|
result = newNodeI(nkStmtList, n.info)
|
|
|
|
|
|
|
|
|
|
# Returns prevent exception propagation
|
|
|
|
|
result.add(ctx.newNullifyCurExcLevel(n.info))
|
|
|
|
|
result.add(ctx.newNullifyCurExc(n.info))
|
|
|
|
|
|
|
|
|
|
result.add(ctx.newRestoreExternException())
|
|
|
|
|
|
|
|
|
|
var finallyChain = newSeq[PNode]()
|
|
|
|
|
|
|
|
|
|
@@ -986,6 +994,8 @@ proc transformClosureIteratorBody(ctx: var Ctx, n: PNode, gotoOut: PNode): PNode
|
|
|
|
|
|
|
|
|
|
of nkYieldStmt:
|
|
|
|
|
result = addGotoOut(result, gotoOut)
|
|
|
|
|
if ctx.curExceptLevel > 0 or ctx.curFinallyLevel > 0:
|
|
|
|
|
result = newTree(nkStmtList, ctx.newRestoreExternException(), result)
|
|
|
|
|
|
|
|
|
|
of nkElse, nkElseExpr:
|
|
|
|
|
result[0] = addGotoOut(result[0], gotoOut)
|
|
|
|
|
@@ -1055,7 +1065,7 @@ proc transformClosureIteratorBody(ctx: var Ctx, n: PNode, gotoOut: PNode): PNode
|
|
|
|
|
result.add(tryLabel)
|
|
|
|
|
var tryBody = toStmtList(n[0])
|
|
|
|
|
|
|
|
|
|
let exceptBody = ctx.collectExceptState(n)
|
|
|
|
|
var exceptBody = ctx.collectExceptState(n)
|
|
|
|
|
var finallyBody = ctx.getFinallyNode(n)
|
|
|
|
|
var exceptLabel, finallyLabel = ctx.g.emptyNode
|
|
|
|
|
|
|
|
|
|
@@ -1094,19 +1104,19 @@ proc transformClosureIteratorBody(ctx: var Ctx, n: PNode, gotoOut: PNode): PNode
|
|
|
|
|
inc ctx.curFinallyLevel
|
|
|
|
|
ctx.finallyPathStack.add(FinallyTarget(n: n[^1], label: finallyLabel))
|
|
|
|
|
|
|
|
|
|
if ctx.transformClosureIteratorBody(tryBody, tryOut) != tryBody:
|
|
|
|
|
internalError(ctx.g.config, "transformClosureIteratorBody != tryBody")
|
|
|
|
|
tryBody = ctx.transformClosureIteratorBody(tryBody, tryOut)
|
|
|
|
|
|
|
|
|
|
if exceptBody.kind != nkEmpty:
|
|
|
|
|
inc ctx.curExceptLevel
|
|
|
|
|
ctx.curExcLandingState = if finallyBody.kind != nkEmpty: finallyLabel
|
|
|
|
|
else: oldExcLandingState
|
|
|
|
|
discard ctx.newState(exceptBody, false, exceptLabel)
|
|
|
|
|
|
|
|
|
|
let normalOut = if finallyBody.kind != nkEmpty: gotoOut else: nil
|
|
|
|
|
ctx.addElseToExcept(exceptBody, normalOut)
|
|
|
|
|
exceptBody = ctx.addElseToExcept(exceptBody, normalOut)
|
|
|
|
|
# echo "EXCEPT: ", renderTree(exceptBody)
|
|
|
|
|
if ctx.transformClosureIteratorBody(exceptBody, tryOut) != exceptBody:
|
|
|
|
|
internalError(ctx.g.config, "transformClosureIteratorBody != exceptBody")
|
|
|
|
|
exceptBody = ctx.transformClosureIteratorBody(exceptBody, tryOut)
|
|
|
|
|
inc ctx.curExceptLevel
|
|
|
|
|
|
|
|
|
|
ctx.curExcLandingState = oldExcLandingState
|
|
|
|
|
|
|
|
|
|
@@ -1114,8 +1124,7 @@ proc transformClosureIteratorBody(ctx: var Ctx, n: PNode, gotoOut: PNode): PNode
|
|
|
|
|
discard ctx.finallyPathStack.pop()
|
|
|
|
|
discard ctx.newState(finallyBody, false, finallyLabel)
|
|
|
|
|
let finallyExit = newTree(nkGotoState, ctx.newFinallyPathAccess(ctx.curFinallyLevel - 1, finallyBody.info))
|
|
|
|
|
if ctx.transformClosureIteratorBody(finallyBody, finallyExit) != finallyBody:
|
|
|
|
|
internalError(ctx.g.config, "transformClosureIteratorBody != finallyBody")
|
|
|
|
|
finallyBody = ctx.transformClosureIteratorBody(finallyBody, finallyExit)
|
|
|
|
|
dec ctx.curFinallyLevel
|
|
|
|
|
|
|
|
|
|
of nkGotoState, nkForStmt:
|
|
|
|
|
@@ -1201,34 +1210,6 @@ proc createExceptionTable(ctx: var Ctx): PNode {.inline.} =
|
|
|
|
|
for i in 0 .. ctx.states.high:
|
|
|
|
|
result.add(ctx.states[i].excLandingState)
|
|
|
|
|
|
|
|
|
|
proc newExceptBody(ctx: var Ctx, info: TLineInfo): PNode {.inline.} =
|
|
|
|
|
# Generates code:
|
|
|
|
|
# :state = exceptionTable[:state]
|
|
|
|
|
# if :state == 0:
|
|
|
|
|
# raise
|
|
|
|
|
result = newNodeI(nkStmtList, info)
|
|
|
|
|
|
|
|
|
|
let intTyp = ctx.g.getSysType(info, tyInt)
|
|
|
|
|
let boolTyp = ctx.g.getSysType(info, tyBool)
|
|
|
|
|
|
|
|
|
|
# :state = exceptionTable[:state]
|
|
|
|
|
result.add ctx.newStateAssgn(
|
|
|
|
|
newTreeIT(nkBracketExpr, info, intTyp,
|
|
|
|
|
ctx.createExceptionTable(),
|
|
|
|
|
ctx.newStateAccess()))
|
|
|
|
|
|
|
|
|
|
# if :state == 0: raise
|
|
|
|
|
block:
|
|
|
|
|
let cond = newTreeIT(nkCall, info, boolTyp,
|
|
|
|
|
ctx.g.getSysMagic(info, "==", mEqI).newSymNode(),
|
|
|
|
|
ctx.newStateAccess(),
|
|
|
|
|
newIntTypeNode(0, intTyp))
|
|
|
|
|
|
|
|
|
|
let raiseStmt = newTree(nkRaiseStmt, ctx.g.emptyNode)
|
|
|
|
|
let ifBranch = newTree(nkElifBranch, cond, raiseStmt)
|
|
|
|
|
let ifStmt = newTree(nkIfStmt, ifBranch)
|
|
|
|
|
result.add(ifStmt)
|
|
|
|
|
|
|
|
|
|
proc wrapIntoTryExcept(ctx: var Ctx, n: PNode): PNode {.inline.} =
|
|
|
|
|
# Generates code:
|
|
|
|
|
# var :tmp = nil
|
|
|
|
|
@@ -1236,24 +1217,45 @@ proc wrapIntoTryExcept(ctx: var Ctx, n: PNode): PNode {.inline.} =
|
|
|
|
|
# body
|
|
|
|
|
# except:
|
|
|
|
|
# :state = exceptionTable[:state]
|
|
|
|
|
# if :state == 0:
|
|
|
|
|
# raise
|
|
|
|
|
# :tmp = getCurrentException()
|
|
|
|
|
# :curExc = getCurrentException()
|
|
|
|
|
# if :state == 0:
|
|
|
|
|
# closureIterSetExc(:externExc)
|
|
|
|
|
# raise
|
|
|
|
|
#
|
|
|
|
|
# pushCurrentException(:tmp)
|
|
|
|
|
# pushCurrentException(:curExc)
|
|
|
|
|
|
|
|
|
|
let tryBody = newTree(nkStmtList, n)
|
|
|
|
|
let exceptBody = ctx.newExceptBody(ctx.fn.info)
|
|
|
|
|
let exceptBranch = newTree(nkExceptBranch, exceptBody)
|
|
|
|
|
let info = ctx.fn.info
|
|
|
|
|
let getCurExc = ctx.g.callCodegenProc("getCurrentException")
|
|
|
|
|
let exceptBody = newTreeI(nkStmtList, info,
|
|
|
|
|
ctx.newStateAssgn(
|
|
|
|
|
newTreeIT(nkBracketExpr, info, ctx.g.getSysType(info, tyInt),
|
|
|
|
|
ctx.createExceptionTable(),
|
|
|
|
|
ctx.newStateAccess())),
|
|
|
|
|
newTreeI(nkFastAsgn, info, ctx.newCurExcAccess(), getCurExc))
|
|
|
|
|
|
|
|
|
|
result = newTree(nkStmtList)
|
|
|
|
|
let getCurExc = ctx.g.callCodegenProc("getCurrentException")
|
|
|
|
|
let tempExc = ctx.newTempVar(getCurExc.typ, result)
|
|
|
|
|
result.add newTree(nkTryStmt, tryBody, exceptBranch)
|
|
|
|
|
exceptBody.add ctx.newTempVarAsgn(tempExc, getCurExc)
|
|
|
|
|
result.add newTree(nkTryStmt,
|
|
|
|
|
newTree(nkStmtList, n),
|
|
|
|
|
newTree(nkExceptBranch, exceptBody))
|
|
|
|
|
|
|
|
|
|
result.add newTree(nkCall, newSymNode(ctx.g.getCompilerProc("pushCurrentException")), ctx.newTempVarAccess(tempExc))
|
|
|
|
|
result.add ctx.newChangeCurExcLevel(n.info, 1)
|
|
|
|
|
# if :state == 0:
|
|
|
|
|
# closureIterSetExc(:externExc)
|
|
|
|
|
# raise
|
|
|
|
|
block:
|
|
|
|
|
let boolTyp = ctx.g.getSysType(info, tyBool)
|
|
|
|
|
let intTyp = ctx.g.getSysType(info, tyInt)
|
|
|
|
|
let cond = newTreeIT(nkCall, info, boolTyp,
|
|
|
|
|
ctx.g.getSysMagic(info, "==", mEqI).newSymNode(),
|
|
|
|
|
ctx.newStateAccess(),
|
|
|
|
|
newIntTypeNode(0, intTyp))
|
|
|
|
|
|
|
|
|
|
let raiseStmt = newTree(nkRaiseStmt, ctx.newCurExcAccess())
|
|
|
|
|
let ifBody = newTree(nkStmtList, ctx.newRestoreExternException(), raiseStmt)
|
|
|
|
|
let ifBranch = newTree(nkElifBranch, cond, ifBody)
|
|
|
|
|
let ifStmt = newTree(nkIfStmt, ifBranch)
|
|
|
|
|
result.add(ifStmt)
|
|
|
|
|
|
|
|
|
|
result.add newTree(nkCall, newSymNode(ctx.g.getCompilerProc("pushCurrentException")), ctx.newCurExcAccess())
|
|
|
|
|
|
|
|
|
|
proc wrapIntoStateLoop(ctx: var Ctx, n: PNode): PNode =
|
|
|
|
|
# while true:
|
|
|
|
|
@@ -1276,6 +1278,19 @@ proc wrapIntoStateLoop(ctx: var Ctx, n: PNode): PNode =
|
|
|
|
|
blockStmt.add(blockBody)
|
|
|
|
|
loopBody.add(blockStmt)
|
|
|
|
|
|
|
|
|
|
if ctx.hasExceptions:
|
|
|
|
|
# Since we have yields in tries, we must switch current exception
|
|
|
|
|
# between the iter and "outer world"
|
|
|
|
|
# var :externExc = getCurrentException()
|
|
|
|
|
# closureIterSetExc(:curExc)
|
|
|
|
|
let getCurExc = ctx.g.callCodegenProc("getCurrentException")
|
|
|
|
|
discard ctx.newExternExcAccess()
|
|
|
|
|
let setCurExc = ctx.g.callCodegenProc("closureIterSetExc", n.info, ctx.newCurExcAccess())
|
|
|
|
|
result = newTreeI(nkStmtList, n.info,
|
|
|
|
|
ctx.newTempVarDef(ctx.externExcSym, getCurExc),
|
|
|
|
|
setCurExc,
|
|
|
|
|
result)
|
|
|
|
|
|
|
|
|
|
proc countStateOccurences(ctx: var Ctx, n: PNode, stateOccurences: var openArray[int]) =
|
|
|
|
|
## Find all nkGotoState(stateIdx) nodes that do not follow nkYield.
|
|
|
|
|
## For every such node increment stateOccurences[stateIdx]
|
|
|
|
|
@@ -1381,7 +1396,7 @@ proc detectCapturedVars(c: var Ctx, n: PNode, stateIdx: int) =
|
|
|
|
|
case n.kind
|
|
|
|
|
of nkSym:
|
|
|
|
|
let s = n.sym
|
|
|
|
|
if s.kind in {skResult, skVar, skLet, skForVar, skTemp} and sfGlobal notin s.flags and s.owner == c.fn:
|
|
|
|
|
if s.kind in {skResult, skVar, skLet, skForVar, skTemp} and sfGlobal notin s.flags and s.owner == c.fn and s != c.externExcSym:
|
|
|
|
|
let vs = c.varStates.getOrDefault(s.itemId, localNotSeen)
|
|
|
|
|
if vs == localNotSeen: # First seing this variable
|
|
|
|
|
c.varStates[s.itemId] = stateIdx
|
|
|
|
|
@@ -1458,7 +1473,9 @@ proc transformClosureIterator*(g: ModuleGraph; idgen: IdGenerator; fn: PSym, n:
|
|
|
|
|
# echo "transformed into ", n
|
|
|
|
|
|
|
|
|
|
discard ctx.newState(n, false, nil)
|
|
|
|
|
let gotoOut = newTree(nkGotoState, g.newIntLit(n.info, -1))
|
|
|
|
|
|
|
|
|
|
let finalState = ctx.newStateLabel()
|
|
|
|
|
let gotoOut = newTree(nkGotoState, finalState)
|
|
|
|
|
|
|
|
|
|
var ns = false
|
|
|
|
|
n = ctx.lowerStmtListExprs(n, ns)
|
|
|
|
|
@@ -1470,6 +1487,12 @@ proc transformClosureIterator*(g: ModuleGraph; idgen: IdGenerator; fn: PSym, n:
|
|
|
|
|
# Splitting transformation
|
|
|
|
|
discard ctx.transformClosureIteratorBody(n, gotoOut)
|
|
|
|
|
|
|
|
|
|
let finalStateBody = newTree(nkStmtList)
|
|
|
|
|
if ctx.hasExceptions:
|
|
|
|
|
finalStateBody.add(ctx.newRestoreExternException())
|
|
|
|
|
finalStateBody.add(newTree(nkGotoState, g.newIntLit(n.info, -1)))
|
|
|
|
|
discard ctx.newState(finalStateBody, true, finalState)
|
|
|
|
|
|
|
|
|
|
# Assign state label indexes
|
|
|
|
|
for i in 0 .. ctx.states.high:
|
|
|
|
|
ctx.states[i].label.intVal = i
|
|
|
|
|
|