This commit is contained in:
Araq 2014-08-20 02:14:30 +02:00
commit 15b2d6d351
2 changed files with 77 additions and 29 deletions

View file

@ -1,7 +1,7 @@
# #
# #
# The Nimrod Compiler # The Nimrod Compiler
# (c) Copyright 2013 Andreas Rumpf # (c) Copyright 2014 Andreas Rumpf
# #
# See the file "copying.txt", included in this # See the file "copying.txt", included in this
# distribution, for details about the copyright. # distribution, for details about the copyright.
@ -13,7 +13,7 @@
# * inlines iterators # * inlines iterators
# * inlines constants # * inlines constants
# * performes constant folding # * performes constant folding
# * converts "continue" to "break" # * converts "continue" to "break"; disambiguates "break"
# * introduces method dispatchers # * introduces method dispatchers
# * performs lambda lifting for closure support # * performs lambda lifting for closure support
@ -44,7 +44,6 @@ type
inlining: int # > 0 if we are in inlining context (copy vars) inlining: int # > 0 if we are in inlining context (copy vars)
nestedProcs: int # > 0 if we are in a nested proc nestedProcs: int # > 0 if we are in a nested proc
contSyms, breakSyms: seq[PSym] # to transform 'continue' and 'break' contSyms, breakSyms: seq[PSym] # to transform 'continue' and 'break'
inLoop: int # > 0 if we are in a loop
PTransf = ref TTransfContext PTransf = ref TTransfContext
proc newTransNode(a: PNode): PTransNode {.inline.} = proc newTransNode(a: PNode): PTransNode {.inline.} =
@ -213,14 +212,6 @@ proc transformBlock(c: PTransf, n: PNode): PTransNode =
discard c.breakSyms.pop discard c.breakSyms.pop
result[0] = newSymNode(labl).PTransNode 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 = proc transformLoopBody(c: PTransf, n: PNode): PTransNode =
# What if it contains "continue" and "break"? "break" needs # What if it contains "continue" and "break"? "break" needs
# an explicit label too, but not the same! # an explicit label too, but not the same!
@ -239,6 +230,27 @@ proc transformLoopBody(c: PTransf, n: PNode): PTransNode =
else: else:
result = transform(c, n) result = transform(c, n)
proc transformWhile(c: PTransf; n: PNode): PTransNode =
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:
result = n.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) = proc unpackTuple(c: PTransf, n: PNode, father: PTransNode) =
# XXX: BUG: what if `n` is an expression with side-effects? # XXX: BUG: what if `n` is an expression with side-effects?
for i in countup(0, sonsLen(c.transCon.forStmt) - 3): for i in countup(0, sonsLen(c.transCon.forStmt) - 3):
@ -424,20 +436,32 @@ proc transformFor(c: PTransf, n: PNode): PTransNode =
var length = sonsLen(n) var length = sonsLen(n)
var call = n.sons[length - 2] 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 if call.typ.kind != tyIter and
(call.kind notin nkCallKinds or call.sons[0].kind != nkSym or (call.kind notin nkCallKinds or call.sons[0].kind != nkSym or
call.sons[0].sym.kind != skIterator): call.sons[0].sym.kind != skIterator):
n.sons[length-1] = transformLoopBody(c, n.sons[length-1]).PNode n.sons[length-1] = transformLoopBody(c, n.sons[length-1]).PNode
return lambdalifting.liftForLoop(n).PTransNode result[1] = lambdalifting.liftForLoop(n).PTransNode
#InternalError(call.info, "transformFor") discard c.breakSyms.pop
return result
#echo "transforming: ", renderTree(n) #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]) var loopBody = transformLoopBody(c, n.sons[length-1])
result[1] = stmtList
discard c.breakSyms.pop
var v = newNodeI(nkVarSection, n.info) var v = newNodeI(nkVarSection, n.info)
for i in countup(0, length - 3): for i in countup(0, length - 3):
addVar(v, copyTree(n.sons[i])) # declare new vars 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 # Bugfix: inlined locals belong to the invoking routine, not to the invoked
# iterator! # iterator!
@ -459,7 +483,7 @@ proc transformFor(c: PTransf, n: PNode): PTransNode =
# generate a temporary and produce an assignment statement: # generate a temporary and produce an assignment statement:
var temp = newTemp(c, formal.typ, formal.info) var temp = newTemp(c, formal.typ, formal.info)
addVar(v, newSymNode(temp)) 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)) idNodeTablePut(newC.mapping, formal, newSymNode(temp))
of paVarAsgn: of paVarAsgn:
assert(skipTypes(formal.typ, abstractInst).kind == tyVar) assert(skipTypes(formal.typ, abstractInst).kind == tyVar)
@ -468,12 +492,12 @@ proc transformFor(c: PTransf, n: PNode): PTransNode =
var body = iter.getBody var body = iter.getBody
pushInfoContext(n.info) pushInfoContext(n.info)
inc(c.inlining) inc(c.inlining)
add(result, transform(c, body)) add(stmtList, transform(c, body))
#findWrongOwners(c, result.pnode) #findWrongOwners(c, stmtList.pnode)
dec(c.inlining) dec(c.inlining)
popInfoContext() popInfoContext()
popTransCon(c) popTransCon(c)
# echo "transformed: ", result.PNode.renderTree # echo "transformed: ", stmtList.PNode.renderTree
proc getMagicOp(call: PNode): TMagic = proc getMagicOp(call: PNode): TMagic =
if call.sons[0].kind == nkSym and if call.sons[0].kind == nkSym and
@ -643,25 +667,16 @@ proc transform(c: PTransf, n: PNode): PTransNode =
if n.kind == nkMethodDef: methodDef(s, false) if n.kind == nkMethodDef: methodDef(s, false)
result = PTransNode(n) result = PTransNode(n)
of nkForStmt: of nkForStmt:
inc c.inLoop
result = transformFor(c, n) result = transformFor(c, n)
dec c.inLoop
of nkParForStmt: of nkParForStmt:
inc c.inLoop
result = transformSons(c, n) result = transformSons(c, n)
dec c.inLoop
of nkCaseStmt: result = transformCase(c, n) of nkCaseStmt: result = transformCase(c, n)
of nkContinueStmt: of nkContinueStmt:
result = PTransNode(newNodeI(nkBreakStmt, n.info)) result = PTransNode(newNodeI(nkBreakStmt, n.info))
var labl = c.contSyms[c.contSyms.high] var labl = c.contSyms[c.contSyms.high]
add(result, PTransNode(newSymNode(labl))) add(result, PTransNode(newSymNode(labl)))
of nkBreakStmt: result = transformBreak(c, n) of nkBreakStmt: result = transformBreak(c, n)
of nkWhileStmt: of nkWhileStmt: result = transformWhile(c, n)
inc c.inLoop
result = newTransNode(n)
result[0] = transform(c, n.sons[0])
result[1] = transformLoopBody(c, n.sons[1])
dec c.inLoop
of nkCall, nkHiddenCallConv, nkCommand, nkInfix, nkPrefix, nkPostfix, of nkCall, nkHiddenCallConv, nkCommand, nkInfix, nkPrefix, nkPostfix,
nkCallStrLit: nkCallStrLit:
result = transformCall(c, n) result = transformCall(c, n)

View file

@ -0,0 +1,33 @@
discard """
output: '''10'''
"""
var
x = false
run = true
while run:
run = false
block myblock:
if true:
break
echo "leaving myblock"
x = true
doAssert(x)
# bug #1418
iterator foo: int =
for x in 0 .. 9:
for y in [10,20,30,40,50,60,70,80,90]:
yield x + y
for p in foo():
echo p
break
iterator permutations: int =
yield 10
for p in permutations():
break