diff --git a/lib/std/system.nim b/lib/std/system.nim index fd37fca5e..77a8aaec1 100644 --- a/lib/std/system.nim +++ b/lib/std/system.nim @@ -231,7 +231,7 @@ proc afterYield*(): Continuation {.semantics: "afterYield".} = ## Do not use unless you know what you are doing. result = Continuation(fn: nil, env: nil) -proc delay*(x: untyped): Continuation {.magic: "Delay".} +proc delay*(x: typed): Continuation {.magic: "Delay".} ## Delays the execution of a `.passive` proc and returns a continuation representation ## this call. Think of it as a `toTask` builtin. diff --git a/src/hexer/cps.nim b/src/hexer/cps.nim index d457671b7..1a2b1b7e5 100644 --- a/src/hexer/cps.nim +++ b/src/hexer/cps.nim @@ -316,7 +316,6 @@ proc trPassiveCall(c: var Context; dest: var TokenBuf; n: var Cursor; sym: SymId proc trDelay(c: var Context; dest: var TokenBuf; n: var Cursor) = inc n skip n # skip type; it is `Continuation` and uninteresting here - const nested = 1 if n.exprKind in CallKinds and n.firstSon.kind == Symbol: let fn = n.firstSon.symId @@ -325,8 +324,7 @@ proc trDelay(c: var Context; dest: var TokenBuf; n: var Cursor) = dest.copyIntoKind ErrT, n.info: dest.addStrLit "`delay` takes a call expression" skip n - for i in 0.. + # return/raise x --> # this.res[] = x - # return this.caller - let info = n.info + # return/raise this.caller + let head = n.load() + let info = head.info returnValue(c, dest, n, info) - dest.copyIntoKind RetS, info: - dest.copyIntoKind DotX, info: - dest.copyIntoKind DerefX, info: - dest.addSymUse pool.syms.getOrIncl(EnvParamName), info - dest.addSymUse pool.syms.getOrIncl(CallerFieldName), info - dest.addIntLit 1, info # field is in superclass + dest.add head + dest.copyIntoKind DotX, info: + dest.copyIntoKind DerefX, info: + dest.addSymUse pool.syms.getOrIncl(EnvParamName), info + dest.addSymUse pool.syms.getOrIncl(CallerFieldName), info + dest.addIntLit 1, info # field is in superclass + dest.addParRi() proc escapingLocals(c: var Context; n: Cursor) = if n.kind == DotToken: return @@ -559,39 +560,98 @@ proc isPassiveCall(c: var Context; n: PackedToken): bool = return true return false +proc findDelayX(c: var Context; n: Cursor): Cursor = + var nested = 0 + var n = n + while true: + case n.kind + of ParLe: + if n.exprKind == DelayX: + inc n + skip n # type + return n + inc nested + of ParRi: + dec nested + else: + discard + if nested == 0: + break + inc n + return default(Cursor) + +proc skipButHandleGoto(c: var Context; n: var Cursor; nextLabel: var int) = + if n.kind == ParLe: + var nested = 0 + while true: + inc n + case n.kind + of ParRi: + if nested == 0: break + dec nested + of ParLe: inc nested + of GotoInstr: + let diff = n.getInt28 + let i = cursorToPosition(c.currentProc.cf, n) + if i+diff > 0 and i+diff < c.currentProc.cf.len and c.currentProc.reachable[i+diff]: + c.currentProc.labels[i+diff] = nextLabel + inc nextLabel + else: + discard + inc n + 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 c.currentProc.labels = 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])): + elif n.stmtKind == YldS or + (n.exprKind in CallKinds and isPassiveCall(c, n.firstSon.load)): + let i = cursorToPosition(c.currentProc.cf, n) + if c.currentProc.reachable[i]: # after a yield we also have a suspension point (a label): - var nested = 1 c.currentProc.yieldConts[i] = nextLabel - for j in i+1..