fixes #1418
This commit is contained in:
parent
bc2e83fe17
commit
15b2d6d351
2 changed files with 77 additions and 29 deletions
|
|
@ -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)
|
||||||
|
|
|
||||||
33
tests/controlflow/tbreak.nim
Normal file
33
tests/controlflow/tbreak.nim
Normal 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
|
||||||
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue