@@ -166,13 +166,16 @@ type
166166    tmpResultSym: PSym  #  Used when we return, but finally has to interfere
167167    finallyPathSym: PSym 
168168    curExcLevelSym: PSym  #  Current exception level (because exceptions are stacked)
169+     curExcSym: PSym  #  Current exception
170+     externExcSym: PSym  #  Extern exception: what would getCurrentException() return outside of closure iter
169171
170172    states: seq [State ] #  The resulting states. Label is int literal.
171173    finallyPathStack: seq [FinallyTarget ] #  Stack of split blocks, whiles and finallies
172174    stateLoopLabel: PSym  #  Label to break on, when jumping between states.
173175    tempVarId: int  #  unique name counter
174176    hasExceptions: bool  #  Does closure have yield in try?
175177    curExcLandingState: PNode 
178+     curExceptLevel: int 
176179    curFinallyLevel: int 
177180    idgen: IdGenerator 
178181    varStates: Table [ItemId , int ] #  Used to detect if local variable belongs to multiple states
@@ -242,6 +245,12 @@ proc newFinallyPathAssign(ctx: var Ctx, level: int, label: PNode, info: TLineInf
242245  let  fp =  newFinallyPathAccess (ctx, level, info)
243246  result  =  newTree (nkAsgn, fp, label)
244247
248+ proc  newCurExcAccess (ctx: var  Ctx ): PNode  = 
249+   if  ctx.curExcSym.isNil:
250+     let  getCurExc =  ctx.g.callCodegenProc (" getCurrentException"  )
251+     ctx.curExcSym =  ctx.newEnvVar (" :curExc"  , getCurExc.typ)
252+   ctx.newEnvVarAccess (ctx.curExcSym)
253+ 
245254proc  newCurExcLevelAccess (ctx: var  Ctx ): PNode  = 
246255  if  ctx.curExcLevelSym.isNil:
247256    ctx.curExcLevelSym =  ctx.newEnvVar (" :curExcLevel"  , ctx.g.getSysType (ctx.fn.info, tyInt16))
@@ -284,6 +293,15 @@ proc newTempVar(ctx: var Ctx, typ: PType, parent: PNode, initialValue: PNode = n
284293  assert (not  typ.isNil, " Temp var needs a type"  )
285294  parent.add (ctx.newTempVarDef (result , initialValue))
286295
296+ proc  newExternExcAccess (ctx: var  Ctx ): PNode  = 
297+   if  ctx.externExcSym ==  nil :
298+     ctx.externExcSym =  newSym (skVar, getIdent (ctx.g.cache, " :externExc"  ), ctx.idgen, ctx.fn, ctx.fn.info)
299+     ctx.externExcSym.typ =  ctx.curExcSym.typ
300+   newSymNode (ctx.externExcSym, ctx.fn.info)
301+ 
302+ proc  newRestoreExternException (ctx: var  Ctx ): PNode  = 
303+   ctx.g.callCodegenProc (" closureIterSetExc"  , ctx.fn.info, ctx.newExternExcAccess ())
304+ 
287305proc  hasYields (n: PNode ): bool  = 
288306  #  TODO : This is very inefficient. It traverses the node, looking for nkYieldStmt.
289307  case  n.kind
@@ -298,8 +316,15 @@ proc hasYields(n: PNode): bool =
298316        result  =  true 
299317        break 
300318
301- proc  newNullifyCurExcLevel (ctx: var  Ctx , info: TLineInfo , decrement =  false ): PNode  = 
302-   #  :curEcx = 0
319+ proc  newNullifyCurExc (ctx: var  Ctx , info: TLineInfo ): PNode  = 
320+   #  :curEcx = nil
321+   let  curExc =  ctx.newCurExcAccess ()
322+   curExc.info =  info
323+   let  nilnode =  newNodeIT (nkNilLit, info, getSysType (ctx.g, info, tyNil))
324+   result  =  newTree (nkAsgn, curExc, nilnode)
325+ 
326+ proc  newNullifyCurExcLevel (ctx: var  Ctx , info: TLineInfo ): PNode  = 
327+   #  :curEcxLevel = 0
303328  let  curExc =  ctx.newCurExcLevelAccess ()
304329  curExc.info =  info
305330  let  nilnode =  ctx.g.newIntLit (info, 0 )
@@ -344,17 +369,20 @@ proc collectExceptState(ctx: var Ctx, n: PNode): PNode {.inline.} =
344369        else :
345370          ifBranch =  newNodeI (nkElse, c.info)
346371
347-       ifBranch.add (newTreeI (nkStmtList, c.info, ctx.newChangeCurExcLevel (c.info, - 1 ), c[^ 1 ]))
372+       ifBranch.add (c[^ 1 ])
373+       #  ifBranch.add(newTreeI(nkStmtList, c.info, ctx.newChangeCurExcLevel(c.info, -1), c[^1]))
348374      ifStmt.add (ifBranch)
349375
350376  if  ifStmt.len !=  0 :
351377    result  =  newTree (nkStmtList, ifStmt)
378+     #  result = newTree(nkStmtList, ctx.newChangeCurExcLevel(n.info, -1), ifStmt)
352379  else :
353380    result  =  ctx.g.emptyNode
354381
355- proc  addElseToExcept (ctx: var  Ctx , n, gotoOut: PNode ) = 
382+ proc  addElseToExcept (ctx: var  Ctx , n, gotoOut: PNode ):  PNode  = 
356383  #  We should adjust finallyPath to gotoOut if exception is handled
357384  #  if there is no finally node next to this except, gotoOut must be nil
385+   result  =  n
358386  if  n.kind ==  nkStmtList:
359387    if  n[0 ].kind ==  nkIfStmt and  n[0 ][^ 1 ].kind !=  nkElse:
360388      #  Not all cases are covered, which means exception is not handled
@@ -377,10 +405,12 @@ proc addElseToExcept(ctx: var Ctx, n, gotoOut: PNode) =
377405    #  raised one.
378406    n.add  newTree (nkCall,
379407      newSymNode (ctx.g.getCompilerProc (" popCurrentException"  )))
408+     n.add  ctx.newNullifyCurExc (n.info)
380409    if  gotoOut !=  nil :
381410      #  We have a finally node following this except block, and exception is handled
382411      #  Configure its path to continue normally
383412      n.add (ctx.newFinallyPathAssign (ctx.curFinallyLevel -  1 , gotoOut[0 ], n.info))
413+     
384414
385415proc  getFinallyNode (ctx: var  Ctx , n: PNode ): PNode  = 
386416  result  =  n[^ 1 ]
@@ -837,9 +867,9 @@ proc newEndFinallyNode(ctx: var Ctx, info: TLineInfo): PNode =
837867
838868  let  excNilCmp =  newTreeIT (nkCall,
839869                      info, ctx.g.getSysType (info, tyBool),
840-                       newSymNode (ctx.g.getSysMagic (info, " =="  , mEqI ), info),
841-                       ctx.newCurExcLevelAccess (),
842-                       ctx.g. newIntLit ( info, 0 ))
870+                       newSymNode (ctx.g.getSysMagic (info, " =="  , mEqRef ), info),
871+                       ctx.newCurExcAccess (),
872+                       newNodeIT (nkNilLit, info,  getSysType ( ctx.g,  info, tyNil) ))
843873
844874  let  retStmt = 
845875    block :
@@ -919,6 +949,7 @@ proc transformReturnStmt(ctx: var Ctx, n: PNode): PNode =
919949
920950  #  Returns prevent exception propagation
921951  result .add (ctx.newNullifyCurExcLevel (n.info))
952+   result .add (ctx.newNullifyCurExc (n.info))
922953
923954  var  finallyChain =  newSeq [PNode ]()
924955
@@ -986,6 +1017,8 @@ proc transformClosureIteratorBody(ctx: var Ctx, n: PNode, gotoOut: PNode): PNode
9861017
9871018  of  nkYieldStmt:
9881019    result  =  addGotoOut (result , gotoOut)
1020+     if  ctx.curExceptLevel >  0  or  ctx.curFinallyLevel >  0 :
1021+       result  =  newTree (nkStmtList, ctx.newRestoreExternException (), result )
9891022
9901023  of  nkElse, nkElseExpr:
9911024    result [0 ] =  addGotoOut (result [0 ], gotoOut)
@@ -1055,7 +1088,7 @@ proc transformClosureIteratorBody(ctx: var Ctx, n: PNode, gotoOut: PNode): PNode
10551088    result .add (tryLabel)
10561089    var  tryBody =  toStmtList (n[0 ])
10571090
1058-     let  exceptBody =  ctx.collectExceptState (n)
1091+     var  exceptBody =  ctx.collectExceptState (n)
10591092    var  finallyBody =  ctx.getFinallyNode (n)
10601093    var  exceptLabel, finallyLabel =  ctx.g.emptyNode
10611094
@@ -1094,28 +1127,27 @@ proc transformClosureIteratorBody(ctx: var Ctx, n: PNode, gotoOut: PNode): PNode
10941127        inc  ctx.curFinallyLevel
10951128        ctx.finallyPathStack.add (FinallyTarget  (n: n[^ 1 ], label: finallyLabel))
10961129
1097-       if  ctx.transformClosureIteratorBody (tryBody, tryOut) !=  tryBody:
1098-         internalError (ctx.g.config, " transformClosureIteratorBody != tryBody"  )
1130+       tryBody =  ctx.transformClosureIteratorBody (tryBody, tryOut)
10991131
11001132      if  exceptBody.kind !=  nkEmpty:
1133+         inc  ctx.curExceptLevel
11011134        ctx.curExcLandingState =  if  finallyBody.kind !=  nkEmpty: finallyLabel
11021135                                 else : oldExcLandingState
11031136        discard  ctx.newState (exceptBody, false , exceptLabel)
11041137
11051138        let  normalOut =  if  finallyBody.kind !=  nkEmpty: gotoOut else : nil 
1106-         ctx.addElseToExcept (exceptBody, normalOut)
1139+         exceptBody  =   ctx.addElseToExcept (exceptBody, normalOut)
11071140        #  echo "EXCEPT: ", renderTree(exceptBody)
1108-         if   ctx.transformClosureIteratorBody (exceptBody, tryOut)  !=  exceptBody: 
1109-            internalError ( ctx.g.config,  " transformClosureIteratorBody != exceptBody " ) 
1141+         exceptBody  =   ctx.transformClosureIteratorBody (exceptBody, tryOut)
1142+         inc   ctx.curExceptLevel 
11101143
11111144      ctx.curExcLandingState =  oldExcLandingState
11121145
11131146      if  finallyBody.kind !=  nkEmpty:
11141147        discard  ctx.finallyPathStack.pop ()
11151148        discard  ctx.newState (finallyBody, false , finallyLabel)
11161149        let  finallyExit =  newTree (nkGotoState, ctx.newFinallyPathAccess (ctx.curFinallyLevel -  1 , finallyBody.info))
1117-         if  ctx.transformClosureIteratorBody (finallyBody, finallyExit) !=  finallyBody:
1118-           internalError (ctx.g.config, " transformClosureIteratorBody != finallyBody"  )
1150+         finallyBody =  ctx.transformClosureIteratorBody (finallyBody, finallyExit)
11191151        dec  ctx.curFinallyLevel
11201152
11211153  of  nkGotoState, nkForStmt:
@@ -1209,25 +1241,16 @@ proc newExceptBody(ctx: var Ctx, info: TLineInfo): PNode {.inline.} =
12091241  result  =  newNodeI (nkStmtList, info)
12101242
12111243  let  intTyp =  ctx.g.getSysType (info, tyInt)
1212-   let  boolTyp =  ctx.g.getSysType (info, tyBool)
12131244
12141245  #  :state = exceptionTable[:state]
12151246  result .add  ctx.newStateAssgn (
12161247    newTreeIT (nkBracketExpr, info, intTyp,
12171248              ctx.createExceptionTable (),
12181249              ctx.newStateAccess ()))
12191250
1220-   #  if :state == 0: raise
1221-   block :
1222-     let  cond =  newTreeIT (nkCall, info, boolTyp,
1223-       ctx.g.getSysMagic (info, " =="  , mEqI).newSymNode (),
1224-       ctx.newStateAccess (),
1225-       newIntTypeNode (0 , intTyp))
1251+   let  getCurExc =  ctx.g.callCodegenProc (" getCurrentException"  )
1252+   result .add  newTree (nkFastAsgn, ctx.newCurExcAccess (), getCurExc)
12261253
1227-     let  raiseStmt =  newTree (nkRaiseStmt, ctx.g.emptyNode)
1228-     let  ifBranch =  newTree (nkElifBranch, cond, raiseStmt)
1229-     let  ifStmt =  newTree (nkIfStmt, ifBranch)
1230-     result .add (ifStmt)
12311254
12321255proc  wrapIntoTryExcept (ctx: var  Ctx , n: PNode ): PNode  {.inline .} = 
12331256  #  Generates code:
@@ -1236,11 +1259,12 @@ proc wrapIntoTryExcept(ctx: var Ctx, n: PNode): PNode {.inline.} =
12361259  #    body
12371260  #  except:
12381261  #    :state = exceptionTable[:state]
1239-   #    if :state == 0: 
1240-   #      raise 
1241-   #    :tmp = getCurrentException() 
1262+   #    :curExc = getCurrentException() 
1263+   #  if :state == 0: 
1264+   #    raise 
12421265  # 
1243-   #  pushCurrentException(:tmp)
1266+   #  pushCurrentException(:curExc)
1267+   #  inc :curExcLevel
12441268
12451269  let  tryBody =  newTree (nkStmtList, n)
12461270  let  exceptBody =  ctx.newExceptBody (ctx.fn.info)
@@ -1251,8 +1275,25 @@ proc wrapIntoTryExcept(ctx: var Ctx, n: PNode): PNode {.inline.} =
12511275  let  tempExc =  ctx.newTempVar (getCurExc.typ, result )
12521276  result .add  newTree (nkTryStmt, tryBody, exceptBranch)
12531277  exceptBody.add  ctx.newTempVarAsgn (tempExc, getCurExc)
1278+   #  exceptBody.add newTree(nkFastAsgn, ctx.newCurExcAccess(), getCurExc)
1279+ 
1280+   #  if :state == 0: raise
1281+   block :
1282+     let  boolTyp =  ctx.g.getSysType (ctx.fn.info, tyBool)
1283+     let  intTyp =  ctx.g.getSysType (ctx.fn.info, tyInt)
1284+     let  cond =  newTreeIT (nkCall, ctx.fn.info, boolTyp,
1285+       ctx.g.getSysMagic (ctx.fn.info, " =="  , mEqI).newSymNode (),
1286+       ctx.newStateAccess (),
1287+       newIntTypeNode (0 , intTyp))
1288+ 
1289+     let  raiseStmt =  newTree (nkRaiseStmt, ctx.newCurExcAccess ())
1290+     let  ifBody =  newTree (nkStmtList, ctx.newRestoreExternException (), raiseStmt)
1291+     let  ifBranch =  newTree (nkElifBranch, cond, ifBody)
1292+     let  ifStmt =  newTree (nkIfStmt, ifBranch)
1293+     result .add (ifStmt)
12541294
1255-   result .add  newTree (nkCall, newSymNode (ctx.g.getCompilerProc (" pushCurrentException"  )), ctx.newTempVarAccess (tempExc))
1295+   #  result.add newTree(nkCall, newSymNode(ctx.g.getCompilerProc("pushCurrentException")), ctx.newTempVarAccess(tempExc))
1296+   result .add  newTree (nkCall, newSymNode (ctx.g.getCompilerProc (" pushCurrentException"  )), ctx.newCurExcAccess ())
12561297  result .add  ctx.newChangeCurExcLevel (n.info, 1 )
12571298
12581299proc  wrapIntoStateLoop (ctx: var  Ctx , n: PNode ): PNode  = 
@@ -1276,6 +1317,17 @@ proc wrapIntoStateLoop(ctx: var Ctx, n: PNode): PNode =
12761317  blockStmt.add (blockBody)
12771318  loopBody.add (blockStmt)
12781319
1320+   if  ctx.hasExceptions:
1321+     let  res =  newNodeI (nkStmtList, n.info)
1322+     let  getCurExc =  ctx.g.callCodegenProc (" getCurrentException"  )
1323+     discard  ctx.newExternExcAccess ()
1324+     res.add (ctx.newTempVarDef (ctx.externExcSym, getCurExc))
1325+     #  let externExc = ctx.newTempVar(getCurExc.typ, res, getCurExc)
1326+     let  setCurExc =  ctx.g.callCodegenProc (" closureIterSetExc"  , n.info, ctx.newCurExcAccess ())
1327+     res.add (setCurExc)
1328+     res.add (result )
1329+     result  =  res
1330+ 
12791331proc  countStateOccurences (ctx: var  Ctx , n: PNode , stateOccurences: var  openArray [int ]) = 
12801332  # # Find all nkGotoState(stateIdx) nodes that do not follow nkYield.
12811333  # # For every such node increment stateOccurences[stateIdx]
@@ -1381,7 +1433,7 @@ proc detectCapturedVars(c: var Ctx, n: PNode, stateIdx: int) =
13811433  case  n.kind
13821434  of  nkSym:
13831435    let  s =  n.sym
1384-     if  s.kind in  {skResult, skVar, skLet, skForVar, skTemp} and  sfGlobal notin  s.flags and  s.owner ==  c.fn:
1436+     if  s.kind in  {skResult, skVar, skLet, skForVar, skTemp} and  sfGlobal notin  s.flags and  s.owner ==  c.fn  and  s  !=  c.externExcSym :
13851437      let  vs =  c.varStates.getOrDefault (s.itemId, localNotSeen)
13861438      if  vs ==  localNotSeen: #  First seing this variable
13871439        c.varStates[s.itemId] =  stateIdx
@@ -1458,7 +1510,9 @@ proc transformClosureIterator*(g: ModuleGraph; idgen: IdGenerator; fn: PSym, n:
14581510  #  echo "transformed into ", n
14591511
14601512  discard  ctx.newState (n, false , nil )
1461-   let  gotoOut =  newTree (nkGotoState, g.newIntLit (n.info, - 1 ))
1513+ 
1514+   let  finalState =  ctx.newStateLabel ()
1515+   let  gotoOut =  newTree (nkGotoState, finalState)
14621516
14631517  var  ns =  false 
14641518  n =  ctx.lowerStmtListExprs (n, ns)
@@ -1470,6 +1524,12 @@ proc transformClosureIterator*(g: ModuleGraph; idgen: IdGenerator; fn: PSym, n:
14701524  #  Splitting transformation
14711525  discard  ctx.transformClosureIteratorBody (n, gotoOut)
14721526
1527+   let  finalStateBody =  newTree (nkStmtList)
1528+   if  ctx.hasExceptions:
1529+     finalStateBody.add (ctx.newRestoreExternException ())
1530+   finalStateBody.add (newTree (nkGotoState, g.newIntLit (n.info, - 1 )))
1531+   discard  ctx.newState (finalStateBody, true , finalState)
1532+ 
14731533  #  Assign state label indexes
14741534  for  i in  0  ..  ctx.states.high:
14751535    ctx.states[i].label.intVal =  i
0 commit comments