This commit is contained in:
ringabout
2025-12-19 20:43:20 +08:00
parent 0106cfdbe2
commit 435554d2ad
6 changed files with 100 additions and 82 deletions

View File

@@ -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)

View File

@@ -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

View File

@@ -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:

80
compiler/lambdautils.nim Normal file
View File

@@ -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

View File

@@ -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)

View File

@@ -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: