diff options
author | Araq <rumpf_a@web.de> | 2016-01-18 10:55:23 +0100 |
---|---|---|
committer | Araq <rumpf_a@web.de> | 2016-01-18 10:55:23 +0100 |
commit | 55c1f3d30ce5d2ab8745ab2b98a38a605c690a54 (patch) | |
tree | d729e8c0d7c929208c84450ad4a449e3eb32491e /compiler/transf.nim | |
parent | 68cbb4d2b4bc408e13fc27e6d054e3a0bb98bfb4 (diff) | |
parent | 2309975f782bf59b240e3874d5c31b4b299eca5d (diff) | |
download | Nim-55c1f3d30ce5d2ab8745ab2b98a38a605c690a54.tar.gz |
Merge branch 'devel' of https://github.com/nim-lang/Nim into devel
Diffstat (limited to 'compiler/transf.nim')
-rw-r--r-- | compiler/transf.nim | 151 |
1 files changed, 102 insertions, 49 deletions
diff --git a/compiler/transf.nim b/compiler/transf.nim index 3a5ff982e..3e074841e 100644 --- a/compiler/transf.nim +++ b/compiler/transf.nim @@ -45,7 +45,7 @@ type inlining: int # > 0 if we are in inlining context (copy vars) nestedProcs: int # > 0 if we are in a nested proc contSyms, breakSyms: seq[PSym] # to transform 'continue' and 'break' - deferDetected: bool + deferDetected, tooEarly: bool PTransf = ref TTransfContext proc newTransNode(a: PNode): PTransNode {.inline.} = @@ -93,10 +93,15 @@ proc getCurrOwner(c: PTransf): PSym = if c.transCon != nil: result = c.transCon.owner else: result = c.module -proc newTemp(c: PTransf, typ: PType, info: TLineInfo): PSym = - result = newSym(skTemp, getIdent(genPrefix), getCurrOwner(c), info) - result.typ = skipTypes(typ, {tyGenericInst}) - incl(result.flags, sfFromGeneric) +proc newTemp(c: PTransf, typ: PType, info: TLineInfo): PNode = + let r = newSym(skTemp, getIdent(genPrefix), getCurrOwner(c), info) + r.typ = skipTypes(typ, {tyGenericInst}) + incl(r.flags, sfFromGeneric) + let owner = getCurrOwner(c) + if owner.isIterator and not c.tooEarly: + result = freshVarForClosureIter(r, owner) + else: + result = newSymNode(r) proc transform(c: PTransf, n: PNode): PTransNode @@ -111,13 +116,22 @@ proc newAsgnStmt(c: PTransf, le: PNode, ri: PTransNode): PTransNode = result[1] = ri proc transformSymAux(c: PTransf, n: PNode): PNode = - #if n.sym.kind == skClosureIterator: - # return liftIterSym(n) + let s = n.sym + if s.typ != nil and s.typ.callConv == ccClosure: + if s.kind == skIterator: + if c.tooEarly: return n + else: return liftIterSym(n, getCurrOwner(c)) + elif s.kind in {skProc, skConverter, skMethod} and not c.tooEarly: + # top level .closure procs are still somewhat supported for 'Nake': + return makeClosure(s, nil, n.info) + #elif n.sym.kind in {skVar, skLet} and n.sym.typ.callConv == ccClosure: + # echo n.info, " come heer for ", c.tooEarly + # if not c.tooEarly: var b: PNode var tc = c.transCon - if sfBorrow in n.sym.flags and n.sym.kind in routineKinds: + if sfBorrow in s.flags and s.kind in routineKinds: # simply exchange the symbol: - b = n.sym.getBody + b = s.getBody if b.kind != nkSym: internalError(n.info, "wrong AST for borrowed symbol") b = newSymNode(b.sym) b.info = n.info @@ -132,6 +146,16 @@ proc transformSymAux(c: PTransf, n: PNode): PNode = proc transformSym(c: PTransf, n: PNode): PTransNode = result = PTransNode(transformSymAux(c, n)) +proc freshVar(c: PTransf; v: PSym): PNode = + let owner = getCurrOwner(c) + if owner.isIterator and not c.tooEarly: + result = freshVarForClosureIter(v, owner) + else: + var newVar = copySym(v) + incl(newVar.flags, sfFromGeneric) + newVar.owner = owner + result = newSymNode(newVar) + proc transformVarSection(c: PTransf, v: PNode): PTransNode = result = newTransNode(v) for i in countup(0, sonsLen(v)-1): @@ -141,35 +165,30 @@ proc transformVarSection(c: PTransf, v: PNode): PTransNode = elif it.kind == nkIdentDefs: if it.sons[0].kind == nkSym: internalAssert(it.len == 3) - var newVar = copySym(it.sons[0].sym) - incl(newVar.flags, sfFromGeneric) - # fixes a strange bug for rodgen: - #include(it.sons[0].sym.flags, sfFromGeneric); - newVar.owner = getCurrOwner(c) - idNodeTablePut(c.transCon.mapping, it.sons[0].sym, newSymNode(newVar)) + let x = freshVar(c, it.sons[0].sym) + idNodeTablePut(c.transCon.mapping, it.sons[0].sym, x) var defs = newTransNode(nkIdentDefs, it.info, 3) if importantComments(): # keep documentation information: PNode(defs).comment = it.comment - defs[0] = newSymNode(newVar).PTransNode + defs[0] = x.PTransNode defs[1] = it.sons[1].PTransNode defs[2] = transform(c, it.sons[2]) - newVar.ast = defs[2].PNode + if x.kind == nkSym: x.sym.ast = defs[2].PNode result[i] = defs else: - # has been transformed into 'param.x' for closure iterators, so keep it: - result[i] = PTransNode(it) + # has been transformed into 'param.x' for closure iterators, so just + # transform it: + result[i] = transform(c, it) else: if it.kind != nkVarTuple: internalError(it.info, "transformVarSection: not nkVarTuple") var L = sonsLen(it) var defs = newTransNode(it.kind, it.info, L) for j in countup(0, L-3): - var newVar = copySym(it.sons[j].sym) - incl(newVar.flags, sfFromGeneric) - newVar.owner = getCurrOwner(c) - idNodeTablePut(c.transCon.mapping, it.sons[j].sym, newSymNode(newVar)) - defs[j] = newSymNode(newVar).PTransNode + let x = freshVar(c, it.sons[j].sym) + idNodeTablePut(c.transCon.mapping, it.sons[j].sym, x) + defs[j] = x.PTransNode assert(it.sons[L-2].kind == nkEmpty) defs[L-2] = ast.emptyNode.PTransNode defs[L-1] = transform(c, it.sons[L-1]) @@ -294,10 +313,18 @@ proc introduceNewLocalVars(c: PTransf, n: PNode): PTransNode = result = PTransNode(n) of nkVarSection, nkLetSection: result = transformVarSection(c, n) + of nkClosure: + # it can happen that for-loop-inlining produced a fresh + # set of variables, including some computed environment + # (bug #2604). We need to patch this environment here too: + let a = n[1] + if a.kind == nkSym: + n.sons[1] = transformSymAux(c, a) + return PTransNode(n) else: result = newTransNode(n) for i in countup(0, sonsLen(n)-1): - result[i] = introduceNewLocalVars(c, n.sons[i]) + result[i] = introduceNewLocalVars(c, n.sons[i]) proc transformYield(c: PTransf, n: PNode): PTransNode = result = newTransNode(nkStmtList, n.info, 0) @@ -348,6 +375,20 @@ proc transformAddrDeref(c: PTransf, n: PNode, a, b: TNodeKind): PTransNode = # addr ( deref ( x )) --> x result = PTransNode(n.sons[0].sons[0]) +proc generateThunk(prc: PNode, dest: PType): PNode = + ## Converts 'prc' into '(thunk, nil)' so that it's compatible with + ## a closure. + + # we cannot generate a proper thunk here for GC-safety reasons + # (see internal documentation): + if gCmd == cmdCompileToJS: return prc + result = newNodeIT(nkClosure, prc.info, dest) + var conv = newNodeIT(nkHiddenStdConv, prc.info, dest) + conv.add(emptyNode) + conv.add(prc) + result.add(conv) + result.add(newNodeIT(nkNilLit, prc.info, getSysType(tyNil))) + proc transformConv(c: PTransf, n: PNode): PTransNode = # numeric types need range checks: var dest = skipTypes(n.typ, abstractVarRange) @@ -428,6 +469,10 @@ proc transformConv(c: PTransf, n: PNode): PTransNode = of tyGenericParam, tyOrdinal: result = transform(c, n.sons[1]) # happens sometimes for generated assignments, etc. + of tyProc: + result = transformSons(c, n) + if dest.callConv == ccClosure and source.callConv == ccDefault: + result = generateThunk(result[1].PNode, dest).PTransNode else: result = transformSons(c, n) @@ -479,9 +524,13 @@ proc transformFor(c: PTransf, n: PNode): PTransNode = return result c.breakSyms.add(labl) if call.kind notin nkCallKinds or call.sons[0].kind != nkSym or - call.sons[0].sym.kind != skIterator: + call.sons[0].typ.callConv == ccClosure: n.sons[length-1] = transformLoopBody(c, n.sons[length-1]).PNode - result[1] = lambdalifting.liftForLoop(n).PTransNode + if not c.tooEarly: + n.sons[length-2] = transform(c, n.sons[length-2]).PNode + result[1] = lambdalifting.liftForLoop(n, getCurrOwner(c)).PTransNode + else: + result[1] = newNode(nkEmpty).PTransNode discard c.breakSyms.pop return result @@ -517,9 +566,9 @@ proc transformFor(c: PTransf, n: PNode): PTransNode = of paFastAsgn: # generate a temporary and produce an assignment statement: var temp = newTemp(c, formal.typ, formal.info) - addVar(v, newSymNode(temp)) - add(stmtList, newAsgnStmt(c, newSymNode(temp), arg.PTransNode)) - idNodeTablePut(newC.mapping, formal, newSymNode(temp)) + addVar(v, temp) + add(stmtList, newAsgnStmt(c, temp, arg.PTransNode)) + idNodeTablePut(newC.mapping, formal, temp) of paVarAsgn: assert(skipTypes(formal.typ, abstractInst).kind == tyVar) idNodeTablePut(newC.mapping, formal, arg) @@ -700,18 +749,13 @@ proc transform(c: PTransf, n: PNode): PTransNode = result = PTransNode(n) of nkBracketExpr: result = transformArrayAccess(c, n) of procDefs: - when false: - if n.sons[genericParamsPos].kind == nkEmpty: - var s = n.sons[namePos].sym - n.sons[bodyPos] = PNode(transform(c, s.getBody)) - if s.ast.sons[bodyPos] != n.sons[bodyPos]: - # somehow this can happen ... :-/ - s.ast.sons[bodyPos] = n.sons[bodyPos] - #n.sons[bodyPos] = liftLambdas(s, n) - #if n.kind == nkMethodDef: methodDef(s, false) - #if n.kind == nkIteratorDef and n.typ != nil: - # return liftIterSym(n.sons[namePos]).PTransNode - result = PTransNode(n) + var s = n.sons[namePos].sym + if n.typ != nil and s.typ.callConv == ccClosure: + result = transformSym(c, n.sons[namePos]) + # use the same node as before if still a symbol: + if result.PNode.kind == nkSym: result = PTransNode(n) + else: + result = PTransNode(n) of nkMacroDef: # XXX no proper closure support yet: when false: @@ -748,7 +792,7 @@ proc transform(c: PTransf, n: PNode): PTransNode = result = newTransNode(nkCommentStmt, n.info, 0) tryStmt.addSon(deferPart) # disable the original 'defer' statement: - n.kind = nkCommentStmt + n.kind = nkEmpty of nkContinueStmt: result = PTransNode(newNodeI(nkBreakStmt, n.info)) var labl = c.contSyms[c.contSyms.high] @@ -794,7 +838,14 @@ proc transform(c: PTransf, n: PNode): PTransNode = # XXX comment handling really sucks: if importantComments(): PNode(result).comment = n.comment - of nkClosure: return PTransNode(n) + of nkClosure: + # it can happen that for-loop-inlining produced a fresh + # set of variables, including some computed environment + # (bug #2604). We need to patch this environment here too: + let a = n[1] + if a.kind == nkSym: + n.sons[1] = transformSymAux(c, a) + return PTransNode(n) else: result = transformSons(c, n) when false: @@ -866,11 +917,11 @@ proc transformBody*(module: PSym, n: PNode, prc: PSym): PNode = result = n else: var c = openTransf(module, "") - result = processTransf(c, n, prc) + result = liftLambdas(prc, n, c.tooEarly) + #result = n + result = processTransf(c, result, prc) liftDefer(c, result) - result = liftLambdas(prc, result) - #if prc.kind == skClosureIterator: - # result = lambdalifting.liftIterator(prc, result) + #result = liftLambdas(prc, result) incl(result.flags, nfTransf) when useEffectSystem: trackProc(prc, result) #if prc.name.s == "testbody": @@ -883,9 +934,11 @@ proc transformStmt*(module: PSym, n: PNode): PNode = var c = openTransf(module, "") result = processTransf(c, n, module) liftDefer(c, result) - result = liftLambdasForTopLevel(module, result) + #result = liftLambdasForTopLevel(module, result) incl(result.flags, nfTransf) when useEffectSystem: trackTopLevelStmt(module, result) + #if n.info ?? "temp.nim": + # echo renderTree(result, {renderIds}) proc transformExpr*(module: PSym, n: PNode): PNode = if nfTransf in n.flags: |