Merge branch 'devel' into yield-in-try
This commit is contained in:
commit
cfe40a3e6e
121 changed files with 5545 additions and 5491 deletions
|
|
@ -11,7 +11,7 @@
|
|||
|
||||
import
|
||||
intsets, strutils, options, ast, astalgo, trees, treetab, msgs,
|
||||
idents, renderer, types, magicsys, rodread, lowerings, tables
|
||||
idents, renderer, types, magicsys, rodread, lowerings, tables, modulegraphs
|
||||
|
||||
discard """
|
||||
The basic approach is that captured vars need to be put on the heap and
|
||||
|
|
@ -125,32 +125,32 @@ proc newCall(a: PSym, b: PNode): PNode =
|
|||
result.add newSymNode(a)
|
||||
result.add b
|
||||
|
||||
proc createClosureIterStateType*(iter: PSym): PType =
|
||||
proc createClosureIterStateType*(g: ModuleGraph; iter: PSym): PType =
|
||||
var n = newNodeI(nkRange, iter.info)
|
||||
addSon(n, newIntNode(nkIntLit, -1))
|
||||
addSon(n, newIntNode(nkIntLit, 0))
|
||||
result = newType(tyRange, iter)
|
||||
result.n = n
|
||||
var intType = nilOrSysInt()
|
||||
var intType = nilOrSysInt(g)
|
||||
if intType.isNil: intType = newType(tyInt, iter)
|
||||
rawAddSon(result, intType)
|
||||
|
||||
proc createStateField(iter: PSym): PSym =
|
||||
proc createStateField(g: ModuleGraph; iter: PSym): PSym =
|
||||
result = newSym(skField, getIdent(":state"), iter, iter.info)
|
||||
result.typ = createClosureIterStateType(iter)
|
||||
result.typ = createClosureIterStateType(g, iter)
|
||||
|
||||
proc createEnvObj(owner: PSym; info: TLineInfo): PType =
|
||||
proc createEnvObj(g: ModuleGraph; owner: PSym; info: TLineInfo): PType =
|
||||
# YYY meh, just add the state field for every closure for now, it's too
|
||||
# hard to figure out if it comes from a closure iterator:
|
||||
result = createObj(owner, info, final=false)
|
||||
rawAddField(result, createStateField(owner))
|
||||
result = createObj(g, owner, info, final=false)
|
||||
rawAddField(result, createStateField(g, owner))
|
||||
|
||||
proc getClosureIterResult*(iter: PSym): PSym =
|
||||
if resultPos < iter.ast.len:
|
||||
result = iter.ast.sons[resultPos].sym
|
||||
else:
|
||||
# XXX a bit hacky:
|
||||
result = newSym(skResult, getIdent":result", iter, iter.info)
|
||||
result = newSym(skResult, getIdent":result", iter, iter.info, {})
|
||||
result.typ = iter.typ.sons[0]
|
||||
incl(result.flags, sfUsed)
|
||||
iter.ast.add newSymNode(result)
|
||||
|
|
@ -166,7 +166,7 @@ proc addHiddenParam(routine: PSym, param: PSym) =
|
|||
assert sfFromGeneric in param.flags
|
||||
#echo "produced environment: ", param.id, " for ", routine.id
|
||||
|
||||
proc getHiddenParam(routine: PSym): PSym =
|
||||
proc getHiddenParam(g: ModuleGraph; routine: PSym): PSym =
|
||||
let params = routine.ast.sons[paramsPos]
|
||||
let hidden = lastSon(params)
|
||||
if hidden.kind == nkSym and hidden.sym.kind == skParam and hidden.sym.name.s == paramName:
|
||||
|
|
@ -174,7 +174,7 @@ proc getHiddenParam(routine: PSym): PSym =
|
|||
assert sfFromGeneric in result.flags
|
||||
else:
|
||||
# writeStackTrace()
|
||||
localError(routine.info, "internal error: could not find env param for " & routine.name.s)
|
||||
localError(g.config, routine.info, "internal error: could not find env param for " & routine.name.s)
|
||||
result = routine
|
||||
|
||||
proc getEnvParam*(routine: PSym): PSym =
|
||||
|
|
@ -208,14 +208,14 @@ proc newAsgnStmt(le, ri: PNode, info: TLineInfo): PNode =
|
|||
result.sons[0] = le
|
||||
result.sons[1] = ri
|
||||
|
||||
proc makeClosure*(prc: PSym; env: PNode; info: TLineInfo): PNode =
|
||||
proc makeClosure*(g: ModuleGraph; prc: PSym; env: PNode; info: TLineInfo): PNode =
|
||||
result = newNodeIT(nkClosure, info, prc.typ)
|
||||
result.add(newSymNode(prc))
|
||||
if env == nil:
|
||||
result.add(newNodeIT(nkNilLit, info, getSysType(tyNil)))
|
||||
result.add(newNodeIT(nkNilLit, info, getSysType(g, info, tyNil)))
|
||||
else:
|
||||
if env.skipConv.kind == nkClosure:
|
||||
localError(info, "internal error: taking closure of closure")
|
||||
localError(g.config, info, "internal error: taking closure of closure")
|
||||
result.add(env)
|
||||
|
||||
proc interestingIterVar(s: PSym): bool {.inline.} =
|
||||
|
|
@ -227,23 +227,23 @@ proc interestingIterVar(s: PSym): bool {.inline.} =
|
|||
template isIterator*(owner: PSym): bool =
|
||||
owner.kind == skIterator and owner.typ.callConv == ccClosure
|
||||
|
||||
proc liftingHarmful(owner: PSym): bool {.inline.} =
|
||||
proc liftingHarmful(conf: ConfigRef; owner: PSym): bool {.inline.} =
|
||||
## lambda lifting can be harmful for JS-like code generators.
|
||||
let isCompileTime = sfCompileTime in owner.flags or owner.kind == skMacro
|
||||
result = gCmd == cmdCompileToJS and not isCompileTime
|
||||
result = conf.cmd == cmdCompileToJS and not isCompileTime
|
||||
|
||||
proc liftIterSym*(n: PNode; owner: PSym): PNode =
|
||||
proc liftIterSym*(g: ModuleGraph; n: PNode; owner: PSym): PNode =
|
||||
# transforms (iter) to (let env = newClosure[iter](); (iter, env))
|
||||
if liftingHarmful(owner): return n
|
||||
if liftingHarmful(g.config, owner): return n
|
||||
let iter = n.sym
|
||||
assert iter.isIterator
|
||||
|
||||
result = newNodeIT(nkStmtListExpr, n.info, n.typ)
|
||||
|
||||
let hp = getHiddenParam(iter)
|
||||
let hp = getHiddenParam(g, iter)
|
||||
var env: PNode
|
||||
if owner.isIterator:
|
||||
let it = getHiddenParam(owner)
|
||||
let it = getHiddenParam(g, owner)
|
||||
addUniqueField(it.typ.sons[0], hp)
|
||||
env = indirectAccess(newSymNode(it), hp, hp.info)
|
||||
else:
|
||||
|
|
@ -255,11 +255,11 @@ proc liftIterSym*(n: PNode; owner: PSym): PNode =
|
|||
addVar(v, env)
|
||||
result.add(v)
|
||||
# add 'new' statement:
|
||||
result.add newCall(getSysSym"internalNew", env)
|
||||
result.add makeClosure(iter, env, n.info)
|
||||
result.add newCall(getSysSym(g, n.info, "internalNew"), env)
|
||||
result.add makeClosure(g, iter, env, n.info)
|
||||
|
||||
proc freshVarForClosureIter*(s, owner: PSym): PNode =
|
||||
let envParam = getHiddenParam(owner)
|
||||
proc freshVarForClosureIter*(g: ModuleGraph; s, owner: PSym): PNode =
|
||||
let envParam = getHiddenParam(g, owner)
|
||||
let obj = envParam.typ.lastSon
|
||||
addField(obj, s)
|
||||
|
||||
|
|
@ -269,18 +269,18 @@ proc freshVarForClosureIter*(s, owner: PSym): PNode =
|
|||
if field != nil:
|
||||
result = rawIndirectAccess(access, field, s.info)
|
||||
else:
|
||||
localError(s.info, "internal error: cannot generate fresh variable")
|
||||
localError(g.config, s.info, "internal error: cannot generate fresh variable")
|
||||
result = access
|
||||
|
||||
# ------------------ new stuff -------------------------------------------
|
||||
|
||||
proc markAsClosure(owner: PSym; n: PNode) =
|
||||
proc markAsClosure(g: ModuleGraph; owner: PSym; n: PNode) =
|
||||
let s = n.sym
|
||||
if illegalCapture(s):
|
||||
localError(n.info, "illegal capture '$1' of type <$2> which is declared here: $3" %
|
||||
localError(g.config, n.info, "illegal capture '$1' of type <$2> which is declared here: $3" %
|
||||
[s.name.s, typeToString(s.typ), $s.info])
|
||||
elif owner.typ.callConv notin {ccClosure, ccDefault}:
|
||||
localError(n.info, "illegal capture '$1' because '$2' has the calling convention: <$3>" %
|
||||
localError(g.config, n.info, "illegal capture '$1' because '$2' has the calling convention: <$3>" %
|
||||
[s.name.s, owner.name.s, CallingConvToStr[owner.typ.callConv]])
|
||||
incl(owner.typ.flags, tfCapturesEnv)
|
||||
owner.typ.callConv = ccClosure
|
||||
|
|
@ -290,12 +290,14 @@ type
|
|||
processed, capturedVars: IntSet
|
||||
ownerToType: Table[int, PType]
|
||||
somethingToDo: bool
|
||||
graph: ModuleGraph
|
||||
|
||||
proc initDetectionPass(fn: PSym): DetectionPass =
|
||||
proc initDetectionPass(g: ModuleGraph; fn: PSym): DetectionPass =
|
||||
result.processed = initIntSet()
|
||||
result.capturedVars = initIntSet()
|
||||
result.ownerToType = initTable[int, PType]()
|
||||
result.processed.incl(fn.id)
|
||||
result.graph = g
|
||||
|
||||
discard """
|
||||
proc outer =
|
||||
|
|
@ -312,7 +314,7 @@ proc getEnvTypeForOwner(c: var DetectionPass; owner: PSym;
|
|||
result = c.ownerToType.getOrDefault(owner.id)
|
||||
if result.isNil:
|
||||
result = newType(tyRef, owner)
|
||||
let obj = createEnvObj(owner, info)
|
||||
let obj = createEnvObj(c.graph, owner, info)
|
||||
rawAddSon(result, obj)
|
||||
c.ownerToType[owner.id] = result
|
||||
|
||||
|
|
@ -321,13 +323,13 @@ proc createUpField(c: var DetectionPass; dest, dep: PSym; info: TLineInfo) =
|
|||
let obj = refObj.lastSon
|
||||
let fieldType = c.getEnvTypeForOwner(dep, info) #getHiddenParam(dep).typ
|
||||
if refObj == fieldType:
|
||||
localError(dep.info, "internal error: invalid up reference computed")
|
||||
localError(c.graph.config, dep.info, "internal error: invalid up reference computed")
|
||||
|
||||
let upIdent = getIdent(upName)
|
||||
let upField = lookupInRecord(obj.n, upIdent)
|
||||
if upField != nil:
|
||||
if upField.typ != fieldType:
|
||||
localError(dep.info, "internal error: up references do not agree")
|
||||
localError(c.graph.config, dep.info, "internal error: up references do not agree")
|
||||
else:
|
||||
let result = newSym(skField, upIdent, obj.owner, obj.owner.info)
|
||||
result.typ = fieldType
|
||||
|
|
@ -369,7 +371,7 @@ proc addClosureParam(c: var DetectionPass; fn: PSym; info: TLineInfo) =
|
|||
cp.typ = t
|
||||
addHiddenParam(fn, cp)
|
||||
elif cp.typ != t and fn.kind != skIterator:
|
||||
localError(fn.info, "internal error: inconsistent environment type")
|
||||
localError(c.graph.config, fn.info, "internal error: inconsistent environment type")
|
||||
#echo "adding closure to ", fn.name.s
|
||||
|
||||
proc detectCapturedVars(n: PNode; owner: PSym; c: var DetectionPass) =
|
||||
|
|
@ -395,7 +397,7 @@ proc detectCapturedVars(n: PNode; owner: PSym; c: var DetectionPass) =
|
|||
addClosureParam(c, owner, n.info)
|
||||
if interestingIterVar(s):
|
||||
if not c.capturedVars.containsOrIncl(s.id):
|
||||
let obj = getHiddenParam(owner).typ.lastSon
|
||||
let obj = getHiddenParam(c.graph, owner).typ.lastSon
|
||||
#let obj = c.getEnvTypeForOwner(s.owner).lastSon
|
||||
|
||||
if s.name == getIdent(":state"):
|
||||
|
|
@ -419,7 +421,7 @@ proc detectCapturedVars(n: PNode; owner: PSym; c: var DetectionPass) =
|
|||
"""
|
||||
# mark 'owner' as taking a closure:
|
||||
c.somethingToDo = true
|
||||
markAsClosure(owner, n)
|
||||
markAsClosure(c.graph, owner, n)
|
||||
addClosureParam(c, owner, n.info)
|
||||
#echo "capturing ", n.info
|
||||
# variable 's' is actually captured:
|
||||
|
|
@ -444,7 +446,7 @@ proc detectCapturedVars(n: PNode; owner: PSym; c: var DetectionPass) =
|
|||
"""
|
||||
let up = w.skipGenericOwner
|
||||
#echo "up for ", w.name.s, " up ", up.name.s
|
||||
markAsClosure(w, n)
|
||||
markAsClosure(c.graph, w, n)
|
||||
addClosureParam(c, w, n.info) # , ow
|
||||
createUpField(c, w, up, n.info)
|
||||
w = up
|
||||
|
|
@ -465,17 +467,16 @@ type
|
|||
processed: IntSet
|
||||
envVars: Table[int, PNode]
|
||||
inContainer: int
|
||||
features: set[Feature]
|
||||
|
||||
proc initLiftingPass(fn: PSym): LiftingPass =
|
||||
result.processed = initIntSet()
|
||||
result.processed.incl(fn.id)
|
||||
result.envVars = initTable[int, PNode]()
|
||||
|
||||
proc accessViaEnvParam(n: PNode; owner: PSym): PNode =
|
||||
proc accessViaEnvParam(g: ModuleGraph; n: PNode; owner: PSym): PNode =
|
||||
let s = n.sym
|
||||
# Type based expression construction for simplicity:
|
||||
let envParam = getHiddenParam(owner)
|
||||
let envParam = getHiddenParam(g, owner)
|
||||
if not envParam.isNil:
|
||||
var access = newSymNode(envParam)
|
||||
while true:
|
||||
|
|
@ -487,7 +488,7 @@ proc accessViaEnvParam(n: PNode; owner: PSym): PNode =
|
|||
let upField = lookupInRecord(obj.n, getIdent(upName))
|
||||
if upField == nil: break
|
||||
access = rawIndirectAccess(access, upField, n.info)
|
||||
localError(n.info, "internal error: environment misses: " & s.name.s)
|
||||
localError(g.config, n.info, "internal error: environment misses: " & s.name.s)
|
||||
result = n
|
||||
|
||||
proc newEnvVar(owner: PSym; typ: PType): PNode =
|
||||
|
|
@ -506,22 +507,22 @@ proc newEnvVar(owner: PSym; typ: PType): PNode =
|
|||
proc setupEnvVar(owner: PSym; d: DetectionPass;
|
||||
c: var LiftingPass): PNode =
|
||||
if owner.isIterator:
|
||||
return getHiddenParam(owner).newSymNode
|
||||
return getHiddenParam(d.graph, owner).newSymNode
|
||||
result = c.envvars.getOrDefault(owner.id)
|
||||
if result.isNil:
|
||||
let envVarType = d.ownerToType.getOrDefault(owner.id)
|
||||
if envVarType.isNil:
|
||||
localError owner.info, "internal error: could not determine closure type"
|
||||
localError d.graph.config, owner.info, "internal error: could not determine closure type"
|
||||
result = newEnvVar(owner, envVarType)
|
||||
c.envVars[owner.id] = result
|
||||
|
||||
proc getUpViaParam(owner: PSym): PNode =
|
||||
let p = getHiddenParam(owner)
|
||||
proc getUpViaParam(g: ModuleGraph; owner: PSym): PNode =
|
||||
let p = getHiddenParam(g, owner)
|
||||
result = p.newSymNode
|
||||
if owner.isIterator:
|
||||
let upField = lookupInRecord(p.typ.lastSon.n, getIdent(upName))
|
||||
if upField == nil:
|
||||
localError(owner.info, "could not find up reference for closure iter")
|
||||
localError(g.config, owner.info, "could not find up reference for closure iter")
|
||||
else:
|
||||
result = rawIndirectAccess(result, upField, p.info)
|
||||
|
||||
|
|
@ -531,7 +532,7 @@ proc rawClosureCreation(owner: PSym;
|
|||
|
||||
var env: PNode
|
||||
if owner.isIterator:
|
||||
env = getHiddenParam(owner).newSymNode
|
||||
env = getHiddenParam(d.graph, owner).newSymNode
|
||||
else:
|
||||
env = setupEnvVar(owner, d, c)
|
||||
if env.kind == nkSym:
|
||||
|
|
@ -539,7 +540,7 @@ proc rawClosureCreation(owner: PSym;
|
|||
addVar(v, env)
|
||||
result.add(v)
|
||||
# add 'new' statement:
|
||||
result.add(newCall(getSysSym"internalNew", env))
|
||||
result.add(newCall(getSysSym(d.graph, env.info, "internalNew"), env))
|
||||
# add assignment statements for captured parameters:
|
||||
for i in 1..<owner.typ.n.len:
|
||||
let local = owner.typ.n[i].sym
|
||||
|
|
@ -550,7 +551,7 @@ proc rawClosureCreation(owner: PSym;
|
|||
|
||||
let upField = lookupInRecord(env.typ.lastSon.n, getIdent(upName))
|
||||
if upField != nil:
|
||||
let up = getUpViaParam(owner)
|
||||
let up = getUpViaParam(d.graph, owner)
|
||||
if up != nil and upField.typ == up.typ:
|
||||
result.add(newAsgnStmt(rawIndirectAccess(env, upField, env.info),
|
||||
up, env.info))
|
||||
|
|
@ -558,7 +559,7 @@ proc rawClosureCreation(owner: PSym;
|
|||
# result.add(newAsgnStmt(rawIndirectAccess(env, upField, env.info),
|
||||
# oldenv, env.info))
|
||||
else:
|
||||
localError(env.info, "internal error: cannot create up reference")
|
||||
localError(d.graph.config, env.info, "internal error: cannot create up reference")
|
||||
|
||||
proc closureCreationForIter(iter: PNode;
|
||||
d: DetectionPass; c: var LiftingPass): PNode =
|
||||
|
|
@ -566,10 +567,10 @@ proc closureCreationForIter(iter: PNode;
|
|||
let owner = iter.sym.skipGenericOwner
|
||||
var v = newSym(skVar, getIdent(envName), owner, iter.info)
|
||||
incl(v.flags, sfShadowed)
|
||||
v.typ = getHiddenParam(iter.sym).typ
|
||||
v.typ = getHiddenParam(d.graph, iter.sym).typ
|
||||
var vnode: PNode
|
||||
if owner.isIterator:
|
||||
let it = getHiddenParam(owner)
|
||||
let it = getHiddenParam(d.graph, owner)
|
||||
addUniqueField(it.typ.sons[0], v)
|
||||
vnode = indirectAccess(newSymNode(it), v, v.info)
|
||||
else:
|
||||
|
|
@ -577,7 +578,7 @@ proc closureCreationForIter(iter: PNode;
|
|||
var vs = newNodeI(nkVarSection, iter.info)
|
||||
addVar(vs, vnode)
|
||||
result.add(vs)
|
||||
result.add(newCall(getSysSym"internalNew", vnode))
|
||||
result.add(newCall(getSysSym(d.graph, iter.info, "internalNew"), vnode))
|
||||
|
||||
let upField = lookupInRecord(v.typ.lastSon.n, getIdent(upName))
|
||||
if upField != nil:
|
||||
|
|
@ -586,8 +587,8 @@ proc closureCreationForIter(iter: PNode;
|
|||
result.add(newAsgnStmt(rawIndirectAccess(vnode, upField, iter.info),
|
||||
u, iter.info))
|
||||
else:
|
||||
localError(iter.info, "internal error: cannot create up reference for iter")
|
||||
result.add makeClosure(iter.sym, vnode, iter.info)
|
||||
localError(d.graph.config, iter.info, "internal error: cannot create up reference for iter")
|
||||
result.add makeClosure(d.graph, iter.sym, vnode, iter.info)
|
||||
|
||||
proc accessViaEnvVar(n: PNode; owner: PSym; d: DetectionPass;
|
||||
c: var LiftingPass): PNode =
|
||||
|
|
@ -597,11 +598,11 @@ proc accessViaEnvVar(n: PNode; owner: PSym; d: DetectionPass;
|
|||
if field != nil:
|
||||
result = rawIndirectAccess(access, field, n.info)
|
||||
else:
|
||||
localError(n.info, "internal error: not part of closure object type")
|
||||
localError(d.graph.config, n.info, "internal error: not part of closure object type")
|
||||
result = n
|
||||
|
||||
proc getStateField*(owner: PSym): PSym =
|
||||
getHiddenParam(owner).typ.sons[0].n.sons[0].sym
|
||||
proc getStateField*(g: ModuleGraph; owner: PSym): PSym =
|
||||
getHiddenParam(g, owner).typ.sons[0].n.sons[0].sym
|
||||
|
||||
proc liftCapturedVars(n: PNode; owner: PSym; d: DetectionPass;
|
||||
c: var LiftingPass): PNode
|
||||
|
|
@ -609,8 +610,8 @@ proc liftCapturedVars(n: PNode; owner: PSym; d: DetectionPass;
|
|||
proc transformYield(n: PNode; owner: PSym; d: DetectionPass;
|
||||
c: var LiftingPass): PNode =
|
||||
if c.inContainer > 0:
|
||||
localError(n.info, "invalid control flow: 'yield' within a constructor")
|
||||
let state = getStateField(owner)
|
||||
localError(d.graph.config, n.info, "invalid control flow: 'yield' within a constructor")
|
||||
let state = getStateField(d.graph, owner)
|
||||
assert state != nil
|
||||
assert state.typ != nil
|
||||
assert state.typ.n != nil
|
||||
|
|
@ -620,7 +621,8 @@ proc transformYield(n: PNode; owner: PSym; d: DetectionPass;
|
|||
var stateAsgnStmt = newNodeI(nkAsgn, n.info)
|
||||
stateAsgnStmt.add(rawIndirectAccess(newSymNode(getEnvParam(owner)),
|
||||
state, n.info))
|
||||
stateAsgnStmt.add(newIntTypeNode(nkIntLit, stateNo, getSysType(tyInt)))
|
||||
stateAsgnStmt.add(newIntTypeNode(nkIntLit, stateNo,
|
||||
getSysType(d.graph, n.info, tyInt)))
|
||||
|
||||
var retStmt = newNodeI(nkReturnStmt, n.info)
|
||||
if n.sons[0].kind != nkEmpty:
|
||||
|
|
@ -633,7 +635,8 @@ proc transformYield(n: PNode; owner: PSym; d: DetectionPass;
|
|||
retStmt.add(emptyNode)
|
||||
|
||||
var stateLabelStmt = newNodeI(nkState, n.info)
|
||||
stateLabelStmt.add(newIntTypeNode(nkIntLit, stateNo, getSysType(tyInt)))
|
||||
stateLabelStmt.add(newIntTypeNode(nkIntLit, stateNo,
|
||||
getSysType(d.graph, n.info, tyInt)))
|
||||
|
||||
result = newNodeI(nkStmtList, n.info)
|
||||
result.add(stateAsgnStmt)
|
||||
|
|
@ -642,16 +645,16 @@ proc transformYield(n: PNode; owner: PSym; d: DetectionPass;
|
|||
|
||||
proc transformReturn(n: PNode; owner: PSym; d: DetectionPass;
|
||||
c: var LiftingPass): PNode =
|
||||
let state = getStateField(owner)
|
||||
let state = getStateField(d.graph, owner)
|
||||
result = newNodeI(nkStmtList, n.info)
|
||||
var stateAsgnStmt = newNodeI(nkAsgn, n.info)
|
||||
stateAsgnStmt.add(rawIndirectAccess(newSymNode(getEnvParam(owner)),
|
||||
state, n.info))
|
||||
stateAsgnStmt.add(newIntTypeNode(nkIntLit, -1, getSysType(tyInt)))
|
||||
stateAsgnStmt.add(newIntTypeNode(nkIntLit, -1, getSysType(d.graph, n.info, tyInt)))
|
||||
result.add(stateAsgnStmt)
|
||||
result.add(n)
|
||||
|
||||
proc wrapIterBody(n: PNode; owner: PSym): PNode =
|
||||
proc wrapIterBody(g: ModuleGraph; n: PNode; owner: PSym): PNode =
|
||||
if not owner.isIterator: return n
|
||||
when false:
|
||||
# unfortunately control flow is still convoluted and we can end up
|
||||
|
|
@ -665,7 +668,7 @@ proc wrapIterBody(n: PNode; owner: PSym): PNode =
|
|||
let info = n.info
|
||||
result = newNodeI(nkStmtList, info)
|
||||
var gs = newNodeI(nkGotoState, info)
|
||||
gs.add(rawIndirectAccess(newSymNode(owner.getHiddenParam), getStateField(owner), info))
|
||||
gs.add(rawIndirectAccess(newSymNode(getHiddenParam(g, owner)), getStateField(g, owner), info))
|
||||
result.add(gs)
|
||||
var state0 = newNodeI(nkState, info)
|
||||
state0.add(newIntNode(nkIntLit, 0))
|
||||
|
|
@ -674,9 +677,9 @@ proc wrapIterBody(n: PNode; owner: PSym): PNode =
|
|||
result.add(n)
|
||||
|
||||
var stateAsgnStmt = newNodeI(nkAsgn, info)
|
||||
stateAsgnStmt.add(rawIndirectAccess(newSymNode(owner.getHiddenParam),
|
||||
getStateField(owner), info))
|
||||
stateAsgnStmt.add(newIntTypeNode(nkIntLit, -1, getSysType(tyInt)))
|
||||
stateAsgnStmt.add(rawIndirectAccess(newSymNode(getHiddenParam(g, owner)),
|
||||
getStateField(g, owner), info))
|
||||
stateAsgnStmt.add(newIntTypeNode(nkIntLit, -1, getSysType(g, info, tyInt)))
|
||||
result.add(stateAsgnStmt)
|
||||
|
||||
proc symToClosure(n: PNode; owner: PSym; d: DetectionPass;
|
||||
|
|
@ -684,25 +687,25 @@ proc symToClosure(n: PNode; owner: PSym; d: DetectionPass;
|
|||
let s = n.sym
|
||||
if s == owner:
|
||||
# recursive calls go through (lambda, hiddenParam):
|
||||
let available = getHiddenParam(owner)
|
||||
result = makeClosure(s, available.newSymNode, n.info)
|
||||
let available = getHiddenParam(d.graph, owner)
|
||||
result = makeClosure(d.graph, s, available.newSymNode, n.info)
|
||||
elif s.isIterator:
|
||||
result = closureCreationForIter(n, d, c)
|
||||
elif s.skipGenericOwner == owner:
|
||||
# direct dependency, so use the outer's env variable:
|
||||
result = makeClosure(s, setupEnvVar(owner, d, c), n.info)
|
||||
result = makeClosure(d.graph, s, setupEnvVar(owner, d, c), n.info)
|
||||
else:
|
||||
let available = getHiddenParam(owner)
|
||||
let wanted = getHiddenParam(s).typ
|
||||
let available = getHiddenParam(d.graph, owner)
|
||||
let wanted = getHiddenParam(d.graph, s).typ
|
||||
# ugh: call through some other inner proc;
|
||||
var access = newSymNode(available)
|
||||
while true:
|
||||
if access.typ == wanted:
|
||||
return makeClosure(s, access, n.info)
|
||||
return makeClosure(d.graph, s, access, n.info)
|
||||
let obj = access.typ.sons[0]
|
||||
let upField = lookupInRecord(obj.n, getIdent(upName))
|
||||
if upField == nil:
|
||||
localError(n.info, "internal error: no environment found")
|
||||
localError(d.graph.config, n.info, "internal error: no environment found")
|
||||
return n
|
||||
access = rawIndirectAccess(access, upField, n.info)
|
||||
|
||||
|
|
@ -719,8 +722,8 @@ proc liftCapturedVars(n: PNode; owner: PSym; d: DetectionPass;
|
|||
let oldInContainer = c.inContainer
|
||||
c.inContainer = 0
|
||||
var body = liftCapturedVars(s.getBody, s, d, c)
|
||||
if oldIterTransf in c.features:
|
||||
body = wrapIterBody(body, s)
|
||||
if oldIterTransf in d.graph.config.features:
|
||||
body = wrapIterBody(d.graph, body, s)
|
||||
if c.envvars.getOrDefault(s.id).isNil:
|
||||
s.ast.sons[bodyPos] = body
|
||||
else:
|
||||
|
|
@ -730,9 +733,9 @@ proc liftCapturedVars(n: PNode; owner: PSym; d: DetectionPass;
|
|||
result = symToClosure(n, owner, d, c)
|
||||
elif s.id in d.capturedVars:
|
||||
if s.owner != owner:
|
||||
result = accessViaEnvParam(n, owner)
|
||||
result = accessViaEnvParam(d.graph, n, owner)
|
||||
elif owner.isIterator and interestingIterVar(s):
|
||||
result = accessViaEnvParam(n, owner)
|
||||
result = accessViaEnvParam(d.graph, n, owner)
|
||||
else:
|
||||
result = accessViaEnvVar(n, owner, d, c)
|
||||
of nkEmpty..pred(nkSym), succ(nkSym)..nkNilLit, nkComesFrom,
|
||||
|
|
@ -763,9 +766,9 @@ proc liftCapturedVars(n: PNode; owner: PSym; d: DetectionPass;
|
|||
if n[1].kind == nkClosure: result = n[1]
|
||||
else:
|
||||
if owner.isIterator:
|
||||
if oldIterTransf in c.features and n.kind == nkYieldStmt:
|
||||
if oldIterTransf in d.graph.config.features and n.kind == nkYieldStmt:
|
||||
return transformYield(n, owner, d, c)
|
||||
elif oldIterTransf in c.features and n.kind == nkReturnStmt:
|
||||
elif oldIterTransf in d.graph.config.features and n.kind == nkReturnStmt:
|
||||
return transformReturn(n, owner, d, c)
|
||||
elif nfLL in n.flags:
|
||||
# special case 'when nimVm' due to bug #3636:
|
||||
|
|
@ -798,8 +801,8 @@ proc semCaptureSym*(s, owner: PSym) =
|
|||
# since the analysis is not entirely correct, we don't set 'tfCapturesEnv'
|
||||
# here
|
||||
|
||||
proc liftIterToProc*(fn: PSym; body: PNode; ptrType: PType): PNode =
|
||||
var d = initDetectionPass(fn)
|
||||
proc liftIterToProc*(g: ModuleGraph; fn: PSym; body: PNode; ptrType: PType): PNode =
|
||||
var d = initDetectionPass(g, fn)
|
||||
var c = initLiftingPass(fn)
|
||||
# pretend 'fn' is a closure iterator for the analysis:
|
||||
let oldKind = fn.kind
|
||||
|
|
@ -808,11 +811,11 @@ proc liftIterToProc*(fn: PSym; body: PNode; ptrType: PType): PNode =
|
|||
fn.typ.callConv = ccClosure
|
||||
d.ownerToType[fn.id] = ptrType
|
||||
detectCapturedVars(body, fn, d)
|
||||
result = wrapIterBody(liftCapturedVars(body, fn, d, c), fn)
|
||||
result = wrapIterBody(g, liftCapturedVars(body, fn, d, c), fn)
|
||||
fn.kind = oldKind
|
||||
fn.typ.callConv = oldCC
|
||||
|
||||
proc liftLambdas*(features: set[Feature], fn: PSym, body: PNode; tooEarly: var bool): PNode =
|
||||
proc liftLambdas*(g: ModuleGraph; fn: PSym, body: PNode; tooEarly: var bool): PNode =
|
||||
# XXX gCmd == cmdCompileToJS does not suffice! The compiletime stuff needs
|
||||
# the transformation even when compiling to JS ...
|
||||
|
||||
|
|
@ -820,27 +823,26 @@ proc liftLambdas*(features: set[Feature], fn: PSym, body: PNode; tooEarly: var b
|
|||
let isCompileTime = sfCompileTime in fn.flags or fn.kind == skMacro
|
||||
|
||||
if body.kind == nkEmpty or (
|
||||
gCmd == cmdCompileToJS and not isCompileTime) or
|
||||
g.config.cmd == cmdCompileToJS and not isCompileTime) or
|
||||
fn.skipGenericOwner.kind != skModule:
|
||||
|
||||
# ignore forward declaration:
|
||||
result = body
|
||||
tooEarly = true
|
||||
else:
|
||||
var d = initDetectionPass(fn)
|
||||
var d = initDetectionPass(g, fn)
|
||||
detectCapturedVars(body, fn, d)
|
||||
if not d.somethingToDo and fn.isIterator:
|
||||
addClosureParam(d, fn, body.info)
|
||||
d.somethingToDo = true
|
||||
if d.somethingToDo:
|
||||
var c = initLiftingPass(fn)
|
||||
c.features = features
|
||||
result = liftCapturedVars(body, fn, d, c)
|
||||
if c.envvars.getOrDefault(fn.id) != nil:
|
||||
result = newTree(nkStmtList, rawClosureCreation(fn, d, c), result)
|
||||
|
||||
if oldIterTransf in features:
|
||||
result = wrapIterBody(result, fn)
|
||||
if oldIterTransf in g.config.features:
|
||||
result = wrapIterBody(g, result, fn)
|
||||
else:
|
||||
result = body
|
||||
#if fn.name.s == "get2":
|
||||
|
|
@ -848,15 +850,12 @@ proc liftLambdas*(features: set[Feature], fn: PSym, body: PNode; tooEarly: var b
|
|||
# echo renderTree(result, {renderIds})
|
||||
|
||||
proc liftLambdasForTopLevel*(module: PSym, body: PNode): PNode =
|
||||
if body.kind == nkEmpty or gCmd == cmdCompileToJS:
|
||||
result = body
|
||||
else:
|
||||
# XXX implement it properly
|
||||
result = body
|
||||
# XXX implement it properly
|
||||
result = body
|
||||
|
||||
# ------------------- iterator transformation --------------------------------
|
||||
|
||||
proc liftForLoop*(body: PNode; owner: PSym): PNode =
|
||||
proc liftForLoop*(g: ModuleGraph; body: PNode; owner: PSym): PNode =
|
||||
# problem ahead: the iterator could be invoked indirectly, but then
|
||||
# we don't know what environment to create here:
|
||||
#
|
||||
|
|
@ -885,10 +884,10 @@ proc liftForLoop*(body: PNode; owner: PSym): PNode =
|
|||
break
|
||||
...
|
||||
"""
|
||||
if liftingHarmful(owner): return body
|
||||
if liftingHarmful(g.config, owner): return body
|
||||
var L = body.len
|
||||
if not (body.kind == nkForStmt and body[L-2].kind in nkCallKinds):
|
||||
localError(body.info, "ignored invalid for loop")
|
||||
localError(g.config, body.info, "ignored invalid for loop")
|
||||
return body
|
||||
var call = body[L-2]
|
||||
|
||||
|
|
@ -901,7 +900,7 @@ proc liftForLoop*(body: PNode; owner: PSym): PNode =
|
|||
# createClosure()
|
||||
let iter = op.sym
|
||||
|
||||
let hp = getHiddenParam(iter)
|
||||
let hp = getHiddenParam(g, iter)
|
||||
env = newSym(skLet, iter.name, owner, body.info)
|
||||
env.typ = hp.typ
|
||||
env.flags = hp.flags
|
||||
|
|
@ -910,7 +909,7 @@ proc liftForLoop*(body: PNode; owner: PSym): PNode =
|
|||
addVar(v, newSymNode(env))
|
||||
result.add(v)
|
||||
# add 'new' statement:
|
||||
result.add(newCall(getSysSym"internalNew", env.newSymNode))
|
||||
result.add(newCall(getSysSym(g, env.info, "internalNew"), env.newSymNode))
|
||||
elif op.kind == nkStmtListExpr:
|
||||
let closure = op.lastSon
|
||||
if closure.kind == nkClosure:
|
||||
|
|
@ -920,7 +919,7 @@ proc liftForLoop*(body: PNode; owner: PSym): PNode =
|
|||
|
||||
var loopBody = newNodeI(nkStmtList, body.info, 3)
|
||||
var whileLoop = newNodeI(nkWhileStmt, body.info, 2)
|
||||
whileLoop.sons[0] = newIntTypeNode(nkIntLit, 1, getSysType(tyBool))
|
||||
whileLoop.sons[0] = newIntTypeNode(nkIntLit, 1, getSysType(g, body.info, tyBool))
|
||||
whileLoop.sons[1] = loopBody
|
||||
result.add whileLoop
|
||||
|
||||
|
|
@ -935,7 +934,7 @@ proc liftForLoop*(body: PNode; owner: PSym): PNode =
|
|||
|
||||
addSon(vpart, ast.emptyNode) # no explicit type
|
||||
if not env.isNil:
|
||||
call.sons[0] = makeClosure(call.sons[0].sym, env.newSymNode, body.info)
|
||||
call.sons[0] = makeClosure(g, call.sons[0].sym, env.newSymNode, body.info)
|
||||
addSon(vpart, call)
|
||||
addSon(v2, vpart)
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue