diff options
Diffstat (limited to 'compiler/transf.nim')
-rw-r--r-- | compiler/transf.nim | 108 |
1 files changed, 76 insertions, 32 deletions
diff --git a/compiler/transf.nim b/compiler/transf.nim index dece1ac18..b9b06675e 100644 --- a/compiler/transf.nim +++ b/compiler/transf.nim @@ -1,7 +1,7 @@ # # # The Nimrod Compiler -# (c) Copyright 2013 Andreas Rumpf +# (c) Copyright 2014 Andreas Rumpf # # See the file "copying.txt", included in this # distribution, for details about the copyright. @@ -13,7 +13,7 @@ # * inlines iterators # * inlines constants # * performes constant folding -# * converts "continue" to "break" +# * converts "continue" to "break"; disambiguates "break" # * introduces method dispatchers # * performs lambda lifting for closure support @@ -44,7 +44,6 @@ 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' - inLoop: int # > 0 if we are in a loop PTransf = ref TTransfContext proc newTransNode(a: PNode): PTransNode {.inline.} = @@ -201,6 +200,18 @@ proc newLabel(c: PTransf, n: PNode): PSym = result = newSym(skLabel, nil, getCurrOwner(c), n.info) result.name = getIdent(genPrefix & $result.id) +proc freshLabels(c: PTransf, n: PNode; symMap: var TIdTable) = + if n.kind in {nkBlockStmt, nkBlockExpr}: + if n.sons[0].kind == nkSym: + let x = newLabel(c, n[0]) + idTablePut(symMap, n[0].sym, x) + n.sons[0].sym = x + if n.kind == nkSym and n.sym.kind == skLabel: + let x = PSym(idTableGet(symMap, n.sym)) + if x != nil: n.sym = x + else: + for i in 0 .. <safeLen(n): freshLabels(c, n.sons[i], symMap) + proc transformBlock(c: PTransf, n: PNode): PTransNode = var labl: PSym if n.sons[0].kind != nkEmpty: @@ -213,14 +224,6 @@ proc transformBlock(c: PTransf, n: PNode): PTransNode = discard c.breakSyms.pop result[0] = newSymNode(labl).PTransNode -proc transformBreak(c: PTransf, n: PNode): PTransNode = - if c.inLoop > 0 or n.sons[0].kind != nkEmpty: - result = n.PTransNode - else: - let labl = c.breakSyms[c.breakSyms.high] - result = transformSons(c, n) - result[0] = newSymNode(labl).PTransNode - proc transformLoopBody(c: PTransf, n: PNode): PTransNode = # What if it contains "continue" and "break"? "break" needs # an explicit label too, but not the same! @@ -239,6 +242,37 @@ proc transformLoopBody(c: PTransf, n: PNode): PTransNode = else: result = transform(c, n) +proc transformWhile(c: PTransf; n: PNode): PTransNode = + if c.inlining > 0: + result = transformSons(c, n) + else: + let labl = newLabel(c, n) + c.breakSyms.add(labl) + result = newTransNode(nkBlockStmt, n.info, 2) + result[0] = newSymNode(labl).PTransNode + + var body = newTransNode(n) + for i in 0..n.len-2: + body[i] = transform(c, n.sons[i]) + body[<n.len] = transformLoopBody(c, n.sons[<n.len]) + result[1] = body + discard c.breakSyms.pop + +proc transformBreak(c: PTransf, n: PNode): PTransNode = + if n.sons[0].kind != nkEmpty or c.inlining > 0: + result = n.PTransNode + when false: + let lablCopy = idNodeTableGet(c.transCon.mapping, n.sons[0].sym) + if lablCopy.isNil: + result = n.PTransNode + else: + result = newTransNode(n.kind, n.info, 1) + result[0] = lablCopy.PTransNode + else: + let labl = c.breakSyms[c.breakSyms.high] + result = transformSons(c, n) + result[0] = newSymNode(labl).PTransNode + proc unpackTuple(c: PTransf, n: PNode, father: PTransNode) = # XXX: BUG: what if `n` is an expression with side-effects? for i in countup(0, sonsLen(c.transCon.forStmt) - 3): @@ -424,20 +458,32 @@ proc transformFor(c: PTransf, n: PNode): PTransNode = var length = sonsLen(n) var call = n.sons[length - 2] + + let labl = newLabel(c, n) + c.breakSyms.add(labl) + result = newTransNode(nkBlockStmt, n.info, 2) + result[0] = newSymNode(labl).PTransNode + if call.typ.kind != tyIter and (call.kind notin nkCallKinds or call.sons[0].kind != nkSym or call.sons[0].sym.kind != skIterator): n.sons[length-1] = transformLoopBody(c, n.sons[length-1]).PNode - return lambdalifting.liftForLoop(n).PTransNode - #InternalError(call.info, "transformFor") + result[1] = lambdalifting.liftForLoop(n).PTransNode + discard c.breakSyms.pop + return result #echo "transforming: ", renderTree(n) - result = newTransNode(nkStmtList, n.info, 0) + var stmtList = newTransNode(nkStmtList, n.info, 0) + var loopBody = transformLoopBody(c, n.sons[length-1]) + + result[1] = stmtList + discard c.breakSyms.pop + var v = newNodeI(nkVarSection, n.info) for i in countup(0, length - 3): addVar(v, copyTree(n.sons[i])) # declare new vars - add(result, v.PTransNode) + add(stmtList, v.PTransNode) # Bugfix: inlined locals belong to the invoking routine, not to the invoked # iterator! @@ -453,27 +499,32 @@ proc transformFor(c: PTransf, n: PNode): PTransNode = var formal = skipTypes(iter.typ, abstractInst).n.sons[i].sym if arg.typ.kind == tyIter: continue case putArgInto(arg, formal.typ) - of paDirectMapping: + of paDirectMapping: idNodeTablePut(newC.mapping, formal, arg) - of paFastAsgn: + of paFastAsgn: # generate a temporary and produce an assignment statement: var temp = newTemp(c, formal.typ, formal.info) addVar(v, newSymNode(temp)) - add(result, newAsgnStmt(c, newSymNode(temp), arg.PTransNode)) + add(stmtList, newAsgnStmt(c, newSymNode(temp), arg.PTransNode)) idNodeTablePut(newC.mapping, formal, newSymNode(temp)) of paVarAsgn: assert(skipTypes(formal.typ, abstractInst).kind == tyVar) idNodeTablePut(newC.mapping, formal, arg) # XXX BUG still not correct if the arg has a side effect! - var body = iter.getBody + var body = iter.getBody.copyTree pushInfoContext(n.info) + # XXX optimize this somehow. But the check "c.inlining" is not correct: + var symMap: TIdTable + initIdTable symMap + freshLabels(c, body, symMap) + inc(c.inlining) - add(result, transform(c, body)) - #findWrongOwners(c, result.pnode) + add(stmtList, transform(c, body)) + #findWrongOwners(c, stmtList.pnode) dec(c.inlining) popInfoContext() popTransCon(c) - # echo "transformed: ", result.PNode.renderTree + # echo "transformed: ", stmtList.PNode.renderTree proc getMagicOp(call: PNode): TMagic = if call.sons[0].kind == nkSym and @@ -643,25 +694,16 @@ proc transform(c: PTransf, n: PNode): PTransNode = if n.kind == nkMethodDef: methodDef(s, false) result = PTransNode(n) of nkForStmt: - inc c.inLoop result = transformFor(c, n) - dec c.inLoop of nkParForStmt: - inc c.inLoop result = transformSons(c, n) - dec c.inLoop of nkCaseStmt: result = transformCase(c, n) of nkContinueStmt: result = PTransNode(newNodeI(nkBreakStmt, n.info)) var labl = c.contSyms[c.contSyms.high] add(result, PTransNode(newSymNode(labl))) of nkBreakStmt: result = transformBreak(c, n) - of nkWhileStmt: - inc c.inLoop - result = newTransNode(n) - result[0] = transform(c, n.sons[0]) - result[1] = transformLoopBody(c, n.sons[1]) - dec c.inLoop + of nkWhileStmt: result = transformWhile(c, n) of nkCall, nkHiddenCallConv, nkCommand, nkInfix, nkPrefix, nkPostfix, nkCallStrLit: result = transformCall(c, n) @@ -740,6 +782,8 @@ proc transformBody*(module: PSym, n: PNode, prc: PSym): PNode = # result = lambdalifting.liftIterator(prc, result) incl(result.flags, nfTransf) when useEffectSystem: trackProc(prc, result) + if prc.name.s == "testbody": + echo renderTree(result) proc transformStmt*(module: PSym, n: PNode): PNode = if nfTransf in n.flags: |