From 435554d2ad0f573752dbbf3055429a216ee9c7eb Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Fri, 19 Dec 2025 20:43:20 +0800 Subject: [PATCH] progress --- compiler/cgen.nim | 8 +++- compiler/closureiters.nim | 5 ++- compiler/lambdalifting.nim | 83 +++-------------------------------- compiler/lambdautils.nim | 80 +++++++++++++++++++++++++++++++++ compiler/plugins/itersgen.nim | 2 +- compiler/transf.nim | 4 +- 6 files changed, 100 insertions(+), 82 deletions(-) create mode 100644 compiler/lambdautils.nim diff --git a/compiler/cgen.nim b/compiler/cgen.nim index 8c84c6e720..276e4d6141 100644 --- a/compiler/cgen.nim +++ b/compiler/cgen.nim @@ -20,6 +20,8 @@ import from expanddefaults import caseObjDefaultBranch +import closureiters + import pipelineutils when defined(nimPreviewSlimSystem): @@ -1312,13 +1314,17 @@ proc genProcLvl3*(m: BModule, prc: PSym) = assert(prc.ast != nil) var procBody: PNode = nil - if isIterator(prc) and prc.closureBody != nil: + if prc.closureBody != nil: procBody = prc.closureBody else: procBody = transformBody(m.g.graph, m.idgen, prc, {}) if sfInjectDestructors in prc.flags: procBody = injectDestructorCalls(m.g.graph, m.idgen, prc, procBody) + if isIterator(prc): + procBody = transformClosureIterator(m.g.graph, m.idgen, prc, procBody) + prc.closureBody = procBody + let tmpInfo = prc.info discard freshLineInfo(p, prc.info) diff --git a/compiler/closureiters.nim b/compiler/closureiters.nim index 8fca38957d..08b3596a43 100644 --- a/compiler/closureiters.nim +++ b/compiler/closureiters.nim @@ -139,8 +139,9 @@ import ast, msgs, idents, - renderer, magicsys, lowerings, lambdalifting, modulegraphs, lineinfos, - options + renderer, magicsys, lowerings, modulegraphs, lineinfos + +import lambdautils import std/tables diff --git a/compiler/lambdalifting.nim b/compiler/lambdalifting.nim index e547bc66c9..b108e2c0a4 100644 --- a/compiler/lambdalifting.nim +++ b/compiler/lambdalifting.nim @@ -14,6 +14,8 @@ import idents, renderer, types, magicsys, lowerings, modulegraphs, lineinfos, transf, liftdestructors, typeallowed +import lambdautils, closureiters, injectdestructors + import std/[strutils, tables, intsets] when defined(nimPreviewSlimSystem): @@ -119,79 +121,6 @@ discard """ # local storage requirements for efficiency. This means closure iterators # have slightly different semantics from ordinary closures. -# ---------------- essential helpers ------------------------------------- - -const - upName* = ":up" # field name for the 'up' reference - paramName* = ":envP" - envName* = ":env" - -proc newCall(a: PSym, b: PNode): PNode = - result = newNodeI(nkCall, a.info) - result.add newSymNode(a) - result.add b - -proc createClosureIterStateType*(g: ModuleGraph; iter: PSym; idgen: IdGenerator): PType = - var n = newNodeI(nkRange, iter.info) - n.add newIntNode(nkIntLit, -1) - n.add newIntNode(nkIntLit, 0) - result = newType(tyRange, idgen, iter) - result.n = n - var intType = nilOrSysInt(g) - if intType.isNil: intType = newType(tyInt, idgen, iter) - rawAddSon(result, intType) - -proc createStateField(g: ModuleGraph; iter: PSym; idgen: IdGenerator): PSym = - result = newSym(skField, getIdent(g.cache, ":state"), idgen, iter, iter.info) - result.typ = createClosureIterStateType(g, iter, idgen) - -template isIterator*(owner: PSym): bool = - owner.kind == skIterator and owner.typ.callConv == ccClosure - -proc createEnvObj(g: ModuleGraph; idgen: IdGenerator; owner: PSym; info: TLineInfo): PType = - result = createObj(g, idgen, owner, info, final=false) - result.incl tfFinal - if owner.isIterator: - rawAddField(result, createStateField(g, owner, idgen)) - -proc getClosureIterResult*(g: ModuleGraph; iter: PSym; idgen: IdGenerator): PSym = - if resultPos < iter.ast.len: - result = iter.ast[resultPos].sym - else: - # XXX a bit hacky: - result = newSym(skResult, getIdent(g.cache, ":result"), idgen, iter, iter.info, {}) - result.typ = iter.typ.returnType - incl(result.flagsImpl, sfUsed) - iter.ast.add newSymNode(result) - -proc addHiddenParam(routine: PSym, param: PSym) = - assert param.kind == skParam - var params = routine.ast[paramsPos] - # -1 is correct here as param.position is 0 based but we have at position 0 - # some nkEffect node: - param.position = routine.typ.n.len-1 - params.add newSymNode(param) - #incl(routine.typ.flags, tfCapturesEnv) - assert sfFromGeneric in param.flags - #echo "produced environment: ", param.id, " for ", routine.id - -proc getEnvParam*(routine: PSym): PSym = - if routine.ast.isNil: return nil - let params = routine.ast[paramsPos] - let hidden = lastSon(params) - if hidden.kind == nkSym and hidden.sym.kind == skParam and hidden.sym.name.s == paramName: - result = hidden.sym - assert sfFromGeneric in result.flags - else: - result = nil - -proc getHiddenParam(g: ModuleGraph; routine: PSym): PSym = - result = getEnvParam(routine) - if result.isNil: - # writeStackTrace() - localError(g.config, routine.info, "internal error: could not find env param for " & routine.name.s) - result = routine - proc interestingVar(s: PSym): bool {.inline.} = result = s.kind in {skVar, skLet, skTemp, skForVar, skParam, skResult} and sfGlobal notin s.flags and @@ -706,9 +635,6 @@ proc accessViaEnvVar(n: PNode; owner: PSym; d: var DetectionPass; localError(d.graph.config, n.info, "internal error: not part of closure object type") result = n -proc getStateField*(g: ModuleGraph; owner: PSym): PSym = - getHiddenParam(g, owner).typ.skipTypes({tyOwned, tyRef, tyPtr}).n[0].sym - proc liftCapturedVars(n: PNode; owner: PSym; d: var DetectionPass; c: var LiftingPass): PNode @@ -759,6 +685,11 @@ proc liftCapturedVars(n: PNode; owner: PSym; d: var DetectionPass; else: s.transformedBody = newTree(nkStmtList, rawClosureCreation(s, d, c, n.info), body) finishClosureCreation(s, d, c, n.info, s.transformedBody) + + if isIterator(s) and s.closureBody == nil: + let injected = injectDestructorCalls(d.graph, d.idgen, s, body) + let closureBody = transformClosureIterator(d.graph, d.idgen, s, injected) + s.closureBody = closureBody c.inContainer = oldInContainer if s.typ.callConv == ccClosure: diff --git a/compiler/lambdautils.nim b/compiler/lambdautils.nim new file mode 100644 index 0000000000..b62c939aeb --- /dev/null +++ b/compiler/lambdautils.nim @@ -0,0 +1,80 @@ +import ast, modulegraphs, magicsys, idents, lowerings, msgs, lineinfos + +import std/assertions + +const + upName* = ":up" # field name for the 'up' reference + paramName* = ":envP" + envName* = ":env" + +# ---------------- essential helpers ------------------------------------- + + +proc newCall(a: PSym, b: PNode): PNode = + result = newNodeI(nkCall, a.info) + result.add newSymNode(a) + result.add b + +proc createClosureIterStateType*(g: ModuleGraph; iter: PSym; idgen: IdGenerator): PType = + var n = newNodeI(nkRange, iter.info) + n.add newIntNode(nkIntLit, -1) + n.add newIntNode(nkIntLit, 0) + result = newType(tyRange, idgen, iter) + result.n = n + var intType = nilOrSysInt(g) + if intType.isNil: intType = newType(tyInt, idgen, iter) + rawAddSon(result, intType) + +proc createStateField(g: ModuleGraph; iter: PSym; idgen: IdGenerator): PSym = + result = newSym(skField, getIdent(g.cache, ":state"), idgen, iter, iter.info) + result.typ = createClosureIterStateType(g, iter, idgen) + +template isIterator*(owner: PSym): bool = + owner.kind == skIterator and owner.typ.callConv == ccClosure + +proc createEnvObj*(g: ModuleGraph; idgen: IdGenerator; owner: PSym; info: TLineInfo): PType = + result = createObj(g, idgen, owner, info, final=false) + result.incl tfFinal + if owner.isIterator: + rawAddField(result, createStateField(g, owner, idgen)) + +proc getClosureIterResult*(g: ModuleGraph; iter: PSym; idgen: IdGenerator): PSym = + if resultPos < iter.ast.len: + result = iter.ast[resultPos].sym + else: + # XXX a bit hacky: + result = newSym(skResult, getIdent(g.cache, ":result"), idgen, iter, iter.info, {}) + result.typ = iter.typ.returnType + incl(result.flagsImpl, sfUsed) + iter.ast.add newSymNode(result) + +proc addHiddenParam*(routine: PSym, param: PSym) = + assert param.kind == skParam + var params = routine.ast[paramsPos] + # -1 is correct here as param.position is 0 based but we have at position 0 + # some nkEffect node: + param.position = routine.typ.n.len-1 + params.add newSymNode(param) + #incl(routine.typ.flags, tfCapturesEnv) + assert sfFromGeneric in param.flags + #echo "produced environment: ", param.id, " for ", routine.id + +proc getEnvParam*(routine: PSym): PSym = + if routine.ast.isNil: return nil + let params = routine.ast[paramsPos] + let hidden = lastSon(params) + if hidden.kind == nkSym and hidden.sym.kind == skParam and hidden.sym.name.s == paramName: + result = hidden.sym + assert sfFromGeneric in result.flags + else: + result = nil + +proc getHiddenParam*(g: ModuleGraph; routine: PSym): PSym = + result = getEnvParam(routine) + if result.isNil: + # writeStackTrace() + localError(g.config, routine.info, "internal error: could not find env param for " & routine.name.s) + result = routine + +proc getStateField*(g: ModuleGraph; owner: PSym): PSym = + getHiddenParam(g, owner).typ.skipTypes({tyOwned, tyRef, tyPtr}).n[0].sym diff --git a/compiler/plugins/itersgen.nim b/compiler/plugins/itersgen.nim index 6c0bfd8f30..6757dfaeff 100644 --- a/compiler/plugins/itersgen.nim +++ b/compiler/plugins/itersgen.nim @@ -9,7 +9,7 @@ ## Plugin to transform an inline iterator into a data structure. -import ".." / [ast, modulegraphs, lookups, semdata, lambdalifting, msgs] +import ".." / [ast, modulegraphs, lookups, semdata, lambdautils, lambdalifting, msgs] proc iterToProcImpl*(c: PContext, n: PNode): PNode = result = newNodeI(nkStmtList, n.info) diff --git a/compiler/transf.nim b/compiler/transf.nim index 5187f05346..34235a1099 100644 --- a/compiler/transf.nim +++ b/compiler/transf.nim @@ -130,8 +130,8 @@ proc transformSymAux(c: PTransf, n: PNode): PNode = if c.tooEarly: return n else: if s.closureBody == nil: - let transformedBody = injectDestructorCalls(c.graph, c.idgen, s, body) - let closureBody = transformClosureIterator(c.graph, c.idgen, s, transformedBody) + let injected = injectDestructorCalls(c.graph, c.idgen, s, body) + let closureBody = transformClosureIterator(c.graph, c.idgen, s, injected) s.closureBody = closureBody return liftIterSym(c.graph, n, c.idgen, getCurrOwner(c)) elif s.kind in {skProc, skFunc, skConverter, skMethod} and not c.tooEarly: