diff --git a/src/hexer/cps.nim b/src/hexer/cps.nim index d457671b7..9dc1e2969 100644 --- a/src/hexer/cps.nim +++ b/src/hexer/cps.nim @@ -67,7 +67,8 @@ import std / [assertions, sets, tables] include ".." / lib / nifprelude import ".." / lib / symparser import ".." / nimony / [nimony_model, decls, programs, typenav, sizeof, expreval, xints, - builtintypes, langmodes, renderer, reporters, controlflow, typeprops] + builtintypes, langmodes, renderer, reporters, typeprops] +import ".." / njvl / nj import hexer_context # TODO: @@ -130,7 +131,6 @@ type yieldConts: Table[int, int] labels: Table[int, int] cf: TokenBuf - reachable: seq[bool] resultSym: SymId upcomingState: int counter: int @@ -560,51 +560,74 @@ proc isPassiveCall(c: var Context; n: PackedToken): bool = return false proc treIteratorBody(c: var Context; dest: var TokenBuf; init: TokenBuf; iter: Cursor; sym: SymId) = - c.currentProc.cf = toControlflow(iter, keepReturns = true) - c.currentProc.reachable = eliminateDeadInstructions(c.currentProc.cf) - - # Now compute basic blocks considering only reachable instructions + # Instead of lowering to a CFG, work on a copy of the original tree and + # derive suspension points directly from structured constructs. + # Transform the iterator/proc via the NJ pass to structured NJVL without jumps. + # Wrap the single proc into a temporary `(stmts ...)` so NJ can process it: + var wrapper = createTokenBuf(10) + wrapper.addParLe StmtsS, NoLineInfo + wrapper.copyTree iter + wrapper.addParRi() + var wcur = beginRead(wrapper) + c.currentProc.cf = eliminateJumps(wcur, c.thisModuleSuffix) + + # Compute suspension points (labels) and mapping from suspension sites to next state. c.currentProc.labels = initTable[int, int]() + c.currentProc.yieldConts = initTable[int, int]() var nextLabel = 0 - for i in 0.. 0 and i+diff < c.currentProc.cf.len and c.currentProc.reachable[i+diff]: - c.currentProc.labels[i+diff] = nextLabel - inc nextLabel - elif c.currentProc.cf[i].stmtKind == YldS or - (c.currentProc.cf[i].exprKind in CallKinds and isPassiveCall(c, c.currentProc.cf[i+1])): - # after a yield we also have a suspension point (a label): - var nested = 1 - c.currentProc.yieldConts[i] = nextLabel - for j in i+1.. 0: + case c.currentProc.cf[j].kind + of ParLe: inc nested + of ParRi: dec nested + else: discard + inc j + # j now points to the token after the matching ParRi + if j <= c.currentProc.cf.len: + c.currentProc.labels[j] = nextLabel + inc nextLabel + inc scan + elif scan.kind == ParRi: + dec depth + if depth == 0: break gather + inc scan + else: + inc scan + + # Analyze which locals escape across suspension points using the same label map var n = beginRead(c.currentProc.cf) inc n # ProcS for i in 0..